]> git.neil.brown.name Git - history.git/commitdiff
v2.4.6.3 -> v2.4.6.4
authorLinus Torvalds <torvalds@athlon.transmeta.com>
Tue, 5 Feb 2002 03:10:48 +0000 (19:10 -0800)
committerLinus Torvalds <torvalds@athlon.transmeta.com>
Tue, 5 Feb 2002 03:10:48 +0000 (19:10 -0800)
  - David Miller: sparc and networking updates
  - Al Viro: SysV FS add_link off-by-two bogosity.
  - Jeff Garzik: merge D-Link DL2k GigE driver, other network driver cleanups
  - Kai Germaschewski: ISDN update
  - Alan Cox: more merging (MPT fusion core)
  - Johannes Erdfelt: USB updates
  - Stas Sergeev: make sure we return out of vm86 mode when interrupts
  get re.enabled
  - Rusty Russell: netfilter fixes for ipt_unclean and ip_queue
  - me: initialize page->age when adding it to the swap cache
  - Paul Mackerras: PPC updates
  - some subtle fs/buffer.c race conditions (Andrew Morton, me)

76 files changed:
Documentation/Configure.help
Documentation/DocBook/Makefile
Documentation/DocBook/via-audio.tmpl
Documentation/networking/8139too.txt
Documentation/networking/dl2k.txt [new file with mode: 0644]
MAINTAINERS
arch/i386/defconfig
arch/i386/kernel/vm86.c
arch/ppc/kernel/prom.c
drivers/block/ll_rw_blk.c
drivers/block/ps2esdi.c
drivers/char/serial.c
drivers/isdn/eicon/eicon.h
drivers/isdn/hisax/config.c
drivers/isdn/hisax/md [deleted file]
drivers/isdn/isdn_tty.c
drivers/message/fusion/Config.in [new file with mode: 0644]
drivers/message/fusion/Makefile [new file with mode: 0644]
drivers/message/fusion/ascq_tbl.c [new file with mode: 0644]
drivers/message/fusion/ascq_tbl.sh [new file with mode: 0644]
drivers/message/fusion/isense.c [new file with mode: 0644]
drivers/message/fusion/isense.h [new file with mode: 0644]
drivers/message/fusion/linux_compat.h [new file with mode: 0644]
drivers/message/fusion/lsi/fc_log.h [new file with mode: 0644]
drivers/message/fusion/lsi/mpi.h [new file with mode: 0644]
drivers/message/fusion/lsi/mpi_cnfg.h [new file with mode: 0644]
drivers/message/fusion/lsi/mpi_fc.h [new file with mode: 0644]
drivers/message/fusion/lsi/mpi_history.txt [new file with mode: 0644]
drivers/message/fusion/lsi/mpi_init.h [new file with mode: 0644]
drivers/message/fusion/lsi/mpi_ioc.h [new file with mode: 0644]
drivers/message/fusion/lsi/mpi_lan.h [new file with mode: 0644]
drivers/message/fusion/lsi/mpi_targ.h [new file with mode: 0644]
drivers/message/fusion/lsi/mpi_type.h [new file with mode: 0644]
drivers/message/fusion/mptbase.c [new file with mode: 0644]
drivers/message/fusion/mptbase.h [new file with mode: 0644]
drivers/message/fusion/mptctl.c [new file with mode: 0644]
drivers/message/fusion/mptlan.c [new file with mode: 0644]
drivers/message/fusion/mptlan.h [new file with mode: 0644]
drivers/message/fusion/mptscsih.c [new file with mode: 0644]
drivers/message/fusion/mptscsih.h [new file with mode: 0644]
drivers/message/fusion/scsi3.h [new file with mode: 0644]
drivers/message/fusion/scsiops.c [new file with mode: 0644]
drivers/net/3c509.c
drivers/net/8139too.c
drivers/net/Config.in
drivers/net/Makefile
drivers/net/dl2k.c [new file with mode: 0644]
drivers/net/dl2k.h [new file with mode: 0644]
drivers/net/epic100.c
drivers/sbus/char/aurora.c
drivers/usb/printer.c
drivers/usb/scanner.c
drivers/usb/serial/empeg.c
drivers/usb/serial/ftdi_sio.c
drivers/usb/serial/usbserial.c
drivers/usb/usb-ohci.c
drivers/video/hgafb.c
drivers/video/imsttfb.c
fs/buffer.c
fs/proc/proc_misc.c
fs/sysv/dir.c
include/asm-sparc/vaddrs.h
include/asm-sparc64/starfire.h
include/linux/if_arp.h
include/linux/isdnif.h
include/linux/locks.h
kernel/ksyms.c
mm/filemap.c
mm/memory.c
mm/oom_kill.c
mm/shmem.c
mm/swap_state.c
net/decnet/dn_dev.c
net/ipv4/netfilter/ip_queue.c
net/ipv4/netfilter/ipt_unclean.c
net/ipv4/netfilter/iptable_mangle.c

index 799e354d230b30df79fccdfbefa57e25e570d40e..932e50efc2f2ec3a14b6fde26196721d6c935714 100644 (file)
@@ -8842,6 +8842,18 @@ CONFIG_MYRI_SBUS
   say M here and read Documentation/modules.txt. This is recommended.
   The module will be called myri_sbus.o.
 
+D-Link 2000-based Gigabit Ethernet support
+CONFIG_DL2K
+  This driver supports D-Link 2000-based gigabit ethernet cards, which
+  includes
+       D-Link DGE-550T Gigabit Ethernet Adapter.
+       D-Link DL2000-based Gigabit Ethernet Adapter.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read Documentation/modules.txt. This is recommended.
+  The module will be called dl2k.o.
+
 AMD LANCE and PCnet (AT1500 and NE2100) support
 CONFIG_LANCE
   If you have a network (Ethernet) card of this type, say Y and read
index d2b63417e0b97e25547d87167ea6d9136e9c9e38..9729d2b08552c77134eb4cc68e96bc0898499750 100644 (file)
@@ -1,7 +1,7 @@
 BOOKS  := wanbook.sgml z8530book.sgml mcabook.sgml videobook.sgml \
           kernel-api.sgml parportbook.sgml kernel-hacking.sgml \
           kernel-locking.sgml via-audio.sgml mousedrivers.sgml sis900.sgml \
-          deviceiobook.sgml procfs-guide.sgml
+          deviceiobook.sgml procfs-guide.sgml tulip-user.sgml
 
 PS     :=      $(patsubst %.sgml, %.ps, $(BOOKS))
 PDF    :=      $(patsubst %.sgml, %.pdf, $(BOOKS))
@@ -62,6 +62,9 @@ via-audio.sgml: via-audio.tmpl $(TOPDIR)/drivers/sound/via82cxxx_audio.c
        $(TOPDIR)/scripts/docgen $(TOPDIR)/drivers/sound/via82cxxx_audio.c \
                <via-audio.tmpl >via-audio.sgml
 
+tulip-user.sgml: tulip-user.tmpl
+       $(TOPDIR)/scripts/docgen <$< >$@
+
 sis900.sgml: sis900.tmpl $(TOPDIR)/drivers/net/sis900.c
        $(TOPDIR)/scripts/docgen $(TOPDIR)/drivers/net/sis900.c \
                <sis900.tmpl >sis900.sgml
index 039eff979d32fc59aa75a89a13ab1879a336cfef..768031ccba95f93cae29f2a179f763785e2bef3a 100644 (file)
@@ -17,7 +17,7 @@
   </authorgroup>
 
   <copyright>
-   <year>2000</year>
+   <year>1999-2001</year>
    <holder>Jeff Garzik</holder>
   </copyright>
 
      <title>Known Bugs And Assumptions</title>
   <para>
   <variablelist>
-    <varlistentry><term>MMAP support</term>
-    <listitem>
-    <para>
-       MMAP support is currently missing.  Make sure to
-       test with Quake.
-    </para>
-    </listitem></varlistentry>
-
-    <varlistentry><term>AC97 codec timeout during init</term>
-    <listitem>
-    <para>
-       A warning message "via82cxxx: timeout while reading AC97
-       codec" is printed during driver initialization.  This
-       message can safely be ignored.
-    </para>
-    </listitem></varlistentry>
-
     <varlistentry><term>Low volume</term>
     <listitem>
     <para>
   <para>
        AC97 mixer interface fixes and debugging by Ron Cemer <email>roncemer@gte.net</email>.
   </para>
+  <para>
+       Rui Sousa <email>rui.sousa@conexant.com</email>, for bugfixing
+       MMAP support, and several other notable fixes that resulted from
+       his hard work and testing.
+  </para>
+  <para>
+       Adrian Cox <email>adrian@humboldt.co.uk</email>, for bugfixing
+       MMAP support, and several other notable fixes that resulted from
+       his hard work and testing.
+  </para>
   </chapter>
   
   <chapter id="notes">
        and device ids are not examined.
   </para>
   <para>
-       GNU indent formatting options:  -kr -i8 -pcs
+       GNU indent formatting options:
+  <programlisting>
+-kr -i8 -ts8 -br -ce -bap -sob -l80 -pcs -cs -ss -bs -di1 -nbc -lp -psl
+  </programlisting>
   </para>
   <para>
        Via has graciously donated e-mail support and source code to help further
   <chapter id="changelog">
       <title>Driver ChangeLog</title>
 
+<sect1 id="version1115"><title>
+Version 1.1.15
+</title>
+  <itemizedlist spacing=compact>
+   <listitem>
+    <para>
+    Support for variable fragment size and variable fragment number (Rui
+    Sousa)
+    </para>
+   </listitem>
+
+   <listitem>
+    <para>
+    Fixes for the SPEED, STEREO, CHANNELS, FMT ioctls when in read &
+    write mode (Rui Sousa)
+    </para>
+   </listitem>
+
+   <listitem>
+    <para>
+    Mmaped sound is now fully functional. (Rui Sousa)
+    </para>
+   </listitem>
+
+   <listitem>
+    <para>
+    Make sure to enable PCI device before reading any of its PCI
+    config information. (fixes potential hotplug problems)
+    </para>
+   </listitem>
+
+   <listitem>
+    <para>
+    Clean up code a bit and add more internal function documentation.
+    </para>
+   </listitem>
+
+   <listitem>
+    <para>
+    AC97 codec access fixes (Adrian Cox)
+    </para>
+   </listitem>
+
+   <listitem>
+    <para>
+    Big endian fixes (Adrian Cox)
+    </para>
+   </listitem>
+
+   <listitem>
+    <para>
+    MIDI support (Adrian Cox)
+    </para>
+   </listitem>
+
+   <listitem>
+    <para>
+    Detect and report locked-rate AC97 codecs.  If your hardware only
+    supports 48Khz (locked rate), then your recording/playback software
+    must upsample or downsample accordingly.  The hardware cannot do it.
+    </para>
+   </listitem>
+
+   <listitem>
+    <para>
+    Use new pci_request_regions and pci_disable_device functions in
+    kernel 2.4.6.
+    </para>
+   </listitem>
+
+  </itemizedlist>
+</sect1>
+
 <sect1 id="version1114"><title>
 Version 1.1.14
 </title>
index b9a3da3f93cf10542bd503699e7abc97166087b7..34f239c1a3108e2d2a9580f6b4921503e0b77071 100644 (file)
@@ -185,6 +185,20 @@ suggestions welcome)  (WIP)
 Change History
 --------------
 
+Version 0.9.18 - July 6, 2001
+
+* Fix race leading to crashes on some machines.
+* Minimize race leading to low performance.
+* Correct interrupt acknowledgement to cover all three
+  relevant Rx events.
+* Add ethtool driver info support.
+* Collect additional driver-internal statistics.
+* Add descriptions for module parameters.
+* Support new SIOCxMIIxxx ioctls added in kernel 2.4.6.
+* Multicast filter big endian fix.
+* Support new PCI PM API added in kernel 2.4.6.
+
+
 Version 0.9.17 - May 7, 2001
 
 * Fix chipset wakeup bug which prevent media connection for 8139B
diff --git a/Documentation/networking/dl2k.txt b/Documentation/networking/dl2k.txt
new file mode 100644 (file)
index 0000000..6cf2316
--- /dev/null
@@ -0,0 +1,236 @@
+
+    D-Link DL2000-based Gigabit Ethernet Adapter Installation 
+    for Linux
+    July 5, 2001
+
+Contents
+========
+ - Compatibility List
+ - Quick Install
+ - Compiling the Driver
+ - Installing the Driver
+ - Option parameter
+ - Configuration Script Sample
+ - Troubleshooting
+
+
+Compatiblity List
+=================
+Adapter Support:
+
+D-Link DGE-550T Gigabit Ethernet Adapter.
+D-Link DL2000-based Gigabit Ethernet Adapter.
+
+
+The driver support Linux kernal 2.4.x later. We had tested it 
+on the environments below.
+
+ . Red Hat v6.2 (update to kernel 2.4.4)
+ . Red Hat v7.0 (update to kernel 2.4.4)
+ . Red Hat v7.1 (kernel 2.4.2-2)
+
+
+Quick Install
+=============
+Install linux driver as following command:
+
+1. make all
+2. insmod dl2x.o 
+3. ifconfig eth0 up 10.xxx.xxx.xxx netmask 255.0.0.0
+                    ^^^^^^^^^^^^^^^\        ^^^^^^^^\
+                                   IP               NETMASK 
+Now eth0 bring up, you can test it by "ping" or get more information by 
+"ifconfig". If test ok, then continue next step.
+
+4. cp dl2x.o /lib/modules/`uname -r`/kernel/drivers/net
+5. Add the following lines to /etc/modules.conf:
+       alias eth0 dl2x
+6. Run "netconfig" or "netconf" to create configuration script ifcfg-eth0 
+   located at /etc/sysconfig/network-scripts or create it manually.
+   [see - Configuration Script Sample]
+7. Driver will automatically load and configure at next boot time.
+
+Compiling the Driver
+====================
+  In Linux, NIC drivers are most commonly configured as loadable modules.
+The approach of building a monolithic kernel has become obsolete. The driver
+can be compiled as part of a monolithic kernel, but is strongly discouraged.
+The remainder of this section assumes the driver is built as a loadable module.
+In the Linux environment, it is a good idea to rebuild the driver from the
+source instead of relying on a precompiled version. This approach provides
+better reliability since a precompiled driver might depend on libraries or
+kernel features that are not present in a given Linux installation.
+
+The 3 files necessary to build Linux device driver are dl2x.c, dl2x.h and
+Makefile. To compile, the Linux installation must include the gcc compiler,
+the kernel source, and the kernel headers. The Linux driver supports Linux
+Kernels 2.4.x. Copy the files to a directory and enter the following command 
+to compile and link the driver:
+
+CD-ROM drive
+------------
+
+[root@XXX /] mkdir cdrom
+[root@XXX /] mount -r -t iso9660 -o conv=auto /dev/cdrom /cdrom
+[root@XXX /] cd root
+[root@XXX /root] mkdir dl2x
+[root@XXX /root] cd dl2x
+[root@XXX dl2x] cp /cdrom/linux/dl2x.tgz /root/dl2x
+[root@XXX dl2x] tar xfvz dl2x.tgz 
+[root@XXX dl2x] make all
+
+Floppy disc drive
+-----------------
+
+[root@XXX /] cd root
+[root@XXX /root] mkdir dl2x
+[root@XXX /root] cd dl2x
+[root@XXX dl2x] mcopy a:/linux/dl2x.tgz /root/dl2x
+[root@XXX dl2x] tar xfvz dl2x.tgz 
+[root@XXX dl2x] make all
+
+Installing the Driver
+=====================
+
+  Manual Installation
+  -------------------
+  Once the driver has been compiled, it must be loaded, enabled, and bound
+  to a protocol stack in order to establish network connectivity. To load a
+  module enter the command:
+
+  insmod dl2x.o
+
+  or
+
+  insmod dl2x.o <optional parameter>    ; add parameter
+  
+  ===============================================================
+   example: insmod dl2x.o media=100mbps_hd
+   or       insmod dl2x.o media=3
+   or      insmod dl2x.o media=3 2     ; for 2 cards
+  ===============================================================
+
+  Please reference the list of the command line parameters supported by
+  the Linux device driver below.
+
+  The insmod command only loads the driver and gives it a name of the form
+  eth0, eth1, etc. To bring the NIC into an operational state,
+  it is necessary to issue the following command:
+
+  ifconfig eth0 up
+
+  Finally, to bind the driver to the active protocol (e.g., TCP/IP with
+  Linux), enter the following command:
+
+  ifup eth0
+
+  Note that this is meaningful only if the system can find a configuration
+  script that contains the necessary network information. A sample will be
+  given in the next paragraph.
+
+  The commands to unload a driver are as follows:
+
+  ifdown eth0
+  ifconfig eth0 down
+  rmmod dl2x.o
+
+  The following are the commands to list the currently loaded modules and
+  to see the current network configuration.
+
+  lsmod
+  ifconfig
+
+
+  Automated Installation
+  ----------------------
+  This section describes how to install the driver such that it is
+  automatically loaded and configured at boot time. The following description
+  is based on a Red Hat 6.0/7.0 distribution, but it can easily be ported to
+  other distributions as well.
+
+  Red Hat v6.x/v7.x
+  -----------------
+  1. Copy dl2x.o to the network modules directory, typically
+     /lib/modules/2.x.x-xx/net or /lib/modules/2.x.x/kernel/drivers/net.
+  2. Locate the boot module configuration file, most commonly modules.conf
+     or conf.modules in the /etc directory. Add the following lines:
+
+     alias ethx dl2x
+     options dl2x <optional parameters>
+
+     where ethx will be eth0 if the NIC is the only ethernet adapter, eth1 if
+     one other ethernet adapter is installed, etc. Refer to the table in the
+     previous section for the list of optional parameters.
+  3. Locate the network configuration scripts, normally the
+     /etc/sysconfig/network-scripts directory, and create a configuration
+     script named ifcfg-ethx that contains network information.
+  4. Note that for most Linux distributions, Red Hat included, a configuration
+     utility with a graphical user interface is provided to perform steps 2
+     and 3 above.
+
+
+Parameter Description
+=====================
+You can install this driver without any addtional parameter. However, if you 
+are going to have extensive functions then it is necessary to set extra 
+parameter. Below is a list of the command line parameters supported by the 
+Linux device
+driver.
+
+mtu=packet_size                 - Specifies the maximum packet size. default
+                                  is 1500.
+
+media=xxxxxxxxx                        - Specifies the media type the NIC operates at.
+                                 autosense     Autosensing active media.
+                                 10mbps_hd     10Mbps half duplex.
+                                 10mbps_fd     10Mbps full duplex.
+                                 100mbps_hd    100Mbps half duplex.
+                                 100mbps_fd    100Mbps full duplex.
+                                 1000mbps_fd   1000Mbps full duplex.
+                                 1000mbps_hd   1000Mbps half duplex.
+                                 0             Autosensing active media.
+                                 1             10Mbps half duplex.
+                                 2             10Mbps full duplex.
+                                 3             100Mbps half duplex.
+                                 4             100Mbps full duplex.
+                                 5             1000Mbps full duplex.
+                                 6             1000Mbps half duplex.
+                                 By default, the NIC operates at autosense.
+                                 
+vlan=x                         - Specifies the VLAN ID. If vlan=0, the  
+                                 Virtual Local Area Network (VLAN) function is
+                                 disable. 
+                                 
+jumbo=x                                - Specifies the jumbo frame support. If jumbo=1, 
+                                 the NIC accept jumbo frames. By default, this
+                                 function is disabled.
+
+Configuration Script Sample
+===========================
+Here is a sample of a simple configuration script:
+
+DEVICE=eth0
+USERCTL=no
+ONBOOT=yes
+POOTPROTO=none
+BROADCAST=207.200.5.255
+NETWORK=207.200.5.0
+NETMASK=255.255.255.0
+IPADDR=207.200.5.2
+
+
+Troubleshooting
+===============
+Q: Couldn't compiler the driver ?
+A1: Copy all necessary files on same current directory. Make sure all files 
+   are Unix file format (no LF). You can use some convertible program conver 
+   it from DOS to UNIX. (Like dos2unix,  UltraEdit-32 ...).
+      
+A2: The default include directory configured in Makefile is 
+    /usr/src/linux/include. If kernel source was not installed, you could 
+    not compile driver. Try to install kernel source, and make sure kernel 
+    source in /usr/src/linux. If there is a copy of header files in 
+    /usr/include, you can try to change the variable "INCLUDEDIR" in Makefile from 
+    /usr/src/linux/include to /usr/include.
+    
index 8b3de51297b8b423381137ea6daf391f7528d62d..76a54c9f31b3806070a09e5cebc120ef99f6c0d3 100644 (file)
@@ -106,6 +106,12 @@ M: p_gortmaker@yahoo.com
 L:     linux-net@vger.kernel.org
 S:     Maintained
 
+ACENIC DRIVER
+P:     Jes Sorensen
+M:     jes@trained-monkey.org
+L:     linux-acenic@sunsite.dk
+S:     Maintained
+
 ACI MIXER DRIVER
 P:     Robert Siemer
 M:     Robert.Siemer@gmx.de
@@ -566,8 +572,8 @@ S:  Maintained
 
 HIPPI
 P:     Jes Sorensen
-M:     jes@linuxcare.com
-L:     linux-hippi@sunsite.auc.dk
+M:     jes@trained-monkey.org
+L:     linux-hippi@sunsite.dk
 S:     Maintained
 
 HP100: Driver for HP 10/100 Mbit/s Voice Grade Network Adapter Series
@@ -812,7 +818,7 @@ S:     Maintained
 
 M68K
 P:     Jes Sorensen
-M:     jes@linuxcare.com
+M:     jes@trained-monkey.org
 W:     http://www.clark.net/pub/lawrencc/linux/index.html
 L:     linux-m68k@lists.linux-m68k.org
 S:     Maintained
index 822ae7407f64e632e80f1cee2b4f2430d92c453c..fde5dbf42fb42bc80fe9b179e01e2f01b7e99038 100644 (file)
@@ -414,6 +414,7 @@ CONFIG_EEPRO100=y
 #
 # CONFIG_ACENIC is not set
 # CONFIG_ACENIC_OMIT_TIGON_I is not set
+# CONFIG_DL2K is not set
 # CONFIG_MYRI_SBUS is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
index 15b20d6956f7a50109cc42e53bbad3fc21a73400..0ba8589d4d0406abf04b9834495a95bb72e3ebff 100644 (file)
@@ -456,7 +456,7 @@ void handle_vm86_fault(struct kernel_vm86_regs * regs, long error_code)
        if (VMPI.vm86dbg_active && VMPI.vm86dbg_TFpendig) \
                pushw(ssp,sp,popw(ssp,sp) | TF_MASK);
 #define VM86_FAULT_RETURN \
-       if (VMPI.force_return_for_pic  && (VEFLAGS & IF_MASK)) \
+       if (VMPI.force_return_for_pic  && (VEFLAGS & (IF_MASK | VIF_MASK))) \
                return_to_32bit(regs, VM86_PICRETURN); \
        return;
                                           
index 5ea759857a2c3023a9f3c6a9e970d0e36e9e80fa..aaca7e2edd835c34104f2aac615140fe2881df9d 100644 (file)
@@ -116,8 +116,11 @@ unsigned int rtas_entry;  /* physical pointer */
 unsigned int rtas_size;
 unsigned int old_rtas;
 
-/* Set for a newworld machine */
+/* Set for a newworld or CHRP machine */
 int use_of_interrupt_tree;
+struct device_node *dflt_interrupt_controller;
+int num_interrupt_controllers;
+
 int pmac_newworld;
 
 static struct device_node *allnodes;
@@ -1153,7 +1156,19 @@ inspect_node(phandle node, struct device_node *dad,
                *prev_propp = PTRUNRELOC(pp);
                prev_propp = &pp->next;
        }
-       *prev_propp = 0;
+       if (np->node != NULL) {
+               /* Add a "linux,phandle" property" */
+               pp = (struct property *) mem_start;
+               *prev_propp = PTRUNRELOC(pp);
+               prev_propp = &pp->next;
+               namep = (char *) (pp + 1);
+               pp->name = PTRUNRELOC(namep);
+               strcpy(namep, RELOC("linux,phandle"));
+               mem_start = ALIGN((unsigned long)namep + strlen(namep) + 1);
+               pp->value = (unsigned char *) PTRUNRELOC(&np->node);
+               pp->length = sizeof(np->node);
+       }
+       *prev_propp = NULL;
 
        /* get the node's full name */
        l = (int) call_prom(RELOC("package-to-path"), 3, 1, node,
@@ -1186,19 +1201,46 @@ void
 finish_device_tree(void)
 {
        unsigned long mem = (unsigned long) klimit;
+       struct device_node *np;
 
-       /* All newworld machines now use the interrupt tree */
-       struct device_node *np = allnodes;
-
-       while(np && (_machine == _MACH_Pmac)) {
+       /* All newworld pmac machines and CHRPs now use the interrupt tree */
+       for (np = allnodes; np != NULL; np = np->allnext) {
                if (get_property(np, "interrupt-parent", 0)) {
-                       pmac_newworld = 1;
+                       use_of_interrupt_tree = 1;
                        break;
                }
-               np = np->allnext;
        }
-       if ((_machine == _MACH_chrp) || (boot_infos == 0 && pmac_newworld))
-               use_of_interrupt_tree = 1;
+       if (_machine == _MACH_Pmac && use_of_interrupt_tree)
+               pmac_newworld = 1;
+
+#ifdef CONFIG_BOOTX_TEXT
+       if (boot_infos && pmac_newworld) {
+               prom_print("WARNING ! BootX/miBoot booting is not supported on this machine\n");
+               prom_print("          You should use an Open Firmware bootloader\n");
+       }
+#endif /* CONFIG_BOOTX_TEXT */
+
+       if (use_of_interrupt_tree) {
+               /*
+                * We want to find out here how many interrupt-controller
+                * nodes there are, and if we are booted from BootX,
+                * we need a pointer to the first (and hopefully only)
+                * such node.  But we can't use find_devices here since
+                * np->name has not been set yet.  -- paulus
+                */
+               int n = 0;
+               char *name;
+
+               for (np = allnodes; np != NULL; np = np->allnext) {
+                       if ((name = get_property(np, "name", NULL)) == NULL
+                           || strcmp(name, "interrupt-controller") != 0)
+                               continue;
+                       if (n == 0)
+                               dflt_interrupt_controller = np;
+                       ++n;
+               }
+               num_interrupt_controllers = n;
+       }
 
        mem = finish_node(allnodes, mem, NULL, 1, 1);
        dev_tree_size = mem - (unsigned long) allnodes;
@@ -1240,9 +1282,8 @@ finish_node(struct device_node *np, unsigned long mem_start,
        if (ifunc != NULL) {
                mem_start = ifunc(np, mem_start, naddrc, nsizec);
        }
-       if (use_of_interrupt_tree) {
+       if (use_of_interrupt_tree)
                mem_start = finish_node_interrupts(np, mem_start);
-       }
 
        /* Look for #address-cells and #size-cells properties. */
        ip = (int *) get_property(np, "#address-cells", 0);
@@ -1298,141 +1339,210 @@ finish_node(struct device_node *np, unsigned long mem_start,
        return mem_start;
 }
 
-/* This routine walks the interrupt tree for a given device node and gather 
- * all necessary informations according to the draft interrupt mapping
- * for CHRP. The current version was only tested on Apple "Core99" machines
- * and may not handle cascaded controllers correctly.
+/*
+ * Find the interrupt parent of a node.
  */
-__init
-static unsigned long
-finish_node_interrupts(struct device_node *np, unsigned long mem_start)
+static struct device_node *intr_parent(struct device_node *p)
 {
-       /* Finish this node */
-       unsigned int *isizep, *asizep, *interrupts, *map, *map_mask, *reg;
-       phandle *parent;
-       struct device_node *node, *parent_node;
-       int l, isize, ipsize, asize, map_size, regpsize;
-
-       /* Currently, we don't look at all nodes with no "interrupts" property */
-       interrupts = (unsigned int *)get_property(np, "interrupts", &l);
-       if (interrupts == NULL)
-               return mem_start;
-       ipsize = l>>2;
+       phandle *parp;
+
+       parp = (phandle *) get_property(p, "interrupt-parent", NULL);
+       if (parp == NULL)
+               return p->parent;
+       p = find_phandle(*parp);
+       if (p != NULL)
+               return p;
+       /*
+        * On a powermac booted with BootX, we don't get to know the
+        * phandles for any nodes, so find_phandle will return NULL.
+        * Fortunately these machines only have one interrupt controller
+        * so there isn't in fact any ambiguity.  -- paulus
+        */
+       if (num_interrupt_controllers == 1)
+               p = dflt_interrupt_controller;
+       return p;
+}
 
-       reg = (unsigned int *)get_property(np, "reg", &l);
-       regpsize = l>>2;
+/*
+ * Find out the size of each entry of the interrupts property
+ * for a node.
+ */
+static int
+prom_n_intr_cells(struct device_node *np)
+{
+       struct device_node *p;
+       unsigned int *icp;
+
+       for (p = np; (p = intr_parent(p)) != NULL; ) {
+               icp = (unsigned int *)
+                       get_property(p, "#interrupt-cells", NULL);
+               if (icp != NULL)
+                       return *icp;
+               if (get_property(p, "interrupt-controller", NULL) != NULL
+                   || get_property(p, "interrupt-map", NULL) != NULL) {
+                       printk("oops, node %s doesn't have #interrupt-cells\n",
+                              p->full_name);
+                       return 1;
+               }
+       }
+       printk("prom_n_intr_cells failed for %s\n", np->full_name);
+       return 1;
+}
 
-       /* We assume default interrupt cell size is 1 (bugus ?) */
-       isize = 1;
-       node = np;
-       
-       do {
-           /* We adjust the cell size if the current parent contains an #interrupt-cells
-            * property */
-           isizep = (unsigned int *)get_property(node, "#interrupt-cells", &l);
-           if (isizep)
-               isize = *isizep;
-
-           /* We don't do interrupt cascade (ISA) for now, we stop on the first 
-            * controller found
-            */
-           if (get_property(node, "interrupt-controller", &l)) {
-               int i,j;
-               int cvt_irq;
-
-               /* XXX on chrp, offset interrupt numbers for the
-                  8259 by 0, those for the openpic by 16 */
-               cvt_irq = _machine == _MACH_chrp
-                       && get_property(node, "interrupt-parent", NULL) == 0;
-               np->intrs = (struct interrupt_info *) mem_start;
-               np->n_intrs = ipsize / isize;
-               mem_start += np->n_intrs * sizeof(struct interrupt_info);
-               for (i = 0; i < np->n_intrs; ++i) {
-                   np->intrs[i].line = *interrupts++;
-                   if (cvt_irq)
-                       np->intrs[i].line = openpic_to_irq(np->intrs[i].line);
-                   np->intrs[i].sense = 1;
-                   if (isize > 1)
-                       np->intrs[i].sense = *interrupts++;
-                   for (j=2; j<isize; j++)
-                       interrupts++;
+/*
+ * Map an interrupt from a device up to the platform interrupt
+ * descriptor.
+ */
+static int
+map_interrupt(unsigned int **irq, struct device_node **ictrler,
+             struct device_node *np, unsigned int *ints, int nintrc)
+{
+       struct device_node *p, *ipar;
+       unsigned int *imap, *imask, *ip;
+       int i, imaplen, match;
+       int newintrc, newaddrc;
+       unsigned int *reg;
+       int naddrc;
+
+       reg = (unsigned int *) get_property(np, "reg", NULL);
+       naddrc = prom_n_addr_cells(np);
+       p = intr_parent(np);
+       while (p != NULL) {
+               if (get_property(p, "interrupt-controller", NULL) != NULL)
+                       /* this node is an interrupt controller, stop here */
+                       break;
+               imap = (unsigned int *)
+                       get_property(p, "interrupt-map", &imaplen);
+               if (imap == NULL) {
+                       p = intr_parent(p);
+                       continue;
+               }
+               imask = (unsigned int *)
+                       get_property(p, "interrupt-map-mask", NULL);
+               if (imask == NULL) {
+                       printk("oops, %s has interrupt-map but no mask\n",
+                              p->full_name);
+                       return 0;
                }
+               imaplen /= sizeof(unsigned int);
+               match = 0;
+               ipar = NULL;
+               while (imaplen > 0 && !match) {
+                       /* check the child-interrupt field */
+                       match = 1;
+                       for (i = 0; i < naddrc && match; ++i)
+                               match = ((reg[i] ^ imap[i]) & imask[i]) == 0;
+                       for (; i < naddrc + nintrc && match; ++i)
+                               match = ((ints[i-naddrc] ^ imap[i]) & imask[i]) == 0;
+                       imap += naddrc + nintrc;
+                       imaplen -= naddrc + nintrc;
+                       /* grab the interrupt parent */
+                       ipar = find_phandle((phandle) *imap++);
+                       --imaplen;
+                       if (ipar == NULL && num_interrupt_controllers == 1)
+                               /* cope with BootX not giving us phandles */
+                               ipar = dflt_interrupt_controller;
+                       if (ipar == NULL) {
+                               printk("oops, no int parent %x in map of %s\n",
+                                      imap[-1], p->full_name);
+                               return 0;
+                       }
+                       /* find the parent's # addr and intr cells */
+                       ip = (unsigned int *)
+                               get_property(ipar, "#interrupt-cells", NULL);
+                       if (ip == NULL) {
+                               printk("oops, no #interrupt-cells on %s\n",
+                                      ipar->full_name);
+                               return 0;
+                       }
+                       newintrc = *ip;
+                       ip = (unsigned int *)
+                               get_property(ipar, "#address-cells", NULL);
+                       newaddrc = (ip == NULL)? 0: *ip;
+                       imap += newaddrc + newintrc;
+                       imaplen -= newaddrc + newintrc;
+               }
+               if (imaplen < 0) {
+                       printk("oops, error decoding int-map on %s, len=%d\n",
+                              p->full_name, imaplen);
+                       return 0;
+               }
+               if (!match) {
+                       printk("oops, no match in %s int-map for %s\n",
+                              p->full_name, np->full_name);
+                       return 0;
+               }
+               p = ipar;
+               naddrc = newaddrc;
+               nintrc = newintrc;
+               ints = imap - nintrc;
+               reg = ints - naddrc;
+       }
+       if (p == NULL)
+               printk("hmmm, int tree for %s doesn't have ctrler\n",
+                      np->full_name);
+       *irq = ints;
+       *ictrler = p;
+       return nintrc;
+}
+
+/*
+ * New version of finish_node_interrupts.
+ */
+static unsigned long
+finish_node_interrupts(struct device_node *np, unsigned long mem_start)
+{
+       unsigned int *ints;
+       int intlen, intrcells;
+       int i, j, n, offset;
+       unsigned int *irq;
+       struct device_node *ic;
+
+       ints = (unsigned int *) get_property(np, "interrupts", &intlen);
+       if (ints == NULL)
                return mem_start;
-           }
-           /* We lookup for an interrupt-map. This code can only handle one interrupt
-            * per device in the map. We also don't handle #address-cells in the parent
-            * I skip the pci node itself here, may not be necessary but I don't like it's
-            * reg property.
-            */
-           if (np != node)
-               map = (unsigned int *)get_property(node, "interrupt-map", &l);
-            else
-               map = NULL;
-           if (map && l) {
-               int i, found, temp_isize;
-               map_size = l>>2;
-               map_mask = (unsigned int *)get_property(node, "interrupt-map-mask", &l);
-               asizep = (unsigned int *)get_property(node, "#address-cells", &l);
-               if (asizep && l == sizeof(unsigned int))
-                   asize = *asizep;
-               else
-                   asize = 0;
-               found = 0;
-               while(map_size>0 && !found) {
-                   found = 1;
-                   for (i=0; i<asize; i++) {
-                       unsigned int mask = map_mask ? map_mask[i] : 0xffffffff;
-                       if (!reg || (i>=regpsize) || ((mask & *map) != (mask & reg[i])))
-                           found = 0;
-                       map++;
-                       map_size--;
-                   }
-                   for (i=0; i<isize; i++) {
-                       unsigned int mask = map_mask ? map_mask[i+asize] : 0xffffffff;
-                       if ((mask & *map) != (mask & interrupts[i]))
-                           found = 0;
-                       map++;
-                       map_size--;
-                   }
-                   parent = *((phandle *)(map));
-                   map+=1; map_size-=1;
-                   parent_node = find_phandle(parent);
-                   temp_isize = isize;
-                   if (parent_node) {
-                       isizep = (unsigned int *)get_property(parent_node, "#interrupt-cells", &l);
-                       if (isizep)
-                           temp_isize = *isizep;
-                   }
-                   if (!found) {
-                       map += temp_isize;
-                       map_size-=temp_isize;
-                   }
-               }
-               if (found) {
-                   node = parent_node;
-                   reg = NULL;
-                   regpsize = 0;
-                   interrupts = (unsigned int *)map;
-                   ipsize = temp_isize*1;
-                   continue;
-               }
-           }
-           /* We look for an explicit interrupt-parent.
-            */
-           parent = (phandle *)get_property(node, "interrupt-parent", &l);
-           if (parent && (l == sizeof(phandle)) &&
-               (parent_node = find_phandle(*parent))) {
-               node = parent_node;
-               continue;
-           }
-           /* Default, get real parent */
-           node = node->parent;
-       } while(node);
+       intrcells = prom_n_intr_cells(np);
+       intlen /= intrcells * sizeof(unsigned int);
+       np->n_intrs = intlen;
+       np->intrs = (struct interrupt_info *) mem_start;
+       mem_start += intlen * sizeof(struct interrupt_info);
+
+       for (i = 0; i < intlen; ++i) {
+               np->intrs[i].line = 0;
+               np->intrs[i].sense = 1;
+               n = map_interrupt(&irq, &ic, np, ints, intrcells);
+               if (n <= 0)
+                       continue;
+               offset = 0;
+               /*
+                * On a CHRP we have an 8259 which is subordinate to
+                * the openpic in the interrupt tree, but we want the
+                * openpic's interrupt numbers offsetted, not the 8259's.
+                * So we apply the offset if the controller is at the
+                * root of the interrupt tree, i.e. has no interrupt-parent.
+                * This doesn't cope with the general case of multiple
+                * cascaded interrupt controllers, but then neither will
+                * irq.c at the moment either.  -- paulus
+                */
+               if (num_interrupt_controllers > 1 && ic != NULL
+                   && get_property(ic, "interrupt-parent", NULL) == NULL)
+                       offset = 16;
+               np->intrs[i].line = irq[0] + offset;
+               if (n > 1)
+                       np->intrs[i].sense = irq[1];
+               if (n > 2) {
+                       printk("hmmm, got %d intr cells for %s:", n,
+                              np->full_name);
+                       for (j = 0; j < n; ++j)
+                               printk(" %d", irq[j]);
+                       printk("\n");
+               }
+               ints += intrcells;
+       }
 
        return mem_start;
 }
 
-
 /*
  * When BootX makes a copy of the device tree from the MacOS
  * Name Registry, it is in the format we use but all of the pointers
@@ -1475,7 +1585,7 @@ prom_n_addr_cells(struct device_node* np)
                ip = (int *) get_property(np, "#address-cells", 0);
                if (ip != NULL)
                        return *ip;
-       } while(np->parent);
+       } while (np->parent);
        /* No #address-cells property for the root node, default to 1 */
        return 1;
 }
@@ -1490,7 +1600,7 @@ prom_n_size_cells(struct device_node* np)
                ip = (int *) get_property(np, "#size-cells", 0);
                if (ip != NULL)
                        return *ip;
-       } while(np->parent);
+       } while (np->parent);
        /* No #size-cells property for the root node, default to 1 */
        return 1;
 }
@@ -1502,8 +1612,7 @@ interpret_pci_props(struct device_node *np, unsigned long mem_start,
 {
        struct address_range *adr;
        struct pci_reg_property *pci_addrs;
-       int i, l, *ip, ml;
-       struct pci_intr_map *imp;
+       int i, l, *ip;
 
        pci_addrs = (struct pci_reg_property *)
                get_property(np, "assigned-addresses", &l);
@@ -1525,44 +1634,6 @@ interpret_pci_props(struct device_node *np, unsigned long mem_start,
        if (use_of_interrupt_tree)
                return mem_start;
 
-       /*
-        * If the pci host bridge has an interrupt-map property,
-        * look for our node in it.
-        */
-       if (np->parent != 0 && pci_addrs != 0
-           && (imp = (struct pci_intr_map *)
-               get_property(np->parent, "interrupt-map", &ml)) != 0
-           && (ip = (int *) get_property(np, "interrupts", &l)) != 0) {
-               unsigned int devfn = pci_addrs[0].addr.a_hi & 0xff00;
-               unsigned int cell_size;
-               struct device_node* np2;
-               /* This is hackish, but is only used for BootX booting */
-               cell_size = sizeof(struct pci_intr_map);
-               np2 = np->parent;
-               while(np2) {
-                       if (device_is_compatible(np2, "uni-north")) {
-                               cell_size += 4;
-                               break;
-                       }
-                       np2 = np2->parent;
-               }
-               np->n_intrs = 0;
-               np->intrs = (struct interrupt_info *) mem_start;
-               for (i = 0; (ml -= cell_size) >= 0; ++i) {
-                       if (imp->addr.a_hi == devfn) {
-                               np->intrs[np->n_intrs].line = imp->intr;
-                               np->intrs[np->n_intrs].sense = 1; /* FIXME */
-                               ++np->n_intrs;
-                       }
-                       imp = (struct pci_intr_map *)(((unsigned int)imp)
-                               + cell_size);
-               }
-               if (np->n_intrs == 0)
-                       np->intrs = 0;
-               mem_start += np->n_intrs * sizeof(struct interrupt_info);
-               return mem_start;
-       }
-
        ip = (int *) get_property(np, "AAPL,interrupts", &l);
        if (ip == 0 && np->parent)
                ip = (int *) get_property(np->parent, "AAPL,interrupts", &l);
@@ -1677,26 +1748,10 @@ interpret_macio_props(struct device_node *np, unsigned long mem_start,
                ip = (int *) get_property(np, "AAPL,interrupts", &l);
        if (ip != 0) {
                np->intrs = (struct interrupt_info *) mem_start;
-               if (_machine == _MACH_Pmac) {
-                       /* for the iMac */
-                       np->n_intrs = l / sizeof(int);
-                       /* Hack for BootX on Core99 */
-                       if (keylargo)
-                               np->n_intrs = np->n_intrs/2;
-                       for (i = 0; i < np->n_intrs; ++i) {
-                               np->intrs[i].line = *ip++;
-                               if (keylargo)
-                                       np->intrs[i].sense = *ip++;
-                               else
-                                       np->intrs[i].sense = 1;
-                       }
-               } else {
-                       /* CHRP machines */
-                       np->n_intrs = l / (2 * sizeof(int));
-                       for (i = 0; i < np->n_intrs; ++i) {
-                               np->intrs[i].line = openpic_to_irq(*ip++);
-                               np->intrs[i].sense = *ip++;
-                       }
+               np->n_intrs = l / sizeof(int);
+               for (i = 0; i < np->n_intrs; ++i) {
+                       np->intrs[i].line = *ip++;
+                       np->intrs[i].sense = 1;
                }
                mem_start += np->n_intrs * sizeof(struct interrupt_info);
        }
@@ -1978,13 +2033,12 @@ get_property(struct device_node *np, const char *name, int *lenp)
 {
        struct property *pp;
 
-       for (pp = np->properties; pp != 0; pp = pp->next) {
+       for (pp = np->properties; pp != 0; pp = pp->next)
                if (pp->name != NULL && strcmp(pp->name, name) == 0) {
                        if (lenp != 0)
                                *lenp = pp->length;
                        return pp->value;
                }
-       }
        return 0;
 }
 
index 52472167fcf1ad501a8d10c3044c0a462486e679..a57c0b96f06c3dc0e881173670a901a450a73cfa 100644 (file)
@@ -967,6 +967,7 @@ static void end_buffer_io_sync(struct buffer_head *bh, int uptodate)
 {
        mark_buffer_uptodate(bh, uptodate);
        unlock_buffer(bh);
+       atomic_dec(&bh->b_count);
 }
 
 /**
@@ -1055,6 +1056,7 @@ void ll_rw_block(int rw, int nr, struct buffer_head * bhs[])
                        continue;
 
                /* We have the buffer lock */
+               atomic_inc(&bh->b_count);
                bh->b_end_io = end_buffer_io_sync;
 
                switch(rw) {
index ce15a467cc3528112b8bc88293d82544014a555f..a0ca8e94dc9de64952be48a4ef4b2678a7f9694d 100644 (file)
@@ -117,6 +117,7 @@ static int access_count[MAX_HD];
 static char ps2esdi_valid[MAX_HD];
 static int ps2esdi_sizes[MAX_HD << 6];
 static int ps2esdi_blocksizes[MAX_HD << 6];
+static int ps2esdi_maxsect[MAX_HD << 6];
 static int ps2esdi_drives;
 static struct hd_struct ps2esdi[MAX_HD << 6];
 static u_short io_base;
index 646cfb103bf8fc05ebd14431b049c3ed4d9321ba..f36e7334cc63ef5ac66b4ae61178750a286836aa 100644 (file)
@@ -59,8 +59,8 @@
  *
  */
 
-static char *serial_version = "5.05b";
-static char *serial_revdate = "2001-05-03";
+static char *serial_version = "5.05c";
+static char *serial_revdate = "2001-07-08";
 
 /*
  * Serial driver configuration section.  Here are the various options:
@@ -3512,7 +3512,7 @@ static void autoconfig_startech_uarts(struct async_struct *info,
                                      struct serial_state *state,
                                      unsigned long flags)
 {
-       unsigned char scratch, scratch2, scratch3;
+       unsigned char scratch, scratch2, scratch3, scratch4;
 
        /*
         * First we check to see if it's an Oxford Semiconductor UART.
@@ -3556,17 +3556,32 @@ static void autoconfig_startech_uarts(struct async_struct *info,
         * XR16C854.
         * 
         */
+
+       /* Save the DLL and DLM */
+
        serial_outp(info, UART_LCR, UART_LCR_DLAB);
+       scratch3 = serial_inp(info, UART_DLL);
+       scratch4 = serial_inp(info, UART_DLM);
+
        serial_outp(info, UART_DLL, 0);
        serial_outp(info, UART_DLM, 0);
-       state->revision = serial_inp(info, UART_DLL);
+       scratch2 = serial_inp(info, UART_DLL);
        scratch = serial_inp(info, UART_DLM);
        serial_outp(info, UART_LCR, 0);
+
        if (scratch == 0x10 || scratch == 0x14) {
+               if (scratch == 0x10)
+                       state->revision = scratch2;
                state->type = PORT_16850;
                return;
        }
 
+       /* Restore the DLL and DLM */
+
+       serial_outp(info, UART_LCR, UART_LCR_DLAB);
+       serial_outp(info, UART_DLL, scratch3);
+       serial_outp(info, UART_DLM, scratch4);
+       serial_outp(info, UART_LCR, 0);
        /*
         * We distinguish between the '654 and the '650 by counting
         * how many bytes are in the FIFO.  I'm using this for now,
@@ -3979,10 +3994,7 @@ static void __devinit start_pci_pnp_board(struct pci_dev *dev,
  * seems to be mainly needed on card using the PLX which also use I/O
  * mapped memory.
  */
-static int
-#ifndef MODULE
-__devinit
-#endif
+static int __devinit
 pci_plx9050_fn(struct pci_dev *dev, struct pci_board *board, int enable)
 {
        u8 data, *p, irq_config;
@@ -4046,10 +4058,7 @@ pci_plx9050_fn(struct pci_dev *dev, struct pci_board *board, int enable)
 #define PCI_DEVICE_ID_SIIG_1S_10x (PCI_DEVICE_ID_SIIG_1S_10x_550 & 0xfffc)
 #define PCI_DEVICE_ID_SIIG_2S_10x (PCI_DEVICE_ID_SIIG_2S_10x_550 & 0xfff8)
 
-static int
-#ifndef MODULE
-__devinit
-#endif
+static int __devinit
 pci_siig10x_fn(struct pci_dev *dev, struct pci_board *board, int enable)
 {
        u16 data, *p;
@@ -4078,10 +4087,7 @@ pci_siig10x_fn(struct pci_dev *dev, struct pci_board *board, int enable)
 #define PCI_DEVICE_ID_SIIG_2S_20x (PCI_DEVICE_ID_SIIG_2S_20x_550 & 0xfffc)
 #define PCI_DEVICE_ID_SIIG_2S1P_20x (PCI_DEVICE_ID_SIIG_2S1P_20x_550 & 0xfffc)
 
-static int
-#ifndef MODULE
-__devinit
-#endif
+static int __devinit
 pci_siig20x_fn(struct pci_dev *dev, struct pci_board *board, int enable)
 {
        u8 data;
@@ -4102,10 +4108,7 @@ pci_siig20x_fn(struct pci_dev *dev, struct pci_board *board, int enable)
 }
 
 /* Added for EKF Intel i960 serial boards */
-static int
-#ifndef MODULE
-__devinit
-#endif
+static int __devinit
 pci_inteli960ni_fn(struct pci_dev *dev,
                   struct pci_board *board,
                   int enable)
@@ -4163,10 +4166,7 @@ static struct timedia_struct {
        { 0, 0 }
 };
 
-static int
-#ifndef MODULE
-__devinit
-#endif
+static int __devinit
 pci_timedia_fn(struct pci_dev *dev, struct pci_board *board, int enable)
 {
        int     i, j;
@@ -4187,10 +4187,7 @@ pci_timedia_fn(struct pci_dev *dev, struct pci_board *board, int enable)
        return 0;
 }
 
-static int
-#ifndef MODULE
-__devinit
-#endif
+static int __devinit
 pci_xircom_fn(struct pci_dev *dev, struct pci_board *board, int enable)
 {
        __set_current_state(TASK_UNINTERRUPTIBLE);
index fee003d6eecce9acdec7dedc438f10e69db291a9..23d7725616606eabd33ee0ca3016efa6ef4014c3 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: eicon.h,v 1.23.6.3 2001/05/17 21:15:33 kai Exp $
+/* $Id: eicon.h,v 1.23.6.4 2001/06/09 15:14:16 kai Exp $
  *
  * ISDN low-level module for Eicon active ISDN-Cards.
  *
index b1a79f1667349981d8a5b08091ce55b5700ff9ec..ea3185b2c4abe087338ff40c71e3916f8c782c51 100644 (file)
@@ -56,8 +56,8 @@
  *   26 AVM A1 PCMCIA (Fritz)   p0=irq p1=iobase
  *   27 AVM PnP/PCI            p0=irq p1=iobase (PCI no parameter)
  *   28 Sedlbauer Speed Fax+   p0=irq p1=iobase (from isapnp setup)
- *   29 Siemens I-Surf          p0=irq p1=iobase p2=memory (from isapnp setup)   
- *   30 ACER P10                p0=irq p1=iobase (from isapnp setup)   
+ *   29 Siemens I-Surf          p0=irq p1=iobase p2=memory (from isapnp setup)
+ *   30 ACER P10                p0=irq p1=iobase (from isapnp setup)
  *   31 HST Saphir              p0=irq  p1=iobase
  *   32 Telekom A4T             none
  *   33 Scitel Quadro          p0=subcontroller (4*S0, subctrl 1...4)
  *
  */
 
-const char *CardType[] =
-{"No Card", "Teles 16.0", "Teles 8.0", "Teles 16.3", "Creatix/Teles PnP",
- "AVM A1", "Elsa ML", "Elsa Quickstep", "Teles PCMCIA", "ITK ix1-micro Rev.2",
- "Elsa PCMCIA", "Eicon.Diehl Diva", "ISDNLink", "TeleInt", "Teles 16.3c",
- "Sedlbauer Speed Card", "USR Sportster", "ith mic Linux", "Elsa PCI",
- "Compaq ISA", "NETjet-S", "Teles PCI", "Sedlbauer Speed Star (PCMCIA)",
- "AMD 7930", "NICCY", "S0Box", "AVM A1 (PCMCIA)", "AVM Fritz PnP/PCI",
- "Sedlbauer Speed Fax +", "Siemens I-Surf", "Acer P10", "HST Saphir",
- "Telekom A4T", "Scitel Quadro", "Gazel", "HFC 2BDS0 PCI", "Winbond 6692",
- "HFC 2BDS0 SX", "NETspider-U", "HFC-2BDS0-SP PCMCIA",
+const char *CardType[] = {
+       "No Card", "Teles 16.0", "Teles 8.0", "Teles 16.3",
+       "Creatix/Teles PnP", "AVM A1", "Elsa ML", "Elsa Quickstep",
+       "Teles PCMCIA", "ITK ix1-micro Rev.2", "Elsa PCMCIA",
+       "Eicon.Diehl Diva", "ISDNLink", "TeleInt", "Teles 16.3c",
+       "Sedlbauer Speed Card", "USR Sportster", "ith mic Linux",
+       "Elsa PCI", "Compaq ISA", "NETjet-S", "Teles PCI", 
+       "Sedlbauer Speed Star (PCMCIA)", "AMD 7930", "NICCY", "S0Box",
+       "AVM A1 (PCMCIA)", "AVM Fritz PnP/PCI", "Sedlbauer Speed Fax +",
+       "Siemens I-Surf", "Acer P10", "HST Saphir", "Telekom A4T",
+       "Scitel Quadro", "Gazel", "HFC 2BDS0 PCI", "Winbond 6692",
+       "HFC 2BDS0 SX", "NETspider-U", "HFC-2BDS0-SP PCMCIA",
 };
 
 void HiSax_closecard(int cardnr);
@@ -90,9 +92,9 @@ void HiSax_closecard(int cardnr);
 #ifdef CONFIG_HISAX_ELSA
 #define DEFAULT_CARD ISDN_CTYPE_ELSA
 #define DEFAULT_CFG {0,0,0,0}
-int elsa_init_pcmcia(void*, int, int*, int);
+int elsa_init_pcmcia(void *, int, int *, int);
 EXPORT_SYMBOL(elsa_init_pcmcia);
-#endif /* CONFIG_HISAX_ELSA */
+#endif
 
 #ifdef CONFIG_HISAX_AVM_A1
 #undef DEFAULT_CARD
@@ -106,9 +108,9 @@ EXPORT_SYMBOL(elsa_init_pcmcia);
 #undef DEFAULT_CFG
 #define DEFAULT_CARD ISDN_CTYPE_A1_PCMCIA
 #define DEFAULT_CFG {11,0x170,0,0}
-int avm_a1_init_pcmcia(void*, int, int*, int);
+int avm_a1_init_pcmcia(void *, int, int *, int);
 EXPORT_SYMBOL(avm_a1_init_pcmcia);
-#endif /* CONFIG_HISAX_AVM_A1_PCMCIA */
+#endif
 
 #ifdef CONFIG_HISAX_FRITZPCI
 #undef DEFAULT_CARD
@@ -178,9 +180,9 @@ EXPORT_SYMBOL(avm_a1_init_pcmcia);
 #undef DEFAULT_CFG
 #define DEFAULT_CARD ISDN_CTYPE_SEDLBAUER
 #define DEFAULT_CFG {11,0x270,0,0}
-int sedl_init_pcmcia(void*, int, int*, int);
+int sedl_init_pcmcia(void *, int, int *, int);
 EXPORT_SYMBOL(sedl_init_pcmcia);
-#endif /* CONFIG_HISAX_SEDLBAUER */
+#endif
 
 #ifdef CONFIG_HISAX_SPORTSTER
 #undef DEFAULT_CARD
@@ -222,7 +224,7 @@ EXPORT_SYMBOL(sedl_init_pcmcia);
 #undef DEFAULT_CFG
 #define DEFAULT_CARD ISDN_CTYPE_HFC_SX
 #define DEFAULT_CFG {5,0x2E0,0,0}
-int hfc_init_pcmcia(void*, int, int*, int);
+int hfc_init_pcmcia(void *, int, int *, int);
 EXPORT_SYMBOL(hfc_init_pcmcia);
 #endif
 
@@ -255,7 +257,7 @@ EXPORT_SYMBOL(hfc_init_pcmcia);
 #define DEFAULT_CFG {5,0x250,0,0}
 #endif
 
-#ifdef CONFIG_HISAX_BKM_A4T            
+#ifdef CONFIG_HISAX_BKM_A4T
 #undef DEFAULT_CARD
 #undef DEFAULT_CFG
 #define DEFAULT_CARD ISDN_CTYPE_BKM_A4T
@@ -327,8 +329,7 @@ EXPORT_SYMBOL(HiSax_closecard);
 
 #define EMPTY_CARD     {0, DEFAULT_PROTO, {0, 0, 0, 0}, NULL}
 
-struct IsdnCard cards[] =
-{
+struct IsdnCard cards[] = {
        FIRST_CARD,
        EMPTY_CARD,
        EMPTY_CARD,
@@ -373,7 +374,7 @@ MODULE_PARM(id, "s");
 #ifdef IO0_IO1
 MODULE_PARM(io0, "1-8i");
 MODULE_PARM(io1, "1-8i");
-#endif /* IO0_IO1 */
+#endif
 #endif /* MODULE */
 
 int nrcards;
@@ -384,8 +385,7 @@ extern char *l3_revision;
 extern char *lli_revision;
 extern char *tei_revision;
 
-char *
-HiSax_getrev(const char *revision)
+char *HiSax_getrev(const char *revision)
 {
        char *rev;
        char *p;
@@ -399,8 +399,7 @@ HiSax_getrev(const char *revision)
        return rev;
 }
 
-void __init
-HiSaxVersion(void)
+void __init HiSaxVersion(void)
 {
        char tmp[64];
 
@@ -419,26 +418,24 @@ HiSaxVersion(void)
        strcpy(tmp, l3_revision);
        printk(KERN_INFO "HiSax: Layer3 Revision %s\n", HiSax_getrev(tmp));
        strcpy(tmp, lli_revision);
-       printk(KERN_INFO "HiSax: LinkLayer Revision %s\n", HiSax_getrev(tmp));
+       printk(KERN_INFO "HiSax: LinkLayer Revision %s\n",
+              HiSax_getrev(tmp));
        certification_check(1);
 }
 
-void
-HiSax_mod_dec_use_count(void)
+void HiSax_mod_dec_use_count(void)
 {
        MOD_DEC_USE_COUNT;
 }
 
-void
-HiSax_mod_inc_use_count(void)
+void HiSax_mod_inc_use_count(void)
 {
        MOD_INC_USE_COUNT;
 }
 
 #ifndef MODULE
 #define MAX_ARG        (HISAX_MAX_CARDS*5)
-static int __init
-HiSax_setup(char *line)
+static int __init HiSax_setup(char *line)
 {
        int i, j, argc;
        int ints[MAX_ARG + 1];
@@ -446,7 +443,7 @@ HiSax_setup(char *line)
 
        str = get_options(line, MAX_ARG, ints);
        argc = ints[0];
-       printk(KERN_DEBUG"HiSax_setup: argc(%d) str(%s)\n", argc, str);
+       printk(KERN_DEBUG "HiSax_setup: argc(%d) str(%s)\n", argc, str);
        i = 0;
        j = 1;
        while (argc && (i < HISAX_MAX_CARDS)) {
@@ -484,7 +481,7 @@ HiSax_setup(char *line)
                strcpy(HiSaxID, "HiSax");
                HiSax_id = HiSaxID;
        }
-       return(1);
+       return 1;
 }
 
 __setup("hisax=", HiSax_setup);
@@ -527,7 +524,7 @@ extern int setup_ix1micro(struct IsdnCard *card);
 #endif
 
 #if CARD_DIEHLDIVA
-extern int  setup_diva(struct IsdnCard *card);
+extern int setup_diva(struct IsdnCard *card);
 #endif
 
 #if CARD_ASUSCOM
@@ -609,43 +606,41 @@ extern int setup_netjet_u(struct IsdnCard *card);
 /*
  * Find card with given driverId
  */
-static inline struct IsdnCardState
-*hisax_findcard(int driverid)
+static inline struct IsdnCardState *hisax_findcard(int driverid)
 {
        int i;
 
        for (i = 0; i < nrcards; i++)
                if (cards[i].cs)
                        if (cards[i].cs->myid == driverid)
-                               return (cards[i].cs);
-       return (NULL);
+                               return cards[i].cs;
+       return NULL;
 }
 
 /*
  * Find card with given card number
  */
-struct IsdnCardState
-*hisax_get_card(int cardnr)
+struct IsdnCardState *hisax_get_card(int cardnr)
 {
-       if ((cardnr <= nrcards) && (cardnr>0))
-               if (cards[cardnr-1].cs)
-                       return (cards[cardnr-1].cs);
-       return (NULL);
+       if ((cardnr <= nrcards) && (cardnr > 0))
+               if (cards[cardnr - 1].cs)
+                       return cards[cardnr - 1].cs;
+       return NULL;
 }
 
-int
-HiSax_readstatus(u_char * buf, int len, int user, int id, int channel)
+int HiSax_readstatus(u_char * buf, int len, int user, int id, int channel)
 {
-       int count,cnt;
+       int count, cnt;
        u_char *p = buf;
        struct IsdnCardState *cs = hisax_findcard(id);
 
        if (cs) {
                if (len > HISAX_STATUS_BUFSIZE) {
-                       printk(KERN_WARNING "HiSax: status overflow readstat %d/%d\n",
-                               len, HISAX_STATUS_BUFSIZE);
+                       printk(KERN_WARNING
+                              "HiSax: status overflow readstat %d/%d\n",
+                              len, HISAX_STATUS_BUFSIZE);
                }
-               count = cs->status_end - cs->status_read +1;
+               count = cs->status_end - cs->status_read + 1;
                if (count >= len)
                        count = len;
                if (user)
@@ -673,13 +668,12 @@ HiSax_readstatus(u_char * buf, int len, int user, int id, int channel)
                return len;
        } else {
                printk(KERN_ERR
-                "HiSax: if_readstatus called with invalid driverId!\n");
+                      "HiSax: if_readstatus called with invalid driverId!\n");
                return -ENODEV;
        }
 }
 
-inline int
-jiftime(char *s, long mark)
+static inline int jiftime(char *s, long mark)
 {
        s += 8;
 
@@ -697,15 +691,15 @@ jiftime(char *s, long mark)
        *s-- = mark % 10 + '0';
        mark /= 10;
        *s-- = mark % 10 + '0';
-       return(8);
+       return 8;
 }
 
 static u_char tmpbuf[HISAX_STATUS_BUFSIZE];
 
-void
-VHiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt, va_list args)
+void VHiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt,
+                     va_list args)
 {
-/* if head == NULL the fmt contains the full info */
+       /* if head == NULL the fmt contains the full info */
 
        long flags;
        int count, i;
@@ -729,18 +723,19 @@ VHiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt, va_list args)
                len = strlen(fmt);
        }
        if (!cs) {
-               printk(KERN_WARNING "HiSax: No CardStatus for message %s", p);
+               printk(KERN_WARNING "HiSax: No CardStatus for message %s",
+                      p);
                restore_flags(flags);
                return;
        }
        if (len > HISAX_STATUS_BUFSIZE) {
                printk(KERN_WARNING "HiSax: status overflow %d/%d\n",
-                       len, HISAX_STATUS_BUFSIZE);
+                      len, HISAX_STATUS_BUFSIZE);
                restore_flags(flags);
                return;
        }
        count = len;
-       i = cs->status_end - cs->status_write +1;
+       i = cs->status_end - cs->status_write + 1;
        if (i >= len)
                i = len;
        len -= i;
@@ -754,7 +749,7 @@ VHiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt, va_list args)
                cs->status_write += len;
        }
 #ifdef KERNELSTACK_DEBUG
-       i = (ulong)&len - current->kernel_stack_page;
+       i = (ulong) & len - current->kernel_stack_page;
        sprintf(tmpbuf, "kstack %s %lx use %ld\n", current->comm,
                current->kernel_stack_page, i);
        len = strlen(tmpbuf);
@@ -774,8 +769,7 @@ VHiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt, va_list args)
        }
 }
 
-void
-HiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt, ...)
+void HiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt, ...)
 {
        va_list args;
 
@@ -784,8 +778,7 @@ HiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt, ...)
        va_end(args);
 }
 
-int
-ll_run(struct IsdnCardState *cs, int addfeatures)
+int ll_run(struct IsdnCardState *cs, int addfeatures)
 {
        long flags;
        isdn_ctrl ic;
@@ -800,19 +793,17 @@ ll_run(struct IsdnCardState *cs, int addfeatures)
        return 0;
 }
 
-void
-ll_stop(struct IsdnCardState *cs)
+void ll_stop(struct IsdnCardState *cs)
 {
        isdn_ctrl ic;
 
        ic.command = ISDN_STAT_STOP;
        ic.driver = cs->myid;
        cs->iif.statcallb(&ic);
-//     CallcFreeChan(cs);
+       //      CallcFreeChan(cs);
 }
 
-static void
-ll_unload(struct IsdnCardState *cs)
+static void ll_unload(struct IsdnCardState *cs)
 {
        isdn_ctrl ic;
 
@@ -827,8 +818,7 @@ ll_unload(struct IsdnCardState *cs)
        kfree(cs->dlog);
 }
 
-static void
-closecard(int cardnr)
+static void closecard(int cardnr)
 {
        struct IsdnCardState *csta = cards[cardnr].cs;
 
@@ -856,56 +846,54 @@ closecard(int cardnr)
        ll_unload(csta);
 }
 
-static int __devinit
-init_card(struct IsdnCardState *cs)
+static int __devinit init_card(struct IsdnCardState *cs)
 {
        int irq_cnt, cnt = 3;
        long flags;
 
        if (!cs->irq)
-               return(cs->cardmsg(cs, CARD_INIT, NULL));
+               return cs->cardmsg(cs, CARD_INIT, NULL);
        save_flags(flags);
        cli();
        irq_cnt = kstat_irqs(cs->irq);
-       printk(KERN_INFO "%s: IRQ %d count %d\n", CardType[cs->typ], cs->irq,
-               irq_cnt);
+       printk(KERN_INFO "%s: IRQ %d count %d\n", CardType[cs->typ],
+              cs->irq, irq_cnt);
        if (request_irq(cs->irq, cs->irq_func, cs->irq_flags, "HiSax", cs)) {
                printk(KERN_WARNING "HiSax: couldn't get interrupt %d\n",
-                       cs->irq);
+                      cs->irq);
                restore_flags(flags);
-               return(1);
+               return 1;
        }
        while (cnt) {
                cs->cardmsg(cs, CARD_INIT, NULL);
                sti();
                set_current_state(TASK_UNINTERRUPTIBLE);
                /* Timeout 10ms */
-               schedule_timeout((10*HZ)/1000);
+               schedule_timeout((10 * HZ) / 1000);
                restore_flags(flags);
-               printk(KERN_INFO "%s: IRQ %d count %d\n", CardType[cs->typ],
-                       cs->irq, kstat_irqs(cs->irq));
+               printk(KERN_INFO "%s: IRQ %d count %d\n",
+                      CardType[cs->typ], cs->irq, kstat_irqs(cs->irq));
                if (kstat_irqs(cs->irq) == irq_cnt) {
                        printk(KERN_WARNING
                               "%s: IRQ(%d) getting no interrupts during init %d\n",
                               CardType[cs->typ], cs->irq, 4 - cnt);
                        if (cnt == 1) {
                                free_irq(cs->irq, cs);
-                               return (2);
+                               return 2;
                        } else {
                                cs->cardmsg(cs, CARD_RESET, NULL);
                                cnt--;
                        }
                } else {
                        cs->cardmsg(cs, CARD_TEST, NULL);
-                       return(0);
+                       return 0;
                }
        }
        restore_flags(flags);
-       return(3);
+       return 3;
 }
 
-static int __devinit
-checkcard(int cardnr, char *id, int *busy_flag)
+static int __devinit checkcard(int cardnr, char *id, int *busy_flag)
 {
        long flags;
        int ret = 0;
@@ -923,8 +911,8 @@ checkcard(int cardnr, char *id, int *busy_flag)
        }
        memset(cs, 0, sizeof(struct IsdnCardState));
        card->cs = cs;
-       cs->chanlimit = 2; /* maximum B-channel number */
-       cs->logecho = 0; /* No echo logging */
+       cs->chanlimit = 2;      /* maximum B-channel number */
+       cs->logecho = 0;        /* No echo logging */
        cs->cardnr = cardnr;
        cs->debug = L1_DEB_WARN;
        cs->HW_Flags = 0;
@@ -940,14 +928,12 @@ checkcard(int cardnr, char *id, int *busy_flag)
 
        if (card->typ <= 0 || card->typ > ISDN_CTYPE_COUNT) {
                printk(KERN_WARNING
-                      "HiSax: Card Type %d out of range\n",
-                      card->typ);
+                      "HiSax: Card Type %d out of range\n", card->typ);
                goto outf_cs;
        }
        if (!(cs->dlog = kmalloc(MAX_DLOG_SPACE, GFP_ATOMIC))) {
                printk(KERN_WARNING
-                      "HiSax: No memory for dlog(card %d)\n",
-                      cardnr + 1);
+                      "HiSax: No memory for dlog(card %d)\n", cardnr + 1);
                goto outf_cs;
        }
        if (!(cs->status_buf = kmalloc(HISAX_STATUS_BUFSIZE, GFP_ATOMIC))) {
@@ -981,7 +967,7 @@ checkcard(int cardnr, char *id, int *busy_flag)
                ISDN_FEATURE_P_NI1 |
 #endif
                0;
-       
+
        cs->iif.command = HiSax_command;
        cs->iif.writecmd = NULL;
        cs->iif.writebuf_skb = HiSax_writebuf_skb;
@@ -1092,12 +1078,12 @@ checkcard(int cardnr, char *id, int *busy_flag)
                break;
 #endif
 #if CARD_HFC_PCI
-       case ISDN_CTYPE_HFC_PCI: 
+       case ISDN_CTYPE_HFC_PCI:
                ret = setup_hfcpci(card);
                break;
 #endif
 #if CARD_HFC_SX
-       case ISDN_CTYPE_HFC_SX: 
+       case ISDN_CTYPE_HFC_SX:
                ret = setup_hfcsx(card);
                break;
 #endif
@@ -1126,7 +1112,7 @@ checkcard(int cardnr, char *id, int *busy_flag)
                ret = setup_testemu(card);
                break;
 #endif
-#if    CARD_BKM_A4T       
+#if    CARD_BKM_A4T
        case ISDN_CTYPE_BKM_A4T:
                ret = setup_bkm_a4t(card);
                break;
@@ -1163,8 +1149,7 @@ checkcard(int cardnr, char *id, int *busy_flag)
                goto outf_cs;
        }
        if (!(cs->rcvbuf = kmalloc(MAX_DFRAME_LEN_L1, GFP_ATOMIC))) {
-               printk(KERN_WARNING
-                      "HiSax: No memory for isac rcvbuf\n");
+               printk(KERN_WARNING "HiSax: No memory for isac rcvbuf\n");
                ll_unload(cs);
                goto outf_cs;
        }
@@ -1210,8 +1195,7 @@ checkcard(int cardnr, char *id, int *busy_flag)
        return ret;
 }
 
-void __devinit
-HiSax_shiftcards(int idx)
+void __devinit HiSax_shiftcards(int idx)
 {
        int i;
 
@@ -1219,8 +1203,7 @@ HiSax_shiftcards(int idx)
                memcpy(&cards[i], &cards[i + 1], sizeof(cards[i]));
 }
 
-int __devinit
-HiSax_inithardware(int *busy_flag)
+int __devinit HiSax_inithardware(int *busy_flag)
 {
        int foundcards = 0;
        int i = 0;
@@ -1254,7 +1237,8 @@ HiSax_inithardware(int *busy_flag)
                        foundcards++;
                        i++;
                } else {
-                       printk(KERN_WARNING "HiSax: Card %s not installed !\n",
+                       printk(KERN_WARNING
+                              "HiSax: Card %s not installed !\n",
                               CardType[cards[i].typ]);
                        HiSax_shiftcards(i);
                        nrcards--;
@@ -1263,19 +1247,17 @@ HiSax_inithardware(int *busy_flag)
        return foundcards;
 }
 
-void
-HiSax_closecard(int cardnr)
+void HiSax_closecard(int cardnr)
 {
-       int     i,last=nrcards - 1;
+       int i, last = nrcards - 1;
 
-       if (cardnr>last)
+       if (cardnr > last)
                return;
        if (cards[cardnr].cs) {
                ll_stop(cards[cardnr].cs);
                release_tei(cards[cardnr].cs);
-               
                CallcFreeChan(cards[cardnr].cs);
-               
+
                closecard(cardnr);
                if (cards[cardnr].cs->irq)
                        free_irq(cards[cardnr].cs->irq, cards[cardnr].cs);
@@ -1283,15 +1265,14 @@ HiSax_closecard(int cardnr)
                cards[cardnr].cs = NULL;
        }
        i = cardnr;
-       while (i!=last) {
-               cards[i] = cards[i+1];
+       while (i <= last) {
+               cards[i] = cards[i + 1];
                i++;
        }
        nrcards--;
 }
 
-void
-HiSax_reportcard(int cardnr, int sel)
+void HiSax_reportcard(int cardnr, int sel)
 {
        struct IsdnCardState *cs = cards[cardnr].cs;
 
@@ -1299,21 +1280,25 @@ HiSax_reportcard(int cardnr, int sel)
        printk(KERN_DEBUG "HiSax: Type %s\n", CardType[cs->typ]);
        printk(KERN_DEBUG "HiSax: debuglevel %x\n", cs->debug);
        printk(KERN_DEBUG "HiSax: HiSax_reportcard address 0x%lX\n",
-               (ulong) & HiSax_reportcard);
+              (ulong) & HiSax_reportcard);
        printk(KERN_DEBUG "HiSax: cs 0x%lX\n", (ulong) cs);
        printk(KERN_DEBUG "HiSax: HW_Flags %lx bc0 flg %lx bc1 flg %lx\n",
-               cs->HW_Flags, cs->bcs[0].Flag, cs->bcs[1].Flag);
+              cs->HW_Flags, cs->bcs[0].Flag, cs->bcs[1].Flag);
        printk(KERN_DEBUG "HiSax: bcs 0 mode %d ch%d\n",
-               cs->bcs[0].mode, cs->bcs[0].channel);
+              cs->bcs[0].mode, cs->bcs[0].channel);
        printk(KERN_DEBUG "HiSax: bcs 1 mode %d ch%d\n",
-               cs->bcs[1].mode, cs->bcs[1].channel);
+              cs->bcs[1].mode, cs->bcs[1].channel);
 #ifdef ERROR_STATISTIC
        printk(KERN_DEBUG "HiSax: dc errors(rx,crc,tx) %d,%d,%d\n",
-               cs->err_rx, cs->err_crc, cs->err_tx);
-       printk(KERN_DEBUG "HiSax: bc0 errors(inv,rdo,crc,tx) %d,%d,%d,%d\n",
-               cs->bcs[0].err_inv, cs->bcs[0].err_rdo, cs->bcs[0].err_crc, cs->bcs[0].err_tx);
-       printk(KERN_DEBUG "HiSax: bc1 errors(inv,rdo,crc,tx) %d,%d,%d,%d\n",
-               cs->bcs[1].err_inv, cs->bcs[1].err_rdo, cs->bcs[1].err_crc, cs->bcs[1].err_tx);
+              cs->err_rx, cs->err_crc, cs->err_tx);
+       printk(KERN_DEBUG
+              "HiSax: bc0 errors(inv,rdo,crc,tx) %d,%d,%d,%d\n",
+              cs->bcs[0].err_inv, cs->bcs[0].err_rdo, cs->bcs[0].err_crc,
+              cs->bcs[0].err_tx);
+       printk(KERN_DEBUG
+              "HiSax: bc1 errors(inv,rdo,crc,tx) %d,%d,%d,%d\n",
+              cs->bcs[1].err_inv, cs->bcs[1].err_rdo, cs->bcs[1].err_crc,
+              cs->bcs[1].err_tx);
        if (sel == 99) {
                cs->err_rx  = 0;
                cs->err_crc = 0;
@@ -1333,7 +1318,7 @@ HiSax_reportcard(int cardnr, int sel)
 static int __init HiSax_init(void)
 {
        int i, retval;
-#ifdef MODULE 
+#ifdef MODULE
        int j;
        int nzproto = 0;
 #endif
@@ -1357,7 +1342,7 @@ static int __init HiSax_init(void)
 
 #ifdef MODULE
        if (!type[0]) {
-               /* We 'll register drivers later, but init basic functions*/
+               /* We 'll register drivers later, but init basic functions */
                return 0;
        }
 #ifdef CONFIG_HISAX_ELSA
@@ -1396,98 +1381,100 @@ static int __init HiSax_init(void)
                        nzproto++;
                }
                switch (type[i]) {
-                       case ISDN_CTYPE_16_0:
-                               cards[j].para[0] = irq[i];
-                               cards[j].para[1] = mem[i];
-                               cards[j].para[2] = io[i];
-                               break;
+               case ISDN_CTYPE_16_0:
+                       cards[j].para[0] = irq[i];
+                       cards[j].para[1] = mem[i];
+                       cards[j].para[2] = io[i];
+                       break;
 
-                       case ISDN_CTYPE_8_0:
-                               cards[j].para[0] = irq[i];
-                               cards[j].para[1] = mem[i];
-                               break;
+               case ISDN_CTYPE_8_0:
+                       cards[j].para[0] = irq[i];
+                       cards[j].para[1] = mem[i];
+                       break;
 
 #ifdef IO0_IO1
-                       case ISDN_CTYPE_PNP:
-                       case ISDN_CTYPE_NICCY:
-                               cards[j].para[0] = irq[i];
-                               cards[j].para[1] = io0[i];
-                               cards[j].para[2] = io1[i];
-                               break;
-                       case ISDN_CTYPE_COMPAQ_ISA:
-                               cards[j].para[0] = irq[i];
-                               cards[j].para[1] = io0[i];
-                               cards[j].para[2] = io1[i];
-                               cards[j].para[3] = io[i];
-                               break;
-#endif
-                       case ISDN_CTYPE_ELSA:
-                       case ISDN_CTYPE_HFC_PCI:
-                               cards[j].para[0] = io[i];
-                               break;
-                       case ISDN_CTYPE_16_3:
-                       case ISDN_CTYPE_TELESPCMCIA:
-                       case ISDN_CTYPE_A1:
-                       case ISDN_CTYPE_A1_PCMCIA:
-                       case ISDN_CTYPE_ELSA_PNP:
-                       case ISDN_CTYPE_ELSA_PCMCIA:
-                       case ISDN_CTYPE_IX1MICROR2:
-                       case ISDN_CTYPE_DIEHLDIVA:
-                       case ISDN_CTYPE_ASUSCOM:
-                       case ISDN_CTYPE_TELEINT:
-                       case ISDN_CTYPE_SEDLBAUER:
-                       case ISDN_CTYPE_SEDLBAUER_PCMCIA:
-                       case ISDN_CTYPE_SEDLBAUER_FAX:
-                       case ISDN_CTYPE_SPORTSTER:
-                       case ISDN_CTYPE_MIC:
-                       case ISDN_CTYPE_TELES3C:
-                       case ISDN_CTYPE_ACERP10:
-                       case ISDN_CTYPE_S0BOX:
-                       case ISDN_CTYPE_FRITZPCI:
-                       case ISDN_CTYPE_HSTSAPHIR:
-                       case ISDN_CTYPE_GAZEL:
-                       case ISDN_CTYPE_HFC_SX:
-                       case ISDN_CTYPE_HFC_SP_PCMCIA:
-                               cards[j].para[0] = irq[i];
-                               cards[j].para[1] = io[i];
-                               break;
-                       case ISDN_CTYPE_ISURF:
+               case ISDN_CTYPE_PNP:
+               case ISDN_CTYPE_NICCY:
+                       cards[j].para[0] = irq[i];
+                       cards[j].para[1] = io0[i];
+                       cards[j].para[2] = io1[i];
+                       break;
+               case ISDN_CTYPE_COMPAQ_ISA:
+                       cards[j].para[0] = irq[i];
+                       cards[j].para[1] = io0[i];
+                       cards[j].para[2] = io1[i];
+                       cards[j].para[3] = io[i];
+                       break;
+#endif
+               case ISDN_CTYPE_ELSA:
+               case ISDN_CTYPE_HFC_PCI:
+                       cards[j].para[0] = io[i];
+                       break;
+               case ISDN_CTYPE_16_3:
+               case ISDN_CTYPE_TELESPCMCIA:
+               case ISDN_CTYPE_A1:
+               case ISDN_CTYPE_A1_PCMCIA:
+               case ISDN_CTYPE_ELSA_PNP:
+               case ISDN_CTYPE_ELSA_PCMCIA:
+               case ISDN_CTYPE_IX1MICROR2:
+               case ISDN_CTYPE_DIEHLDIVA:
+               case ISDN_CTYPE_ASUSCOM:
+               case ISDN_CTYPE_TELEINT:
+               case ISDN_CTYPE_SEDLBAUER:
+               case ISDN_CTYPE_SEDLBAUER_PCMCIA:
+               case ISDN_CTYPE_SEDLBAUER_FAX:
+               case ISDN_CTYPE_SPORTSTER:
+               case ISDN_CTYPE_MIC:
+               case ISDN_CTYPE_TELES3C:
+               case ISDN_CTYPE_ACERP10:
+               case ISDN_CTYPE_S0BOX:
+               case ISDN_CTYPE_FRITZPCI:
+               case ISDN_CTYPE_HSTSAPHIR:
+               case ISDN_CTYPE_GAZEL:
+               case ISDN_CTYPE_HFC_SX:
+               case ISDN_CTYPE_HFC_SP_PCMCIA:
+                       cards[j].para[0] = irq[i];
+                       cards[j].para[1] = io[i];
+                       break;
+               case ISDN_CTYPE_ISURF:
+                       cards[j].para[0] = irq[i];
+                       cards[j].para[1] = io[i];
+                       cards[j].para[2] = mem[i];
+                       break;
+               case ISDN_CTYPE_ELSA_PCI:
+               case ISDN_CTYPE_NETJET_S:
+               case ISDN_CTYPE_AMD7930:
+               case ISDN_CTYPE_TELESPCI:
+               case ISDN_CTYPE_W6692:
+               case ISDN_CTYPE_NETJET_U:
+                       break;
+               case ISDN_CTYPE_BKM_A4T:
+                       break;
+               case ISDN_CTYPE_SCT_QUADRO:
+                       if (irq[i]) {
                                cards[j].para[0] = irq[i];
-                               cards[j].para[1] = io[i];
-                               cards[j].para[2] = mem[i];
-                               break;
-                       case ISDN_CTYPE_ELSA_PCI:
-                       case ISDN_CTYPE_NETJET_S:
-                       case ISDN_CTYPE_AMD7930:
-                       case ISDN_CTYPE_TELESPCI:
-                       case ISDN_CTYPE_W6692:
-                       case ISDN_CTYPE_NETJET_U:
-                               break;
-                       case ISDN_CTYPE_BKM_A4T:
-                               break;
-                       case ISDN_CTYPE_SCT_QUADRO:
-                               if (irq[i]) {
-                                       cards[j].para[0] = irq[i];
-                               } else {
-                                       /* QUADRO is a 4 BRI card */
-                                       cards[j++].para[0] = 1;
-                                       cards[j].typ = ISDN_CTYPE_SCT_QUADRO; 
-                                       cards[j].protocol = protocol[i];
-                                       cards[j++].para[0] = 2;
-                                       cards[j].typ = ISDN_CTYPE_SCT_QUADRO; 
-                                       cards[j].protocol = protocol[i];
-                                       cards[j++].para[0] = 3;
-                                       cards[j].typ = ISDN_CTYPE_SCT_QUADRO; 
-                                       cards[j].protocol = protocol[i];
-                                       cards[j].para[0] = 4;
-                               }
-                               break;
+                       } else {
+                               /* QUADRO is a 4 BRI card */
+                               cards[j++].para[0] = 1;
+                               cards[j].typ = ISDN_CTYPE_SCT_QUADRO;
+                               cards[j].protocol = protocol[i];
+                               cards[j++].para[0] = 2;
+                               cards[j].typ = ISDN_CTYPE_SCT_QUADRO;
+                               cards[j].protocol = protocol[i];
+                               cards[j++].para[0] = 3;
+                               cards[j].typ = ISDN_CTYPE_SCT_QUADRO;
+                               cards[j].protocol = protocol[i];
+                               cards[j].para[0] = 4;
+                       }
+                       break;
                }
                j++;
        }
        if (!nzproto) {
-               printk(KERN_WARNING "HiSax: Warning - no protocol specified\n");
-               printk(KERN_WARNING "HiSax: using protocol %s\n", DEFAULT_PROTO_NAME);
+               printk(KERN_WARNING
+                      "HiSax: Warning - no protocol specified\n");
+               printk(KERN_WARNING "HiSax: using protocol %s\n",
+                      DEFAULT_PROTO_NAME);
        }
 #endif
        if (!HiSax_id)
@@ -1505,7 +1492,7 @@ static int __init HiSax_init(void)
                retval = -EIO;
                goto out_isdnl1;
        }
-       
+
        return 0;
 
  out_isdnl1:
@@ -1524,12 +1511,12 @@ static int __init HiSax_init(void)
 
 static void __exit HiSax_exit(void)
 {
-       int cardnr = nrcards -1;
+       int cardnr = nrcards - 1;
        long flags;
 
        save_flags(flags);
        cli();
-       while(cardnr>=0)
+       while (cardnr >= 0)
                HiSax_closecard(cardnr--);
        Isdnl1Free();
        TeiFree();
@@ -1549,7 +1536,7 @@ int elsa_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot)
        nrcards = 0;
        /* Initialize all structs, even though we only accept
           two pcmcia cards
-          */
+       */
        for (i = 0; i < HISAX_MAX_CARDS; i++) {
                cards[i].para[0] = irq[i];
                cards[i].para[1] = io[i];
@@ -1559,7 +1546,7 @@ int elsa_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot)
                }
        }
        cards[0].para[0] = pcm_irq;
-       cards[0].para[1] = (int)pcm_iob;
+       cards[0].para[1] = (int) pcm_iob;
        cards[0].protocol = prot;
        cards[0].typ = ISDN_CTYPE_ELSA_PCMCIA;
 
@@ -1576,7 +1563,7 @@ int elsa_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot)
        HiSax_inithardware(busy_flag);
        printk(KERN_NOTICE "HiSax: module installed\n");
 #endif
-       return (0);
+       return 0;
 }
 #endif
 
@@ -1590,7 +1577,7 @@ int hfc_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot)
        nrcards = 0;
        /* Initialize all structs, even though we only accept
           two pcmcia cards
-          */
+       */
        for (i = 0; i < HISAX_MAX_CARDS; i++) {
                cards[i].para[0] = irq[i];
                cards[i].para[1] = io[i];
@@ -1601,7 +1588,7 @@ int hfc_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot)
                }
        }
        cards[0].para[0] = pcm_irq;
-       cards[0].para[1] = (int)pcm_iob;
+       cards[0].para[1] = (int) pcm_iob;
        cards[0].protocol = prot;
        cards[0].typ = ISDN_CTYPE_HFC_SP_PCMCIA;
        nzproto = 1;
@@ -1619,7 +1606,7 @@ int hfc_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot)
        HiSax_inithardware(busy_flag);
        printk(KERN_NOTICE "HiSax: module installed\n");
 #endif
-       return (0);
+       return 0;
 }
 #endif
 
@@ -1633,7 +1620,7 @@ int sedl_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot)
        nrcards = 0;
        /* Initialize all structs, even though we only accept
           two pcmcia cards
-          */
+       */
        for (i = 0; i < HISAX_MAX_CARDS; i++) {
                cards[i].para[0] = irq[i];
                cards[i].para[1] = io[i];
@@ -1644,7 +1631,7 @@ int sedl_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot)
                }
        }
        cards[0].para[0] = pcm_irq;
-       cards[0].para[1] = (int)pcm_iob;
+       cards[0].para[1] = (int) pcm_iob;
        cards[0].protocol = prot;
        cards[0].typ = ISDN_CTYPE_SEDLBAUER_PCMCIA;
        nzproto = 1;
@@ -1662,7 +1649,7 @@ int sedl_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot)
        HiSax_inithardware(busy_flag);
        printk(KERN_NOTICE "HiSax: module installed\n");
 #endif
-       return (0);
+       return 0;
 }
 #endif
 
@@ -1676,7 +1663,7 @@ int avm_a1_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot)
        nrcards = 0;
        /* Initialize all structs, even though we only accept
           two pcmcia cards
-          */
+       */
        for (i = 0; i < HISAX_MAX_CARDS; i++) {
                cards[i].para[0] = irq[i];
                cards[i].para[1] = io[i];
@@ -1687,7 +1674,7 @@ int avm_a1_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot)
                }
        }
        cards[0].para[0] = pcm_irq;
-       cards[0].para[1] = (int)pcm_iob;
+       cards[0].para[1] = (int) pcm_iob;
        cards[0].protocol = prot;
        cards[0].typ = ISDN_CTYPE_A1_PCMCIA;
        nzproto = 1;
@@ -1705,11 +1692,12 @@ int avm_a1_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot)
        HiSax_inithardware(busy_flag);
        printk(KERN_NOTICE "HiSax: module installed\n");
 #endif
-       return (0);
+       return 0;
 }
 #endif
 
-int __devinit hisax_init_pcmcia(void *pcm_iob, int *busy_flag, struct IsdnCard *card)
+int __devinit hisax_init_pcmcia(void *pcm_iob, int *busy_flag,
+                               struct IsdnCard *card)
 {
        u_char ids[16];
        int ret = -1;
@@ -1720,11 +1708,11 @@ int __devinit hisax_init_pcmcia(void *pcm_iob, int *busy_flag, struct IsdnCard *
        else
                sprintf(ids, "HiSax");
        if (!checkcard(nrcards, ids, busy_flag)) {
-               return(-1);
+               return -1;
        }
        ret = nrcards;
        nrcards++;
-       return (ret);
+       return ret;
 }
 
 #include <linux/pci.h>
diff --git a/drivers/isdn/hisax/md b/drivers/isdn/hisax/md
deleted file mode 100644 (file)
index 5efa612..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-6f9433a8b696076562562d090e3c420f  isac.c
-13c3eed869f5139f44c563e3a8fea1f5  isdnl1.c
-addcff863b0ff1e366c0f2ae9fa6e81e  isdnl2.c
-7076deb94a363945c21ea27aca4a720a  isdnl3.c
-51c603829b6cc4f8421f744ad657ceff  tei.c
-669050ab5079f02887ed0239d86e5474  callc.c
-e592db58630c1f1029cc064110108156  cert.c
-fadeb3b85bb23bc1ac48470c0848d6fa  l3dss1.c
-cf7dec9fac6283716904d26b99188476  l3_1tr6.c
-65d9e5471bc129624f858ebcf0743525  elsa.c
-b4cf8a4dceed9ea6dcba65a85b4eecc7  diva.c
-99e67bea8f6945fa0d4e0aded5bf0fa0  sedlbauer.c
index e95beb90ba6077e6c4a4b064b228d8a0b0ff204a..df3645e9d8d60a06313101db0fb12b3f76af8930 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: isdn_tty.c,v 1.94.6.2 2001/06/09 15:14:15 kai Exp $
+/* $Id: isdn_tty.c,v 1.94.6.3 2001/07/03 14:48:25 kai Exp $
 
  * Linux ISDN subsystem, tty functions and AT-command emulator (linklevel).
  *
@@ -66,7 +66,7 @@ static int bit2si[8] =
 static int si2bit[8] =
 {4, 1, 4, 4, 4, 4, 4, 4};
 
-char *isdn_tty_revision = "$Revision: 1.94.6.2 $";
+char *isdn_tty_revision = "$Revision: 1.94.6.3 $";
 
 
 /* isdn_tty_try_read() is called from within isdn_tty_rcv_skb()
@@ -1420,8 +1420,7 @@ isdn_tty_get_lsr_info(modem_info * info, uint * value)
        status = info->lsr;
        restore_flags(flags);
        result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0);
-       put_user(result, (uint *) value);
-       return 0;
+       return put_user(result, (uint *) value);
 }
 
 
@@ -1444,8 +1443,7 @@ isdn_tty_get_modem_info(modem_info * info, uint * value)
            | ((status & UART_MSR_RI) ? TIOCM_RNG : 0)
            | ((status & UART_MSR_DSR) ? TIOCM_DSR : 0)
            | ((status & UART_MSR_CTS) ? TIOCM_CTS : 0);
-       put_user(result, (uint *) value);
-       return 0;
+       return put_user(result, (uint *) value);
 }
 
 static int
@@ -1454,7 +1452,8 @@ isdn_tty_set_modem_info(modem_info * info, uint cmd, uint * value)
        uint arg;
        int pre_dtr;
 
-       get_user(arg, (uint *) value);
+       if (get_user(arg, (uint *) value))
+               return -EFAULT;
        switch (cmd) {
                case TIOCMBIS:
 #ifdef ISDN_DEBUG_MODEM_IOCTL
@@ -1522,7 +1521,6 @@ isdn_tty_ioctl(struct tty_struct *tty, struct file *file,
               uint cmd, ulong arg)
 {
        modem_info *info = (modem_info *) tty->driver_data;
-       int error;
        int retval;
 
        if (isdn_tty_paranoia_check(info, tty->device, "isdn_tty_ioctl"))
@@ -1552,19 +1550,13 @@ isdn_tty_ioctl(struct tty_struct *tty, struct file *file,
 #ifdef ISDN_DEBUG_MODEM_IOCTL
                        printk(KERN_DEBUG "ttyI%d ioctl TIOCGSOFTCAR\n", info->line);
 #endif
-                       error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(long));
-                       if (error)
-                               return error;
-                       put_user(C_CLOCAL(tty) ? 1 : 0, (ulong *) arg);
-                       return 0;
+                       return put_user(C_CLOCAL(tty) ? 1 : 0, (ulong *) arg);
                case TIOCSSOFTCAR:
 #ifdef ISDN_DEBUG_MODEM_IOCTL
                        printk(KERN_DEBUG "ttyI%d ioctl TIOCSSOFTCAR\n", info->line);
 #endif
-                       error = verify_area(VERIFY_READ, (void *) arg, sizeof(long));
-                       if (error)
-                               return error;
-                       get_user(arg, (ulong *) arg);
+                       if (get_user(arg, (ulong *) arg))
+                               return -EFAULT;
                        tty->termios->c_cflag =
                            ((tty->termios->c_cflag & ~CLOCAL) |
                             (arg ? CLOCAL : 0));
@@ -1573,26 +1565,16 @@ isdn_tty_ioctl(struct tty_struct *tty, struct file *file,
 #ifdef ISDN_DEBUG_MODEM_IOCTL
                        printk(KERN_DEBUG "ttyI%d ioctl TIOCMGET\n", info->line);
 #endif
-                       error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(uint));
-                       if (error)
-                               return error;
                        return isdn_tty_get_modem_info(info, (uint *) arg);
                case TIOCMBIS:
                case TIOCMBIC:
                case TIOCMSET:
-                       error = verify_area(VERIFY_READ, (void *) arg, sizeof(uint));
-                       if (error)
-                               return error;
                        return isdn_tty_set_modem_info(info, cmd, (uint *) arg);
                case TIOCSERGETLSR:     /* Get line status register */
 #ifdef ISDN_DEBUG_MODEM_IOCTL
                        printk(KERN_DEBUG "ttyI%d ioctl TIOCSERGETLSR\n", info->line);
 #endif
-                       error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(uint));
-                       if (error)
-                               return error;
-                       else
-                               return isdn_tty_get_lsr_info(info, (uint *) arg);
+                       return isdn_tty_get_lsr_info(info, (uint *) arg);
                default:
 #ifdef ISDN_DEBUG_MODEM_IOCTL
                        printk(KERN_DEBUG "UNKNOWN ioctl 0x%08x on ttyi%d\n", cmd, info->line);
diff --git a/drivers/message/fusion/Config.in b/drivers/message/fusion/Config.in
new file mode 100644 (file)
index 0000000..4d04055
--- /dev/null
@@ -0,0 +1,39 @@
+mainmenu_option next_comment
+comment 'Fusion MPT device support'
+
+dep_tristate "Fusion MPT (base + ScsiHost) drivers" CONFIG_FUSION $CONFIG_SCSI $CONFIG_BLK_DEV_SD
+
+if [ "$CONFIG_FUSION" = "y" -o "$CONFIG_FUSION" = "m" ]; then
+
+  if [ "$CONFIG_BLK_DEV_SD" = "y" -a "$CONFIG_FUSION" = "y" ]; then
+    define_bool CONFIG_FUSION_BOOT y
+    comment "(ability to boot linux kernel from Fusion device is ENABLED!)"
+  else
+    define_bool CONFIG_FUSION_BOOT n
+    comment "(ability to boot linux kernel from Fusion device is DISABLED!)"
+  fi
+
+  if [ "$CONFIG_MODULES" = "y" ]; then
+    #  How can we force these options to module or nothing?
+    dep_tristate "  Enhanced SCSI error reporting" CONFIG_FUSION_ISENSE $CONFIG_FUSION m
+    dep_tristate "  Fusion MPT misc device (ioctl) driver" CONFIG_FUSION_CTL $CONFIG_FUSION m
+  fi
+
+  dep_tristate "  Fusion MPT LAN driver" CONFIG_FUSION_LAN $CONFIG_FUSION $CONFIG_NET
+  if [ "$CONFIG_FUSION_LAN" != "n" ]; then
+    define_bool CONFIG_NET_FC y
+  fi
+
+else
+
+  define_bool CONFIG_FUSION_BOOT n
+  # These <should> be define_tristate, but we leave them define_bool
+  # for backward compatibility with pre-linux-2.2.15 kernels.
+  # (Bugzilla:fibrebugs, #384)
+  define_bool CONFIG_FUSION_ISENSE n
+  define_bool CONFIG_FUSION_CTL n
+  define_bool CONFIG_FUSION_LAN n
+
+fi
+
+endmenu
diff --git a/drivers/message/fusion/Makefile b/drivers/message/fusion/Makefile
new file mode 100644 (file)
index 0000000..46df657
--- /dev/null
@@ -0,0 +1,72 @@
+#
+# Makefile for the LSI Logic Fusion MPT (Message Passing Technology) drivers.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definition is now inherited from the
+# parent makefile.
+#
+# Note 3! If you want to turn on various debug defines for an extended period of
+# time but don't want them lingering around in the Makefile when you pass it on 
+# to someone else, use the MPT_CFLAGS env variable (thanks Steve). -nromer
+
+#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-{ LSI_LOGIC
+
+#  Architecture-specific...
+#                      # intel
+#EXTRA_CFLAGS += -g
+#                      # sparc64
+#EXTRA_CFLAGS += -gstabs+
+
+EXTRA_CFLAGS += -I. ${MPT_CFLAGS}
+
+# Fusion MPT drivers; recognized debug defines...
+#  MPT general:
+#EXTRA_CFLAGS += -DDEBUG
+#EXTRA_CFLAGS += -DMPT_DEBUG
+#EXTRA_CFLAGS += -DMPT_DEBUG_MSG_FRAME
+#EXTRA_CFLAGS += -DMPT_DEBUG_SPINLOCK
+# driver/module specifics...
+#  For mptbase:
+#CFLAGS_mptbase.o += -DMPT_DEBUG_HANDSHAKE
+#CFLAGS_mptbase.o += -DMPT_DEBUG_IRQ
+#  For {mptscsih, mptctl}:
+#CFLAGS_mptscsih.o += -DMPT_SCSI_USE_NEW_EH
+#CFLAGS_mptscsih.o += -DMPT_SCSI_CACHE_AUTOSENSE
+#CFLAGS_mptscsih.o += -DMPT_DEBUG_SG
+#CFLAGS_mptctl.o += -DMPT_DEBUG_SG
+#  For mptlan:
+#CFLAGS_mptlan.o += -DMPT_LAN_IO_DEBUG
+#  For isense:
+
+#  EXP...
+##mptscsih-objs        := scsihost.o scsiherr.o
+
+#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-} LSI_LOGIC
+
+O_TARGET := fusion.o
+
+export-objs    := mptbase.o mptscsih.o mptlan.o mptctl.o isense.o
+
+# ? what's list-multi for?
+#list-multi    := fusion.o mptscsih.o
+
+obj-$(CONFIG_FUSION)           += mptbase.o mptscsih.o
+obj-$(CONFIG_FUSION_ISENSE)    += isense.o
+obj-$(CONFIG_FUSION_CTL)       += mptctl.o
+obj-$(CONFIG_FUSION_LAN)       += mptlan.o
+
+O_OBJS         := $(filter-out         $(export-objs), $(obj-y))
+OX_OBJS                := $(filter             $(export-objs), $(obj-y))
+M_OBJS         := $(sort $(filter-out  $(export-objs), $(obj-m)))
+MX_OBJS                := $(sort $(filter      $(export-objs), $(obj-m)))
+
+include $(TOPDIR)/Rules.make
+
+
+#  EXP...
+## Fusion MPT extra's...
+##mptscsih.o: $(mptscsih-objs)
+##     $(LD) -r -o $@ $(mptscsih-objs)
diff --git a/drivers/message/fusion/ascq_tbl.c b/drivers/message/fusion/ascq_tbl.c
new file mode 100644 (file)
index 0000000..210c4e7
--- /dev/null
@@ -0,0 +1,2416 @@
+#ifndef SCSI_ASCQ_TBL_C_INCLUDED
+#define SCSI_ASCQ_TBL_C_INCLUDED
+
+/* AuToMaGiCaLlY generated from: "t10.org/asc-num.txt"
+ *******************************************************************************
+ * File: ASC-NUM.TXT
+ * 
+ * SCSI ASC/ASCQ Assignments
+ * Numeric Sorted Listing
+ * as of  5/18/00
+ * 
+ *          D - DIRECT ACCESS DEVICE (SBC-2)                   device column key
+ *          .T - SEQUENTIAL ACCESS DEVICE (SSC)               -------------------
+ *          . L - PRINTER DEVICE (SSC)                           blank = reserved
+ *          .  P - PROCESSOR DEVICE (SPC)                     not blank = allowed
+ *          .  .W - WRITE ONCE READ MULTIPLE DEVICE (SBC-2)
+ *          .  . R - CD DEVICE (MMC)
+ *          .  .  S - SCANNER DEVICE (SCSI-2)
+ *          .  .  .O - OPTICAL MEMORY DEVICE (SBC-2)
+ *          .  .  . M - MEDIA CHANGER DEVICE (SMC)
+ *          .  .  .  C - COMMUNICATION DEVICE (SCSI-2)
+ *          .  .  .  .A - STORAGE ARRAY DEVICE (SCC)
+ *          .  .  .  . E - ENCLOSURE SERVICES DEVICE (SES)
+ *          .  .  .  .  B - SIMPLIFIED DIRECT-ACCESS DEVICE (RBC)
+ *          .  .  .  .  .K - OPTICAL CARD READER/WRITER DEVICE (OCRW)
+ * ASC/ASCQ DTLPWRSOMCAEBK  Description
+ * -------  --------------  ----------------------------------------------------
+ */
+
+static char SenseDevTypes001[] = "DTLPWRSOMCAEBK";
+static char SenseDevTypes002[] = ".T............";
+static char SenseDevTypes003[] = ".T....S.......";
+static char SenseDevTypes004[] = ".TL...S.......";
+static char SenseDevTypes005[] = ".....R........";
+static char SenseDevTypes006[] = "DTL.WRSOM.AEBK";
+static char SenseDevTypes007[] = "D...W..O....BK";
+static char SenseDevTypes008[] = "D...WR.OM...BK";
+static char SenseDevTypes009[] = "DTL.W.SO....BK";
+static char SenseDevTypes010[] = "DTL..R.O....B.";
+static char SenseDevTypes011[] = "DT..W..OMCA.BK";
+static char SenseDevTypes012[] = "..............";
+static char SenseDevTypes013[] = "DTL.WRSOMCAEBK";
+static char SenseDevTypes014[] = "DTL.WRSOM...BK";
+static char SenseDevTypes015[] = "DT...R.OM...BK";
+static char SenseDevTypes016[] = "DTLPWRSO.C...K";
+static char SenseDevTypes017[] = "DT..WR.O....B.";
+static char SenseDevTypes018[] = "....WR.O.....K";
+static char SenseDevTypes019[] = "....WR.O......";
+static char SenseDevTypes020[] = ".T...RS.......";
+static char SenseDevTypes021[] = ".............K";
+static char SenseDevTypes022[] = "DT..W..O....B.";
+static char SenseDevTypes023[] = "DT..WRSO....BK";
+static char SenseDevTypes024[] = "DT..W.SO....BK";
+static char SenseDevTypes025[] = "....WR.O....B.";
+static char SenseDevTypes026[] = "....W..O....B.";
+static char SenseDevTypes027[] = "DT.....O....BK";
+static char SenseDevTypes028[] = "DTL.WRSO....BK";
+static char SenseDevTypes029[] = "DT..WR.O....BK";
+static char SenseDevTypes030[] = "DT..W..O....BK";
+static char SenseDevTypes031[] = "D...WR.O....BK";
+static char SenseDevTypes032[] = "D......O.....K";
+static char SenseDevTypes033[] = "D......O....BK";
+static char SenseDevTypes034[] = "DT..WR.OM...BK";
+static char SenseDevTypes035[] = "D.............";
+static char SenseDevTypes036[] = "DTLPWRSOMCAE.K";
+static char SenseDevTypes037[] = "DTLPWRSOMCA.BK";
+static char SenseDevTypes038[] = ".T...R........";
+static char SenseDevTypes039[] = "DT..WR.OM...B.";
+static char SenseDevTypes040[] = "DTL.WRSOMCAE.K";
+static char SenseDevTypes041[] = "DTLPWRSOMCAE..";
+static char SenseDevTypes042[] = "......S.......";
+static char SenseDevTypes043[] = "............B.";
+static char SenseDevTypes044[] = "DTLPWRSO.CA..K";
+static char SenseDevTypes045[] = "DT...R.......K";
+static char SenseDevTypes046[] = "D.L..R.O....B.";
+static char SenseDevTypes047[] = "..L...........";
+static char SenseDevTypes048[] = ".TL...........";
+static char SenseDevTypes049[] = "DTLPWRSOMC..BK";
+static char SenseDevTypes050[] = "DT..WR.OMCAEBK";
+static char SenseDevTypes051[] = "DT..WR.OMCAEB.";
+static char SenseDevTypes052[] = ".T...R.O......";
+static char SenseDevTypes053[] = "...P..........";
+static char SenseDevTypes054[] = "DTLPWRSOM.AE.K";
+static char SenseDevTypes055[] = "DTLPWRSOM.AE..";
+static char SenseDevTypes056[] = ".......O......";
+static char SenseDevTypes057[] = "DTLPWRSOM...BK";
+static char SenseDevTypes058[] = "DT..WR.O..A.BK";
+static char SenseDevTypes059[] = "DTLPWRSOM....K";
+static char SenseDevTypes060[] = "D......O......";
+static char SenseDevTypes061[] = ".....R......B.";
+static char SenseDevTypes062[] = "D...........B.";
+static char SenseDevTypes063[] = "............BK";
+static char SenseDevTypes064[] = "..........A...";
+
+static ASCQ_Table_t ASCQ_Table[] = {
+  {
+    0x00, 0x00,
+    SenseDevTypes001,
+    "NO ADDITIONAL SENSE INFORMATION"
+  },
+  {
+    0x00, 0x01,
+    SenseDevTypes002,
+    "FILEMARK DETECTED"
+  },
+  {
+    0x00, 0x02,
+    SenseDevTypes003,
+    "END-OF-PARTITION/MEDIUM DETECTED"
+  },
+  {
+    0x00, 0x03,
+    SenseDevTypes002,
+    "SETMARK DETECTED"
+  },
+  {
+    0x00, 0x04,
+    SenseDevTypes003,
+    "BEGINNING-OF-PARTITION/MEDIUM DETECTED"
+  },
+  {
+    0x00, 0x05,
+    SenseDevTypes004,
+    "END-OF-DATA DETECTED"
+  },
+  {
+    0x00, 0x06,
+    SenseDevTypes001,
+    "I/O PROCESS TERMINATED"
+  },
+  {
+    0x00, 0x11,
+    SenseDevTypes005,
+    "AUDIO PLAY OPERATION IN PROGRESS"
+  },
+  {
+    0x00, 0x12,
+    SenseDevTypes005,
+    "AUDIO PLAY OPERATION PAUSED"
+  },
+  {
+    0x00, 0x13,
+    SenseDevTypes005,
+    "AUDIO PLAY OPERATION SUCCESSFULLY COMPLETED"
+  },
+  {
+    0x00, 0x14,
+    SenseDevTypes005,
+    "AUDIO PLAY OPERATION STOPPED DUE TO ERROR"
+  },
+  {
+    0x00, 0x15,
+    SenseDevTypes005,
+    "NO CURRENT AUDIO STATUS TO RETURN"
+  },
+  {
+    0x00, 0x16,
+    SenseDevTypes001,
+    "OPERATION IN PROGRESS"
+  },
+  {
+    0x00, 0x17,
+    SenseDevTypes006,
+    "CLEANING REQUESTED"
+  },
+  {
+    0x01, 0x00,
+    SenseDevTypes007,
+    "NO INDEX/SECTOR SIGNAL"
+  },
+  {
+    0x02, 0x00,
+    SenseDevTypes008,
+    "NO SEEK COMPLETE"
+  },
+  {
+    0x03, 0x00,
+    SenseDevTypes009,
+    "PERIPHERAL DEVICE WRITE FAULT"
+  },
+  {
+    0x03, 0x01,
+    SenseDevTypes002,
+    "NO WRITE CURRENT"
+  },
+  {
+    0x03, 0x02,
+    SenseDevTypes002,
+    "EXCESSIVE WRITE ERRORS"
+  },
+  {
+    0x04, 0x00,
+    SenseDevTypes001,
+    "LOGICAL UNIT NOT READY, CAUSE NOT REPORTABLE"
+  },
+  {
+    0x04, 0x01,
+    SenseDevTypes001,
+    "LOGICAL UNIT IS IN PROCESS OF BECOMING READY"
+  },
+  {
+    0x04, 0x02,
+    SenseDevTypes001,
+    "LOGICAL UNIT NOT READY, INITIALIZING CMD. REQUIRED"
+  },
+  {
+    0x04, 0x03,
+    SenseDevTypes001,
+    "LOGICAL UNIT NOT READY, MANUAL INTERVENTION REQUIRED"
+  },
+  {
+    0x04, 0x04,
+    SenseDevTypes010,
+    "LOGICAL UNIT NOT READY, FORMAT IN PROGRESS"
+  },
+  {
+    0x04, 0x05,
+    SenseDevTypes011,
+    "LOGICAL UNIT NOT READY, REBUILD IN PROGRESS"
+  },
+  {
+    0x04, 0x06,
+    SenseDevTypes011,
+    "LOGICAL UNIT NOT READY, RECALCULATION IN PROGRESS"
+  },
+  {
+    0x04, 0x07,
+    SenseDevTypes001,
+    "LOGICAL UNIT NOT READY, OPERATION IN PROGRESS"
+  },
+  {
+    0x04, 0x08,
+    SenseDevTypes005,
+    "LOGICAL UNIT NOT READY, LONG WRITE IN PROGRESS"
+  },
+  {
+    0x04, 0x09,
+    SenseDevTypes001,
+    "LOGICAL UNIT NOT READY, SELF-TEST IN PROGRESS"
+  },
+  {
+    0x04, 0x10,
+    SenseDevTypes012,
+    "auxiliary memory code 2 (99-148) [proposed]"
+  },
+  {
+    0x05, 0x00,
+    SenseDevTypes013,
+    "LOGICAL UNIT DOES NOT RESPOND TO SELECTION"
+  },
+  {
+    0x06, 0x00,
+    SenseDevTypes008,
+    "NO REFERENCE POSITION FOUND"
+  },
+  {
+    0x07, 0x00,
+    SenseDevTypes014,
+    "MULTIPLE PERIPHERAL DEVICES SELECTED"
+  },
+  {
+    0x08, 0x00,
+    SenseDevTypes013,
+    "LOGICAL UNIT COMMUNICATION FAILURE"
+  },
+  {
+    0x08, 0x01,
+    SenseDevTypes013,
+    "LOGICAL UNIT COMMUNICATION TIME-OUT"
+  },
+  {
+    0x08, 0x02,
+    SenseDevTypes013,
+    "LOGICAL UNIT COMMUNICATION PARITY ERROR"
+  },
+  {
+    0x08, 0x03,
+    SenseDevTypes015,
+    "LOGICAL UNIT COMMUNICATION CRC ERROR (ULTRA-DMA/32)"
+  },
+  {
+    0x08, 0x04,
+    SenseDevTypes016,
+    "UNREACHABLE COPY TARGET"
+  },
+  {
+    0x09, 0x00,
+    SenseDevTypes017,
+    "TRACK FOLLOWING ERROR"
+  },
+  {
+    0x09, 0x01,
+    SenseDevTypes018,
+    "TRACKING SERVO FAILURE"
+  },
+  {
+    0x09, 0x02,
+    SenseDevTypes018,
+    "FOCUS SERVO FAILURE"
+  },
+  {
+    0x09, 0x03,
+    SenseDevTypes019,
+    "SPINDLE SERVO FAILURE"
+  },
+  {
+    0x09, 0x04,
+    SenseDevTypes017,
+    "HEAD SELECT FAULT"
+  },
+  {
+    0x0A, 0x00,
+    SenseDevTypes001,
+    "ERROR LOG OVERFLOW"
+  },
+  {
+    0x0B, 0x00,
+    SenseDevTypes001,
+    "WARNING"
+  },
+  {
+    0x0B, 0x01,
+    SenseDevTypes001,
+    "WARNING - SPECIFIED TEMPERATURE EXCEEDED"
+  },
+  {
+    0x0B, 0x02,
+    SenseDevTypes001,
+    "WARNING - ENCLOSURE DEGRADED"
+  },
+  {
+    0x0C, 0x00,
+    SenseDevTypes020,
+    "WRITE ERROR"
+  },
+  {
+    0x0C, 0x01,
+    SenseDevTypes021,
+    "WRITE ERROR - RECOVERED WITH AUTO REALLOCATION"
+  },
+  {
+    0x0C, 0x02,
+    SenseDevTypes007,
+    "WRITE ERROR - AUTO REALLOCATION FAILED"
+  },
+  {
+    0x0C, 0x03,
+    SenseDevTypes007,
+    "WRITE ERROR - RECOMMEND REASSIGNMENT"
+  },
+  {
+    0x0C, 0x04,
+    SenseDevTypes022,
+    "COMPRESSION CHECK MISCOMPARE ERROR"
+  },
+  {
+    0x0C, 0x05,
+    SenseDevTypes022,
+    "DATA EXPANSION OCCURRED DURING COMPRESSION"
+  },
+  {
+    0x0C, 0x06,
+    SenseDevTypes022,
+    "BLOCK NOT COMPRESSIBLE"
+  },
+  {
+    0x0C, 0x07,
+    SenseDevTypes005,
+    "WRITE ERROR - RECOVERY NEEDED"
+  },
+  {
+    0x0C, 0x08,
+    SenseDevTypes005,
+    "WRITE ERROR - RECOVERY FAILED"
+  },
+  {
+    0x0C, 0x09,
+    SenseDevTypes005,
+    "WRITE ERROR - LOSS OF STREAMING"
+  },
+  {
+    0x0C, 0x0A,
+    SenseDevTypes005,
+    "WRITE ERROR - PADDING BLOCKS ADDED"
+  },
+  {
+    0x0C, 0x0B,
+    SenseDevTypes012,
+    "auxiliary memory code 4 (99-148) [proposed]"
+  },
+  {
+    0x10, 0x00,
+    SenseDevTypes007,
+    "ID CRC OR ECC ERROR"
+  },
+  {
+    0x11, 0x00,
+    SenseDevTypes023,
+    "UNRECOVERED READ ERROR"
+  },
+  {
+    0x11, 0x01,
+    SenseDevTypes023,
+    "READ RETRIES EXHAUSTED"
+  },
+  {
+    0x11, 0x02,
+    SenseDevTypes023,
+    "ERROR TOO LONG TO CORRECT"
+  },
+  {
+    0x11, 0x03,
+    SenseDevTypes024,
+    "MULTIPLE READ ERRORS"
+  },
+  {
+    0x11, 0x04,
+    SenseDevTypes007,
+    "UNRECOVERED READ ERROR - AUTO REALLOCATE FAILED"
+  },
+  {
+    0x11, 0x05,
+    SenseDevTypes025,
+    "L-EC UNCORRECTABLE ERROR"
+  },
+  {
+    0x11, 0x06,
+    SenseDevTypes025,
+    "CIRC UNRECOVERED ERROR"
+  },
+  {
+    0x11, 0x07,
+    SenseDevTypes026,
+    "DATA RE-SYNCHRONIZATION ERROR"
+  },
+  {
+    0x11, 0x08,
+    SenseDevTypes002,
+    "INCOMPLETE BLOCK READ"
+  },
+  {
+    0x11, 0x09,
+    SenseDevTypes002,
+    "NO GAP FOUND"
+  },
+  {
+    0x11, 0x0A,
+    SenseDevTypes027,
+    "MISCORRECTED ERROR"
+  },
+  {
+    0x11, 0x0B,
+    SenseDevTypes007,
+    "UNRECOVERED READ ERROR - RECOMMEND REASSIGNMENT"
+  },
+  {
+    0x11, 0x0C,
+    SenseDevTypes007,
+    "UNRECOVERED READ ERROR - RECOMMEND REWRITE THE DATA"
+  },
+  {
+    0x11, 0x0D,
+    SenseDevTypes017,
+    "DE-COMPRESSION CRC ERROR"
+  },
+  {
+    0x11, 0x0E,
+    SenseDevTypes017,
+    "CANNOT DECOMPRESS USING DECLARED ALGORITHM"
+  },
+  {
+    0x11, 0x0F,
+    SenseDevTypes005,
+    "ERROR READING UPC/EAN NUMBER"
+  },
+  {
+    0x11, 0x10,
+    SenseDevTypes005,
+    "ERROR READING ISRC NUMBER"
+  },
+  {
+    0x11, 0x11,
+    SenseDevTypes005,
+    "READ ERROR - LOSS OF STREAMING"
+  },
+  {
+    0x11, 0x12,
+    SenseDevTypes012,
+    "auxiliary memory code 3 (99-148) [proposed]"
+  },
+  {
+    0x12, 0x00,
+    SenseDevTypes007,
+    "ADDRESS MARK NOT FOUND FOR ID FIELD"
+  },
+  {
+    0x13, 0x00,
+    SenseDevTypes007,
+    "ADDRESS MARK NOT FOUND FOR DATA FIELD"
+  },
+  {
+    0x14, 0x00,
+    SenseDevTypes028,
+    "RECORDED ENTITY NOT FOUND"
+  },
+  {
+    0x14, 0x01,
+    SenseDevTypes029,
+    "RECORD NOT FOUND"
+  },
+  {
+    0x14, 0x02,
+    SenseDevTypes002,
+    "FILEMARK OR SETMARK NOT FOUND"
+  },
+  {
+    0x14, 0x03,
+    SenseDevTypes002,
+    "END-OF-DATA NOT FOUND"
+  },
+  {
+    0x14, 0x04,
+    SenseDevTypes002,
+    "BLOCK SEQUENCE ERROR"
+  },
+  {
+    0x14, 0x05,
+    SenseDevTypes030,
+    "RECORD NOT FOUND - RECOMMEND REASSIGNMENT"
+  },
+  {
+    0x14, 0x06,
+    SenseDevTypes030,
+    "RECORD NOT FOUND - DATA AUTO-REALLOCATED"
+  },
+  {
+    0x15, 0x00,
+    SenseDevTypes014,
+    "RANDOM POSITIONING ERROR"
+  },
+  {
+    0x15, 0x01,
+    SenseDevTypes014,
+    "MECHANICAL POSITIONING ERROR"
+  },
+  {
+    0x15, 0x02,
+    SenseDevTypes029,
+    "POSITIONING ERROR DETECTED BY READ OF MEDIUM"
+  },
+  {
+    0x16, 0x00,
+    SenseDevTypes007,
+    "DATA SYNCHRONIZATION MARK ERROR"
+  },
+  {
+    0x16, 0x01,
+    SenseDevTypes007,
+    "DATA SYNC ERROR - DATA REWRITTEN"
+  },
+  {
+    0x16, 0x02,
+    SenseDevTypes007,
+    "DATA SYNC ERROR - RECOMMEND REWRITE"
+  },
+  {
+    0x16, 0x03,
+    SenseDevTypes007,
+    "DATA SYNC ERROR - DATA AUTO-REALLOCATED"
+  },
+  {
+    0x16, 0x04,
+    SenseDevTypes007,
+    "DATA SYNC ERROR - RECOMMEND REASSIGNMENT"
+  },
+  {
+    0x17, 0x00,
+    SenseDevTypes023,
+    "RECOVERED DATA WITH NO ERROR CORRECTION APPLIED"
+  },
+  {
+    0x17, 0x01,
+    SenseDevTypes023,
+    "RECOVERED DATA WITH RETRIES"
+  },
+  {
+    0x17, 0x02,
+    SenseDevTypes029,
+    "RECOVERED DATA WITH POSITIVE HEAD OFFSET"
+  },
+  {
+    0x17, 0x03,
+    SenseDevTypes029,
+    "RECOVERED DATA WITH NEGATIVE HEAD OFFSET"
+  },
+  {
+    0x17, 0x04,
+    SenseDevTypes025,
+    "RECOVERED DATA WITH RETRIES AND/OR CIRC APPLIED"
+  },
+  {
+    0x17, 0x05,
+    SenseDevTypes031,
+    "RECOVERED DATA USING PREVIOUS SECTOR ID"
+  },
+  {
+    0x17, 0x06,
+    SenseDevTypes007,
+    "RECOVERED DATA WITHOUT ECC - DATA AUTO-REALLOCATED"
+  },
+  {
+    0x17, 0x07,
+    SenseDevTypes031,
+    "RECOVERED DATA WITHOUT ECC - RECOMMEND REASSIGNMENT"
+  },
+  {
+    0x17, 0x08,
+    SenseDevTypes031,
+    "RECOVERED DATA WITHOUT ECC - RECOMMEND REWRITE"
+  },
+  {
+    0x17, 0x09,
+    SenseDevTypes031,
+    "RECOVERED DATA WITHOUT ECC - DATA REWRITTEN"
+  },
+  {
+    0x18, 0x00,
+    SenseDevTypes029,
+    "RECOVERED DATA WITH ERROR CORRECTION APPLIED"
+  },
+  {
+    0x18, 0x01,
+    SenseDevTypes031,
+    "RECOVERED DATA WITH ERROR CORR. & RETRIES APPLIED"
+  },
+  {
+    0x18, 0x02,
+    SenseDevTypes031,
+    "RECOVERED DATA - DATA AUTO-REALLOCATED"
+  },
+  {
+    0x18, 0x03,
+    SenseDevTypes005,
+    "RECOVERED DATA WITH CIRC"
+  },
+  {
+    0x18, 0x04,
+    SenseDevTypes005,
+    "RECOVERED DATA WITH L-EC"
+  },
+  {
+    0x18, 0x05,
+    SenseDevTypes031,
+    "RECOVERED DATA - RECOMMEND REASSIGNMENT"
+  },
+  {
+    0x18, 0x06,
+    SenseDevTypes031,
+    "RECOVERED DATA - RECOMMEND REWRITE"
+  },
+  {
+    0x18, 0x07,
+    SenseDevTypes007,
+    "RECOVERED DATA WITH ECC - DATA REWRITTEN"
+  },
+  {
+    0x19, 0x00,
+    SenseDevTypes032,
+    "DEFECT LIST ERROR"
+  },
+  {
+    0x19, 0x01,
+    SenseDevTypes032,
+    "DEFECT LIST NOT AVAILABLE"
+  },
+  {
+    0x19, 0x02,
+    SenseDevTypes032,
+    "DEFECT LIST ERROR IN PRIMARY LIST"
+  },
+  {
+    0x19, 0x03,
+    SenseDevTypes032,
+    "DEFECT LIST ERROR IN GROWN LIST"
+  },
+  {
+    0x1A, 0x00,
+    SenseDevTypes001,
+    "PARAMETER LIST LENGTH ERROR"
+  },
+  {
+    0x1B, 0x00,
+    SenseDevTypes001,
+    "SYNCHRONOUS DATA TRANSFER ERROR"
+  },
+  {
+    0x1C, 0x00,
+    SenseDevTypes033,
+    "DEFECT LIST NOT FOUND"
+  },
+  {
+    0x1C, 0x01,
+    SenseDevTypes033,
+    "PRIMARY DEFECT LIST NOT FOUND"
+  },
+  {
+    0x1C, 0x02,
+    SenseDevTypes033,
+    "GROWN DEFECT LIST NOT FOUND"
+  },
+  {
+    0x1D, 0x00,
+    SenseDevTypes029,
+    "MISCOMPARE DURING VERIFY OPERATION"
+  },
+  {
+    0x1E, 0x00,
+    SenseDevTypes007,
+    "RECOVERED ID WITH ECC CORRECTION"
+  },
+  {
+    0x1F, 0x00,
+    SenseDevTypes032,
+    "PARTIAL DEFECT LIST TRANSFER"
+  },
+  {
+    0x20, 0x00,
+    SenseDevTypes001,
+    "INVALID COMMAND OPERATION CODE"
+  },
+  {
+    0x20, 0x01,
+    SenseDevTypes012,
+    "access controls code 1 (99-314) [proposed]"
+  },
+  {
+    0x20, 0x02,
+    SenseDevTypes012,
+    "access controls code 2 (99-314) [proposed]"
+  },
+  {
+    0x20, 0x03,
+    SenseDevTypes012,
+    "access controls code 3 (99-314) [proposed]"
+  },
+  {
+    0x21, 0x00,
+    SenseDevTypes034,
+    "LOGICAL BLOCK ADDRESS OUT OF RANGE"
+  },
+  {
+    0x21, 0x01,
+    SenseDevTypes034,
+    "INVALID ELEMENT ADDRESS"
+  },
+  {
+    0x22, 0x00,
+    SenseDevTypes035,
+    "ILLEGAL FUNCTION (USE 20 00, 24 00, OR 26 00)"
+  },
+  {
+    0x24, 0x00,
+    SenseDevTypes001,
+    "INVALID FIELD IN CDB"
+  },
+  {
+    0x24, 0x01,
+    SenseDevTypes001,
+    "CDB DECRYPTION ERROR"
+  },
+  {
+    0x25, 0x00,
+    SenseDevTypes001,
+    "LOGICAL UNIT NOT SUPPORTED"
+  },
+  {
+    0x26, 0x00,
+    SenseDevTypes001,
+    "INVALID FIELD IN PARAMETER LIST"
+  },
+  {
+    0x26, 0x01,
+    SenseDevTypes001,
+    "PARAMETER NOT SUPPORTED"
+  },
+  {
+    0x26, 0x02,
+    SenseDevTypes001,
+    "PARAMETER VALUE INVALID"
+  },
+  {
+    0x26, 0x03,
+    SenseDevTypes036,
+    "THRESHOLD PARAMETERS NOT SUPPORTED"
+  },
+  {
+    0x26, 0x04,
+    SenseDevTypes001,
+    "INVALID RELEASE OF PERSISTENT RESERVATION"
+  },
+  {
+    0x26, 0x05,
+    SenseDevTypes037,
+    "DATA DECRYPTION ERROR"
+  },
+  {
+    0x26, 0x06,
+    SenseDevTypes016,
+    "TOO MANY TARGET DESCRIPTORS"
+  },
+  {
+    0x26, 0x07,
+    SenseDevTypes016,
+    "UNSUPPORTED TARGET DESCRIPTOR TYPE CODE"
+  },
+  {
+    0x26, 0x08,
+    SenseDevTypes016,
+    "TOO MANY SEGMENT DESCRIPTORS"
+  },
+  {
+    0x26, 0x09,
+    SenseDevTypes016,
+    "UNSUPPORTED SEGMENT DESCRIPTOR TYPE CODE"
+  },
+  {
+    0x26, 0x0A,
+    SenseDevTypes016,
+    "UNEXPECTED INEXACT SEGMENT"
+  },
+  {
+    0x26, 0x0B,
+    SenseDevTypes016,
+    "INLINE DATA LENGTH EXCEEDED"
+  },
+  {
+    0x26, 0x0C,
+    SenseDevTypes016,
+    "INVALID OPERATION FOR COPY SOURCE OR DESTINATION"
+  },
+  {
+    0x26, 0x0D,
+    SenseDevTypes016,
+    "COPY SEGMENT GRANULARITY VIOLATION"
+  },
+  {
+    0x27, 0x00,
+    SenseDevTypes029,
+    "WRITE PROTECTED"
+  },
+  {
+    0x27, 0x01,
+    SenseDevTypes029,
+    "HARDWARE WRITE PROTECTED"
+  },
+  {
+    0x27, 0x02,
+    SenseDevTypes029,
+    "LOGICAL UNIT SOFTWARE WRITE PROTECTED"
+  },
+  {
+    0x27, 0x03,
+    SenseDevTypes038,
+    "ASSOCIATED WRITE PROTECT"
+  },
+  {
+    0x27, 0x04,
+    SenseDevTypes038,
+    "PERSISTENT WRITE PROTECT"
+  },
+  {
+    0x27, 0x05,
+    SenseDevTypes038,
+    "PERMANENT WRITE PROTECT"
+  },
+  {
+    0x28, 0x00,
+    SenseDevTypes001,
+    "NOT READY TO READY CHANGE, MEDIUM MAY HAVE CHANGED"
+  },
+  {
+    0x28, 0x01,
+    SenseDevTypes039,
+    "IMPORT OR EXPORT ELEMENT ACCESSED"
+  },
+  {
+    0x29, 0x00,
+    SenseDevTypes001,
+    "POWER ON, RESET, OR BUS DEVICE RESET OCCURRED"
+  },
+  {
+    0x29, 0x01,
+    SenseDevTypes001,
+    "POWER ON OCCURRED"
+  },
+  {
+    0x29, 0x02,
+    SenseDevTypes001,
+    "SCSI BUS RESET OCCURRED"
+  },
+  {
+    0x29, 0x03,
+    SenseDevTypes001,
+    "BUS DEVICE RESET FUNCTION OCCURRED"
+  },
+  {
+    0x29, 0x04,
+    SenseDevTypes001,
+    "DEVICE INTERNAL RESET"
+  },
+  {
+    0x29, 0x05,
+    SenseDevTypes001,
+    "TRANSCEIVER MODE CHANGED TO SINGLE-ENDED"
+  },
+  {
+    0x29, 0x06,
+    SenseDevTypes001,
+    "TRANSCEIVER MODE CHANGED TO LVD"
+  },
+  {
+    0x2A, 0x00,
+    SenseDevTypes013,
+    "PARAMETERS CHANGED"
+  },
+  {
+    0x2A, 0x01,
+    SenseDevTypes013,
+    "MODE PARAMETERS CHANGED"
+  },
+  {
+    0x2A, 0x02,
+    SenseDevTypes040,
+    "LOG PARAMETERS CHANGED"
+  },
+  {
+    0x2A, 0x03,
+    SenseDevTypes036,
+    "RESERVATIONS PREEMPTED"
+  },
+  {
+    0x2A, 0x04,
+    SenseDevTypes041,
+    "RESERVATIONS RELEASED"
+  },
+  {
+    0x2A, 0x05,
+    SenseDevTypes041,
+    "REGISTRATIONS PREEMPTED"
+  },
+  {
+    0x2B, 0x00,
+    SenseDevTypes016,
+    "COPY CANNOT EXECUTE SINCE HOST CANNOT DISCONNECT"
+  },
+  {
+    0x2C, 0x00,
+    SenseDevTypes001,
+    "COMMAND SEQUENCE ERROR"
+  },
+  {
+    0x2C, 0x01,
+    SenseDevTypes042,
+    "TOO MANY WINDOWS SPECIFIED"
+  },
+  {
+    0x2C, 0x02,
+    SenseDevTypes042,
+    "INVALID COMBINATION OF WINDOWS SPECIFIED"
+  },
+  {
+    0x2C, 0x03,
+    SenseDevTypes005,
+    "CURRENT PROGRAM AREA IS NOT EMPTY"
+  },
+  {
+    0x2C, 0x04,
+    SenseDevTypes005,
+    "CURRENT PROGRAM AREA IS EMPTY"
+  },
+  {
+    0x2C, 0x05,
+    SenseDevTypes043,
+    "ILLEGAL POWER CONDITION REQUEST"
+  },
+  {
+    0x2D, 0x00,
+    SenseDevTypes002,
+    "OVERWRITE ERROR ON UPDATE IN PLACE"
+  },
+  {
+    0x2E, 0x00,
+    SenseDevTypes044,
+    "ERROR DETECTED BY THIRD PARTY TEMPORARY INITIATOR"
+  },
+  {
+    0x2E, 0x01,
+    SenseDevTypes044,
+    "THIRD PARTY DEVICE FAILURE"
+  },
+  {
+    0x2E, 0x02,
+    SenseDevTypes044,
+    "COPY TARGET DEVICE NOT REACHABLE"
+  },
+  {
+    0x2E, 0x03,
+    SenseDevTypes044,
+    "INCORRECT COPY TARGET DEVICE TYPE"
+  },
+  {
+    0x2E, 0x04,
+    SenseDevTypes044,
+    "COPY TARGET DEVICE DATA UNDERRUN"
+  },
+  {
+    0x2E, 0x05,
+    SenseDevTypes044,
+    "COPY TARGET DEVICE DATA OVERRUN"
+  },
+  {
+    0x2F, 0x00,
+    SenseDevTypes001,
+    "COMMANDS CLEARED BY ANOTHER INITIATOR"
+  },
+  {
+    0x30, 0x00,
+    SenseDevTypes034,
+    "INCOMPATIBLE MEDIUM INSTALLED"
+  },
+  {
+    0x30, 0x01,
+    SenseDevTypes029,
+    "CANNOT READ MEDIUM - UNKNOWN FORMAT"
+  },
+  {
+    0x30, 0x02,
+    SenseDevTypes029,
+    "CANNOT READ MEDIUM - INCOMPATIBLE FORMAT"
+  },
+  {
+    0x30, 0x03,
+    SenseDevTypes045,
+    "CLEANING CARTRIDGE INSTALLED"
+  },
+  {
+    0x30, 0x04,
+    SenseDevTypes029,
+    "CANNOT WRITE MEDIUM - UNKNOWN FORMAT"
+  },
+  {
+    0x30, 0x05,
+    SenseDevTypes029,
+    "CANNOT WRITE MEDIUM - INCOMPATIBLE FORMAT"
+  },
+  {
+    0x30, 0x06,
+    SenseDevTypes017,
+    "CANNOT FORMAT MEDIUM - INCOMPATIBLE MEDIUM"
+  },
+  {
+    0x30, 0x07,
+    SenseDevTypes006,
+    "CLEANING FAILURE"
+  },
+  {
+    0x30, 0x08,
+    SenseDevTypes005,
+    "CANNOT WRITE - APPLICATION CODE MISMATCH"
+  },
+  {
+    0x30, 0x09,
+    SenseDevTypes005,
+    "CURRENT SESSION NOT FIXATED FOR APPEND"
+  },
+  {
+    0x31, 0x00,
+    SenseDevTypes029,
+    "MEDIUM FORMAT CORRUPTED"
+  },
+  {
+    0x31, 0x01,
+    SenseDevTypes046,
+    "FORMAT COMMAND FAILED"
+  },
+  {
+    0x32, 0x00,
+    SenseDevTypes007,
+    "NO DEFECT SPARE LOCATION AVAILABLE"
+  },
+  {
+    0x32, 0x01,
+    SenseDevTypes007,
+    "DEFECT LIST UPDATE FAILURE"
+  },
+  {
+    0x33, 0x00,
+    SenseDevTypes002,
+    "TAPE LENGTH ERROR"
+  },
+  {
+    0x34, 0x00,
+    SenseDevTypes001,
+    "ENCLOSURE FAILURE"
+  },
+  {
+    0x35, 0x00,
+    SenseDevTypes001,
+    "ENCLOSURE SERVICES FAILURE"
+  },
+  {
+    0x35, 0x01,
+    SenseDevTypes001,
+    "UNSUPPORTED ENCLOSURE FUNCTION"
+  },
+  {
+    0x35, 0x02,
+    SenseDevTypes001,
+    "ENCLOSURE SERVICES UNAVAILABLE"
+  },
+  {
+    0x35, 0x03,
+    SenseDevTypes001,
+    "ENCLOSURE SERVICES TRANSFER FAILURE"
+  },
+  {
+    0x35, 0x04,
+    SenseDevTypes001,
+    "ENCLOSURE SERVICES TRANSFER REFUSED"
+  },
+  {
+    0x36, 0x00,
+    SenseDevTypes047,
+    "RIBBON, INK, OR TONER FAILURE"
+  },
+  {
+    0x37, 0x00,
+    SenseDevTypes013,
+    "ROUNDED PARAMETER"
+  },
+  {
+    0x38, 0x00,
+    SenseDevTypes043,
+    "EVENT STATUS NOTIFICATION"
+  },
+  {
+    0x38, 0x02,
+    SenseDevTypes043,
+    "ESN - POWER MANAGEMENT CLASS EVENT"
+  },
+  {
+    0x38, 0x04,
+    SenseDevTypes043,
+    "ESN - MEDIA CLASS EVENT"
+  },
+  {
+    0x38, 0x06,
+    SenseDevTypes043,
+    "ESN - DEVICE BUSY CLASS EVENT"
+  },
+  {
+    0x39, 0x00,
+    SenseDevTypes040,
+    "SAVING PARAMETERS NOT SUPPORTED"
+  },
+  {
+    0x3A, 0x00,
+    SenseDevTypes014,
+    "MEDIUM NOT PRESENT"
+  },
+  {
+    0x3A, 0x01,
+    SenseDevTypes034,
+    "MEDIUM NOT PRESENT - TRAY CLOSED"
+  },
+  {
+    0x3A, 0x02,
+    SenseDevTypes034,
+    "MEDIUM NOT PRESENT - TRAY OPEN"
+  },
+  {
+    0x3A, 0x03,
+    SenseDevTypes039,
+    "MEDIUM NOT PRESENT - LOADABLE"
+  },
+  {
+    0x3A, 0x04,
+    SenseDevTypes039,
+    "MEDIUM NOT PRESENT - MEDIUM AUXILIARY MEMORY ACCESSIBLE"
+  },
+  {
+    0x3B, 0x00,
+    SenseDevTypes048,
+    "SEQUENTIAL POSITIONING ERROR"
+  },
+  {
+    0x3B, 0x01,
+    SenseDevTypes002,
+    "TAPE POSITION ERROR AT BEGINNING-OF-MEDIUM"
+  },
+  {
+    0x3B, 0x02,
+    SenseDevTypes002,
+    "TAPE POSITION ERROR AT END-OF-MEDIUM"
+  },
+  {
+    0x3B, 0x03,
+    SenseDevTypes047,
+    "TAPE OR ELECTRONIC VERTICAL FORMS UNIT NOT READY"
+  },
+  {
+    0x3B, 0x04,
+    SenseDevTypes047,
+    "SLEW FAILURE"
+  },
+  {
+    0x3B, 0x05,
+    SenseDevTypes047,
+    "PAPER JAM"
+  },
+  {
+    0x3B, 0x06,
+    SenseDevTypes047,
+    "FAILED TO SENSE TOP-OF-FORM"
+  },
+  {
+    0x3B, 0x07,
+    SenseDevTypes047,
+    "FAILED TO SENSE BOTTOM-OF-FORM"
+  },
+  {
+    0x3B, 0x08,
+    SenseDevTypes002,
+    "REPOSITION ERROR"
+  },
+  {
+    0x3B, 0x09,
+    SenseDevTypes042,
+    "READ PAST END OF MEDIUM"
+  },
+  {
+    0x3B, 0x0A,
+    SenseDevTypes042,
+    "READ PAST BEGINNING OF MEDIUM"
+  },
+  {
+    0x3B, 0x0B,
+    SenseDevTypes042,
+    "POSITION PAST END OF MEDIUM"
+  },
+  {
+    0x3B, 0x0C,
+    SenseDevTypes003,
+    "POSITION PAST BEGINNING OF MEDIUM"
+  },
+  {
+    0x3B, 0x0D,
+    SenseDevTypes034,
+    "MEDIUM DESTINATION ELEMENT FULL"
+  },
+  {
+    0x3B, 0x0E,
+    SenseDevTypes034,
+    "MEDIUM SOURCE ELEMENT EMPTY"
+  },
+  {
+    0x3B, 0x0F,
+    SenseDevTypes005,
+    "END OF MEDIUM REACHED"
+  },
+  {
+    0x3B, 0x11,
+    SenseDevTypes034,
+    "MEDIUM MAGAZINE NOT ACCESSIBLE"
+  },
+  {
+    0x3B, 0x12,
+    SenseDevTypes034,
+    "MEDIUM MAGAZINE REMOVED"
+  },
+  {
+    0x3B, 0x13,
+    SenseDevTypes034,
+    "MEDIUM MAGAZINE INSERTED"
+  },
+  {
+    0x3B, 0x14,
+    SenseDevTypes034,
+    "MEDIUM MAGAZINE LOCKED"
+  },
+  {
+    0x3B, 0x15,
+    SenseDevTypes034,
+    "MEDIUM MAGAZINE UNLOCKED"
+  },
+  {
+    0x3B, 0x16,
+    SenseDevTypes005,
+    "MECHANICAL POSITIONING OR CHANGER ERROR"
+  },
+  {
+    0x3D, 0x00,
+    SenseDevTypes036,
+    "INVALID BITS IN IDENTIFY MESSAGE"
+  },
+  {
+    0x3E, 0x00,
+    SenseDevTypes001,
+    "LOGICAL UNIT HAS NOT SELF-CONFIGURED YET"
+  },
+  {
+    0x3E, 0x01,
+    SenseDevTypes001,
+    "LOGICAL UNIT FAILURE"
+  },
+  {
+    0x3E, 0x02,
+    SenseDevTypes001,
+    "TIMEOUT ON LOGICAL UNIT"
+  },
+  {
+    0x3E, 0x03,
+    SenseDevTypes001,
+    "LOGICAL UNIT FAILED SELF-TEST"
+  },
+  {
+    0x3E, 0x04,
+    SenseDevTypes001,
+    "LOGICAL UNIT UNABLE TO UPDATE SELF-TEST LOG"
+  },
+  {
+    0x3F, 0x00,
+    SenseDevTypes001,
+    "TARGET OPERATING CONDITIONS HAVE CHANGED"
+  },
+  {
+    0x3F, 0x01,
+    SenseDevTypes001,
+    "MICROCODE HAS BEEN CHANGED"
+  },
+  {
+    0x3F, 0x02,
+    SenseDevTypes049,
+    "CHANGED OPERATING DEFINITION"
+  },
+  {
+    0x3F, 0x03,
+    SenseDevTypes001,
+    "INQUIRY DATA HAS CHANGED"
+  },
+  {
+    0x3F, 0x04,
+    SenseDevTypes050,
+    "COMPONENT DEVICE ATTACHED"
+  },
+  {
+    0x3F, 0x05,
+    SenseDevTypes050,
+    "DEVICE IDENTIFIER CHANGED"
+  },
+  {
+    0x3F, 0x06,
+    SenseDevTypes051,
+    "REDUNDANCY GROUP CREATED OR MODIFIED"
+  },
+  {
+    0x3F, 0x07,
+    SenseDevTypes051,
+    "REDUNDANCY GROUP DELETED"
+  },
+  {
+    0x3F, 0x08,
+    SenseDevTypes051,
+    "SPARE CREATED OR MODIFIED"
+  },
+  {
+    0x3F, 0x09,
+    SenseDevTypes051,
+    "SPARE DELETED"
+  },
+  {
+    0x3F, 0x0A,
+    SenseDevTypes050,
+    "VOLUME SET CREATED OR MODIFIED"
+  },
+  {
+    0x3F, 0x0B,
+    SenseDevTypes050,
+    "VOLUME SET DELETED"
+  },
+  {
+    0x3F, 0x0C,
+    SenseDevTypes050,
+    "VOLUME SET DEASSIGNED"
+  },
+  {
+    0x3F, 0x0D,
+    SenseDevTypes050,
+    "VOLUME SET REASSIGNED"
+  },
+  {
+    0x3F, 0x0E,
+    SenseDevTypes041,
+    "REPORTED LUNS DATA HAS CHANGED"
+  },
+  {
+    0x3F, 0x0F,
+    SenseDevTypes001,
+    "ECHO BUFFER OVERWRITTEN"
+  },
+  {
+    0x3F, 0x10,
+    SenseDevTypes039,
+    "MEDIUM LOADABLE"
+  },
+  {
+    0x3F, 0x11,
+    SenseDevTypes039,
+    "MEDIUM AUXILIARY MEMORY ACCESSIBLE"
+  },
+  {
+    0x40, 0x00,
+    SenseDevTypes035,
+    "RAM FAILURE (SHOULD USE 40 NN)"
+  },
+  {
+    0x40, 0xFF,
+    SenseDevTypes001,
+    "DIAGNOSTIC FAILURE ON COMPONENT NN (80H-FFH)"
+  },
+  {
+    0x41, 0x00,
+    SenseDevTypes035,
+    "DATA PATH FAILURE (SHOULD USE 40 NN)"
+  },
+  {
+    0x42, 0x00,
+    SenseDevTypes035,
+    "POWER-ON OR SELF-TEST FAILURE (SHOULD USE 40 NN)"
+  },
+  {
+    0x43, 0x00,
+    SenseDevTypes001,
+    "MESSAGE ERROR"
+  },
+  {
+    0x44, 0x00,
+    SenseDevTypes001,
+    "INTERNAL TARGET FAILURE"
+  },
+  {
+    0x45, 0x00,
+    SenseDevTypes001,
+    "SELECT OR RESELECT FAILURE"
+  },
+  {
+    0x46, 0x00,
+    SenseDevTypes049,
+    "UNSUCCESSFUL SOFT RESET"
+  },
+  {
+    0x47, 0x00,
+    SenseDevTypes001,
+    "SCSI PARITY ERROR"
+  },
+  {
+    0x47, 0x01,
+    SenseDevTypes001,
+    "DATA PHASE CRC ERROR DETECTED"
+  },
+  {
+    0x47, 0x02,
+    SenseDevTypes001,
+    "SCSI PARITY ERROR DETECTED DURING ST DATA PHASE"
+  },
+  {
+    0x47, 0x03,
+    SenseDevTypes001,
+    "INFORMATION UNIT CRC ERROR DETECTED"
+  },
+  {
+    0x47, 0x04,
+    SenseDevTypes001,
+    "ASYNCHRONOUS INFORMATION PROTECTION ERROR DETECTED"
+  },
+  {
+    0x48, 0x00,
+    SenseDevTypes001,
+    "INITIATOR DETECTED ERROR MESSAGE RECEIVED"
+  },
+  {
+    0x49, 0x00,
+    SenseDevTypes001,
+    "INVALID MESSAGE ERROR"
+  },
+  {
+    0x4A, 0x00,
+    SenseDevTypes001,
+    "COMMAND PHASE ERROR"
+  },
+  {
+    0x4B, 0x00,
+    SenseDevTypes001,
+    "DATA PHASE ERROR"
+  },
+  {
+    0x4C, 0x00,
+    SenseDevTypes001,
+    "LOGICAL UNIT FAILED SELF-CONFIGURATION"
+  },
+  {
+    0x4D, 0xFF,
+    SenseDevTypes001,
+    "TAGGED OVERLAPPED COMMANDS (NN = QUEUE TAG)"
+  },
+  {
+    0x4E, 0x00,
+    SenseDevTypes001,
+    "OVERLAPPED COMMANDS ATTEMPTED"
+  },
+  {
+    0x50, 0x00,
+    SenseDevTypes002,
+    "WRITE APPEND ERROR"
+  },
+  {
+    0x50, 0x01,
+    SenseDevTypes002,
+    "WRITE APPEND POSITION ERROR"
+  },
+  {
+    0x50, 0x02,
+    SenseDevTypes002,
+    "POSITION ERROR RELATED TO TIMING"
+  },
+  {
+    0x51, 0x00,
+    SenseDevTypes052,
+    "ERASE FAILURE"
+  },
+  {
+    0x52, 0x00,
+    SenseDevTypes002,
+    "CARTRIDGE FAULT"
+  },
+  {
+    0x53, 0x00,
+    SenseDevTypes014,
+    "MEDIA LOAD OR EJECT FAILED"
+  },
+  {
+    0x53, 0x01,
+    SenseDevTypes002,
+    "UNLOAD TAPE FAILURE"
+  },
+  {
+    0x53, 0x02,
+    SenseDevTypes034,
+    "MEDIUM REMOVAL PREVENTED"
+  },
+  {
+    0x54, 0x00,
+    SenseDevTypes053,
+    "SCSI TO HOST SYSTEM INTERFACE FAILURE"
+  },
+  {
+    0x55, 0x00,
+    SenseDevTypes053,
+    "SYSTEM RESOURCE FAILURE"
+  },
+  {
+    0x55, 0x01,
+    SenseDevTypes033,
+    "SYSTEM BUFFER FULL"
+  },
+  {
+    0x55, 0x02,
+    SenseDevTypes054,
+    "INSUFFICIENT RESERVATION RESOURCES"
+  },
+  {
+    0x55, 0x03,
+    SenseDevTypes041,
+    "INSUFFICIENT RESOURCES"
+  },
+  {
+    0x55, 0x04,
+    SenseDevTypes055,
+    "INSUFFICIENT REGISTRATION RESOURCES"
+  },
+  {
+    0x55, 0x05,
+    SenseDevTypes012,
+    "access controls code 4 (99-314) [proposed]"
+  },
+  {
+    0x55, 0x06,
+    SenseDevTypes012,
+    "auxiliary memory code 1 (99-148) [proposed]"
+  },
+  {
+    0x57, 0x00,
+    SenseDevTypes005,
+    "UNABLE TO RECOVER TABLE-OF-CONTENTS"
+  },
+  {
+    0x58, 0x00,
+    SenseDevTypes056,
+    "GENERATION DOES NOT EXIST"
+  },
+  {
+    0x59, 0x00,
+    SenseDevTypes056,
+    "UPDATED BLOCK READ"
+  },
+  {
+    0x5A, 0x00,
+    SenseDevTypes057,
+    "OPERATOR REQUEST OR STATE CHANGE INPUT"
+  },
+  {
+    0x5A, 0x01,
+    SenseDevTypes034,
+    "OPERATOR MEDIUM REMOVAL REQUEST"
+  },
+  {
+    0x5A, 0x02,
+    SenseDevTypes058,
+    "OPERATOR SELECTED WRITE PROTECT"
+  },
+  {
+    0x5A, 0x03,
+    SenseDevTypes058,
+    "OPERATOR SELECTED WRITE PERMIT"
+  },
+  {
+    0x5B, 0x00,
+    SenseDevTypes059,
+    "LOG EXCEPTION"
+  },
+  {
+    0x5B, 0x01,
+    SenseDevTypes059,
+    "THRESHOLD CONDITION MET"
+  },
+  {
+    0x5B, 0x02,
+    SenseDevTypes059,
+    "LOG COUNTER AT MAXIMUM"
+  },
+  {
+    0x5B, 0x03,
+    SenseDevTypes059,
+    "LOG LIST CODES EXHAUSTED"
+  },
+  {
+    0x5C, 0x00,
+    SenseDevTypes060,
+    "RPL STATUS CHANGE"
+  },
+  {
+    0x5C, 0x01,
+    SenseDevTypes060,
+    "SPINDLES SYNCHRONIZED"
+  },
+  {
+    0x5C, 0x02,
+    SenseDevTypes060,
+    "SPINDLES NOT SYNCHRONIZED"
+  },
+  {
+    0x5D, 0x00,
+    SenseDevTypes001,
+    "FAILURE PREDICTION THRESHOLD EXCEEDED"
+  },
+  {
+    0x5D, 0x01,
+    SenseDevTypes061,
+    "MEDIA FAILURE PREDICTION THRESHOLD EXCEEDED"
+  },
+  {
+    0x5D, 0x02,
+    SenseDevTypes005,
+    "LOGICAL UNIT FAILURE PREDICTION THRESHOLD EXCEEDED"
+  },
+  {
+    0x5D, 0x10,
+    SenseDevTypes062,
+    "HARDWARE IMPENDING FAILURE GENERAL HARD DRIVE FAILURE"
+  },
+  {
+    0x5D, 0x11,
+    SenseDevTypes062,
+    "HARDWARE IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH"
+  },
+  {
+    0x5D, 0x12,
+    SenseDevTypes062,
+    "HARDWARE IMPENDING FAILURE DATA ERROR RATE TOO HIGH"
+  },
+  {
+    0x5D, 0x13,
+    SenseDevTypes062,
+    "HARDWARE IMPENDING FAILURE SEEK ERROR RATE TOO HIGH"
+  },
+  {
+    0x5D, 0x14,
+    SenseDevTypes062,
+    "HARDWARE IMPENDING FAILURE TOO MANY BLOCK REASSIGNS"
+  },
+  {
+    0x5D, 0x15,
+    SenseDevTypes062,
+    "HARDWARE IMPENDING FAILURE ACCESS TIMES TOO HIGH"
+  },
+  {
+    0x5D, 0x16,
+    SenseDevTypes062,
+    "HARDWARE IMPENDING FAILURE START UNIT TIMES TOO HIGH"
+  },
+  {
+    0x5D, 0x17,
+    SenseDevTypes062,
+    "HARDWARE IMPENDING FAILURE CHANNEL PARAMETRICS"
+  },
+  {
+    0x5D, 0x18,
+    SenseDevTypes062,
+    "HARDWARE IMPENDING FAILURE CONTROLLER DETECTED"
+  },
+  {
+    0x5D, 0x19,
+    SenseDevTypes062,
+    "HARDWARE IMPENDING FAILURE THROUGHPUT PERFORMANCE"
+  },
+  {
+    0x5D, 0x1A,
+    SenseDevTypes062,
+    "HARDWARE IMPENDING FAILURE SEEK TIME PERFORMANCE"
+  },
+  {
+    0x5D, 0x1B,
+    SenseDevTypes062,
+    "HARDWARE IMPENDING FAILURE SPIN-UP RETRY COUNT"
+  },
+  {
+    0x5D, 0x1C,
+    SenseDevTypes062,
+    "HARDWARE IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT"
+  },
+  {
+    0x5D, 0x20,
+    SenseDevTypes062,
+    "CONTROLLER IMPENDING FAILURE GENERAL HARD DRIVE FAILURE"
+  },
+  {
+    0x5D, 0x21,
+    SenseDevTypes062,
+    "CONTROLLER IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH"
+  },
+  {
+    0x5D, 0x22,
+    SenseDevTypes062,
+    "CONTROLLER IMPENDING FAILURE DATA ERROR RATE TOO HIGH"
+  },
+  {
+    0x5D, 0x23,
+    SenseDevTypes062,
+    "CONTROLLER IMPENDING FAILURE SEEK ERROR RATE TOO HIGH"
+  },
+  {
+    0x5D, 0x24,
+    SenseDevTypes062,
+    "CONTROLLER IMPENDING FAILURE TOO MANY BLOCK REASSIGNS"
+  },
+  {
+    0x5D, 0x25,
+    SenseDevTypes062,
+    "CONTROLLER IMPENDING FAILURE ACCESS TIMES TOO HIGH"
+  },
+  {
+    0x5D, 0x26,
+    SenseDevTypes062,
+    "CONTROLLER IMPENDING FAILURE START UNIT TIMES TOO HIGH"
+  },
+  {
+    0x5D, 0x27,
+    SenseDevTypes062,
+    "CONTROLLER IMPENDING FAILURE CHANNEL PARAMETRICS"
+  },
+  {
+    0x5D, 0x28,
+    SenseDevTypes062,
+    "CONTROLLER IMPENDING FAILURE CONTROLLER DETECTED"
+  },
+  {
+    0x5D, 0x29,
+    SenseDevTypes062,
+    "CONTROLLER IMPENDING FAILURE THROUGHPUT PERFORMANCE"
+  },
+  {
+    0x5D, 0x2A,
+    SenseDevTypes062,
+    "CONTROLLER IMPENDING FAILURE SEEK TIME PERFORMANCE"
+  },
+  {
+    0x5D, 0x2B,
+    SenseDevTypes062,
+    "CONTROLLER IMPENDING FAILURE SPIN-UP RETRY COUNT"
+  },
+  {
+    0x5D, 0x2C,
+    SenseDevTypes062,
+    "CONTROLLER IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT"
+  },
+  {
+    0x5D, 0x30,
+    SenseDevTypes062,
+    "DATA CHANNEL IMPENDING FAILURE GENERAL HARD DRIVE FAILURE"
+  },
+  {
+    0x5D, 0x31,
+    SenseDevTypes062,
+    "DATA CHANNEL IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH"
+  },
+  {
+    0x5D, 0x32,
+    SenseDevTypes062,
+    "DATA CHANNEL IMPENDING FAILURE DATA ERROR RATE TOO HIGH"
+  },
+  {
+    0x5D, 0x33,
+    SenseDevTypes062,
+    "DATA CHANNEL IMPENDING FAILURE SEEK ERROR RATE TOO HIGH"
+  },
+  {
+    0x5D, 0x34,
+    SenseDevTypes062,
+    "DATA CHANNEL IMPENDING FAILURE TOO MANY BLOCK REASSIGNS"
+  },
+  {
+    0x5D, 0x35,
+    SenseDevTypes062,
+    "DATA CHANNEL IMPENDING FAILURE ACCESS TIMES TOO HIGH"
+  },
+  {
+    0x5D, 0x36,
+    SenseDevTypes062,
+    "DATA CHANNEL IMPENDING FAILURE START UNIT TIMES TOO HIGH"
+  },
+  {
+    0x5D, 0x37,
+    SenseDevTypes062,
+    "DATA CHANNEL IMPENDING FAILURE CHANNEL PARAMETRICS"
+  },
+  {
+    0x5D, 0x38,
+    SenseDevTypes062,
+    "DATA CHANNEL IMPENDING FAILURE CONTROLLER DETECTED"
+  },
+  {
+    0x5D, 0x39,
+    SenseDevTypes062,
+    "DATA CHANNEL IMPENDING FAILURE THROUGHPUT PERFORMANCE"
+  },
+  {
+    0x5D, 0x3A,
+    SenseDevTypes062,
+    "DATA CHANNEL IMPENDING FAILURE SEEK TIME PERFORMANCE"
+  },
+  {
+    0x5D, 0x3B,
+    SenseDevTypes062,
+    "DATA CHANNEL IMPENDING FAILURE SPIN-UP RETRY COUNT"
+  },
+  {
+    0x5D, 0x3C,
+    SenseDevTypes062,
+    "DATA CHANNEL IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT"
+  },
+  {
+    0x5D, 0x40,
+    SenseDevTypes062,
+    "SERVO IMPENDING FAILURE GENERAL HARD DRIVE FAILURE"
+  },
+  {
+    0x5D, 0x41,
+    SenseDevTypes062,
+    "SERVO IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH"
+  },
+  {
+    0x5D, 0x42,
+    SenseDevTypes062,
+    "SERVO IMPENDING FAILURE DATA ERROR RATE TOO HIGH"
+  },
+  {
+    0x5D, 0x43,
+    SenseDevTypes062,
+    "SERVO IMPENDING FAILURE SEEK ERROR RATE TOO HIGH"
+  },
+  {
+    0x5D, 0x44,
+    SenseDevTypes062,
+    "SERVO IMPENDING FAILURE TOO MANY BLOCK REASSIGNS"
+  },
+  {
+    0x5D, 0x45,
+    SenseDevTypes062,
+    "SERVO IMPENDING FAILURE ACCESS TIMES TOO HIGH"
+  },
+  {
+    0x5D, 0x46,
+    SenseDevTypes062,
+    "SERVO IMPENDING FAILURE START UNIT TIMES TOO HIGH"
+  },
+  {
+    0x5D, 0x47,
+    SenseDevTypes062,
+    "SERVO IMPENDING FAILURE CHANNEL PARAMETRICS"
+  },
+  {
+    0x5D, 0x48,
+    SenseDevTypes062,
+    "SERVO IMPENDING FAILURE CONTROLLER DETECTED"
+  },
+  {
+    0x5D, 0x49,
+    SenseDevTypes062,
+    "SERVO IMPENDING FAILURE THROUGHPUT PERFORMANCE"
+  },
+  {
+    0x5D, 0x4A,
+    SenseDevTypes062,
+    "SERVO IMPENDING FAILURE SEEK TIME PERFORMANCE"
+  },
+  {
+    0x5D, 0x4B,
+    SenseDevTypes062,
+    "SERVO IMPENDING FAILURE SPIN-UP RETRY COUNT"
+  },
+  {
+    0x5D, 0x4C,
+    SenseDevTypes062,
+    "SERVO IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT"
+  },
+  {
+    0x5D, 0x50,
+    SenseDevTypes062,
+    "SPINDLE IMPENDING FAILURE GENERAL HARD DRIVE FAILURE"
+  },
+  {
+    0x5D, 0x51,
+    SenseDevTypes062,
+    "SPINDLE IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH"
+  },
+  {
+    0x5D, 0x52,
+    SenseDevTypes062,
+    "SPINDLE IMPENDING FAILURE DATA ERROR RATE TOO HIGH"
+  },
+  {
+    0x5D, 0x53,
+    SenseDevTypes062,
+    "SPINDLE IMPENDING FAILURE SEEK ERROR RATE TOO HIGH"
+  },
+  {
+    0x5D, 0x54,
+    SenseDevTypes062,
+    "SPINDLE IMPENDING FAILURE TOO MANY BLOCK REASSIGNS"
+  },
+  {
+    0x5D, 0x55,
+    SenseDevTypes062,
+    "SPINDLE IMPENDING FAILURE ACCESS TIMES TOO HIGH"
+  },
+  {
+    0x5D, 0x56,
+    SenseDevTypes062,
+    "SPINDLE IMPENDING FAILURE START UNIT TIMES TOO HIGH"
+  },
+  {
+    0x5D, 0x57,
+    SenseDevTypes062,
+    "SPINDLE IMPENDING FAILURE CHANNEL PARAMETRICS"
+  },
+  {
+    0x5D, 0x58,
+    SenseDevTypes062,
+    "SPINDLE IMPENDING FAILURE CONTROLLER DETECTED"
+  },
+  {
+    0x5D, 0x59,
+    SenseDevTypes062,
+    "SPINDLE IMPENDING FAILURE THROUGHPUT PERFORMANCE"
+  },
+  {
+    0x5D, 0x5A,
+    SenseDevTypes062,
+    "SPINDLE IMPENDING FAILURE SEEK TIME PERFORMANCE"
+  },
+  {
+    0x5D, 0x5B,
+    SenseDevTypes062,
+    "SPINDLE IMPENDING FAILURE SPIN-UP RETRY COUNT"
+  },
+  {
+    0x5D, 0x5C,
+    SenseDevTypes062,
+    "SPINDLE IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT"
+  },
+  {
+    0x5D, 0x60,
+    SenseDevTypes062,
+    "FIRMWARE IMPENDING FAILURE GENERAL HARD DRIVE FAILURE"
+  },
+  {
+    0x5D, 0x61,
+    SenseDevTypes062,
+    "FIRMWARE IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH"
+  },
+  {
+    0x5D, 0x62,
+    SenseDevTypes062,
+    "FIRMWARE IMPENDING FAILURE DATA ERROR RATE TOO HIGH"
+  },
+  {
+    0x5D, 0x63,
+    SenseDevTypes062,
+    "FIRMWARE IMPENDING FAILURE SEEK ERROR RATE TOO HIGH"
+  },
+  {
+    0x5D, 0x64,
+    SenseDevTypes062,
+    "FIRMWARE IMPENDING FAILURE TOO MANY BLOCK REASSIGNS"
+  },
+  {
+    0x5D, 0x65,
+    SenseDevTypes062,
+    "FIRMWARE IMPENDING FAILURE ACCESS TIMES TOO HIGH"
+  },
+  {
+    0x5D, 0x66,
+    SenseDevTypes062,
+    "FIRMWARE IMPENDING FAILURE START UNIT TIMES TOO HIGH"
+  },
+  {
+    0x5D, 0x67,
+    SenseDevTypes062,
+    "FIRMWARE IMPENDING FAILURE CHANNEL PARAMETRICS"
+  },
+  {
+    0x5D, 0x68,
+    SenseDevTypes062,
+    "FIRMWARE IMPENDING FAILURE CONTROLLER DETECTED"
+  },
+  {
+    0x5D, 0x69,
+    SenseDevTypes062,
+    "FIRMWARE IMPENDING FAILURE THROUGHPUT PERFORMANCE"
+  },
+  {
+    0x5D, 0x6A,
+    SenseDevTypes062,
+    "FIRMWARE IMPENDING FAILURE SEEK TIME PERFORMANCE"
+  },
+  {
+    0x5D, 0x6B,
+    SenseDevTypes062,
+    "FIRMWARE IMPENDING FAILURE SPIN-UP RETRY COUNT"
+  },
+  {
+    0x5D, 0x6C,
+    SenseDevTypes062,
+    "FIRMWARE IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT"
+  },
+  {
+    0x5D, 0xFF,
+    SenseDevTypes001,
+    "FAILURE PREDICTION THRESHOLD EXCEEDED (FALSE)"
+  },
+  {
+    0x5E, 0x00,
+    SenseDevTypes044,
+    "LOW POWER CONDITION ON"
+  },
+  {
+    0x5E, 0x01,
+    SenseDevTypes044,
+    "IDLE CONDITION ACTIVATED BY TIMER"
+  },
+  {
+    0x5E, 0x02,
+    SenseDevTypes044,
+    "STANDBY CONDITION ACTIVATED BY TIMER"
+  },
+  {
+    0x5E, 0x03,
+    SenseDevTypes044,
+    "IDLE CONDITION ACTIVATED BY COMMAND"
+  },
+  {
+    0x5E, 0x04,
+    SenseDevTypes044,
+    "STANDBY CONDITION ACTIVATED BY COMMAND"
+  },
+  {
+    0x5E, 0x41,
+    SenseDevTypes043,
+    "POWER STATE CHANGE TO ACTIVE"
+  },
+  {
+    0x5E, 0x42,
+    SenseDevTypes043,
+    "POWER STATE CHANGE TO IDLE"
+  },
+  {
+    0x5E, 0x43,
+    SenseDevTypes043,
+    "POWER STATE CHANGE TO STANDBY"
+  },
+  {
+    0x5E, 0x45,
+    SenseDevTypes043,
+    "POWER STATE CHANGE TO SLEEP"
+  },
+  {
+    0x5E, 0x47,
+    SenseDevTypes063,
+    "POWER STATE CHANGE TO DEVICE CONTROL"
+  },
+  {
+    0x60, 0x00,
+    SenseDevTypes042,
+    "LAMP FAILURE"
+  },
+  {
+    0x61, 0x00,
+    SenseDevTypes042,
+    "VIDEO ACQUISITION ERROR"
+  },
+  {
+    0x61, 0x01,
+    SenseDevTypes042,
+    "UNABLE TO ACQUIRE VIDEO"
+  },
+  {
+    0x61, 0x02,
+    SenseDevTypes042,
+    "OUT OF FOCUS"
+  },
+  {
+    0x62, 0x00,
+    SenseDevTypes042,
+    "SCAN HEAD POSITIONING ERROR"
+  },
+  {
+    0x63, 0x00,
+    SenseDevTypes005,
+    "END OF USER AREA ENCOUNTERED ON THIS TRACK"
+  },
+  {
+    0x63, 0x01,
+    SenseDevTypes005,
+    "PACKET DOES NOT FIT IN AVAILABLE SPACE"
+  },
+  {
+    0x64, 0x00,
+    SenseDevTypes005,
+    "ILLEGAL MODE FOR THIS TRACK"
+  },
+  {
+    0x64, 0x01,
+    SenseDevTypes005,
+    "INVALID PACKET SIZE"
+  },
+  {
+    0x65, 0x00,
+    SenseDevTypes001,
+    "VOLTAGE FAULT"
+  },
+  {
+    0x66, 0x00,
+    SenseDevTypes042,
+    "AUTOMATIC DOCUMENT FEEDER COVER UP"
+  },
+  {
+    0x66, 0x01,
+    SenseDevTypes042,
+    "AUTOMATIC DOCUMENT FEEDER LIFT UP"
+  },
+  {
+    0x66, 0x02,
+    SenseDevTypes042,
+    "DOCUMENT JAM IN AUTOMATIC DOCUMENT FEEDER"
+  },
+  {
+    0x66, 0x03,
+    SenseDevTypes042,
+    "DOCUMENT MISS FEED AUTOMATIC IN DOCUMENT FEEDER"
+  },
+  {
+    0x67, 0x00,
+    SenseDevTypes064,
+    "CONFIGURATION FAILURE"
+  },
+  {
+    0x67, 0x01,
+    SenseDevTypes064,
+    "CONFIGURATION OF INCAPABLE LOGICAL UNITS FAILED"
+  },
+  {
+    0x67, 0x02,
+    SenseDevTypes064,
+    "ADD LOGICAL UNIT FAILED"
+  },
+  {
+    0x67, 0x03,
+    SenseDevTypes064,
+    "MODIFICATION OF LOGICAL UNIT FAILED"
+  },
+  {
+    0x67, 0x04,
+    SenseDevTypes064,
+    "EXCHANGE OF LOGICAL UNIT FAILED"
+  },
+  {
+    0x67, 0x05,
+    SenseDevTypes064,
+    "REMOVE OF LOGICAL UNIT FAILED"
+  },
+  {
+    0x67, 0x06,
+    SenseDevTypes064,
+    "ATTACHMENT OF LOGICAL UNIT FAILED"
+  },
+  {
+    0x67, 0x07,
+    SenseDevTypes064,
+    "CREATION OF LOGICAL UNIT FAILED"
+  },
+  {
+    0x67, 0x08,
+    SenseDevTypes064,
+    "ASSIGN FAILURE OCCURRED"
+  },
+  {
+    0x67, 0x09,
+    SenseDevTypes064,
+    "MULTIPLY ASSIGNED LOGICAL UNIT"
+  },
+  {
+    0x68, 0x00,
+    SenseDevTypes064,
+    "LOGICAL UNIT NOT CONFIGURED"
+  },
+  {
+    0x69, 0x00,
+    SenseDevTypes064,
+    "DATA LOSS ON LOGICAL UNIT"
+  },
+  {
+    0x69, 0x01,
+    SenseDevTypes064,
+    "MULTIPLE LOGICAL UNIT FAILURES"
+  },
+  {
+    0x69, 0x02,
+    SenseDevTypes064,
+    "PARITY/DATA MISMATCH"
+  },
+  {
+    0x6A, 0x00,
+    SenseDevTypes064,
+    "INFORMATIONAL, REFER TO LOG"
+  },
+  {
+    0x6B, 0x00,
+    SenseDevTypes064,
+    "STATE CHANGE HAS OCCURRED"
+  },
+  {
+    0x6B, 0x01,
+    SenseDevTypes064,
+    "REDUNDANCY LEVEL GOT BETTER"
+  },
+  {
+    0x6B, 0x02,
+    SenseDevTypes064,
+    "REDUNDANCY LEVEL GOT WORSE"
+  },
+  {
+    0x6C, 0x00,
+    SenseDevTypes064,
+    "REBUILD FAILURE OCCURRED"
+  },
+  {
+    0x6D, 0x00,
+    SenseDevTypes064,
+    "RECALCULATE FAILURE OCCURRED"
+  },
+  {
+    0x6E, 0x00,
+    SenseDevTypes064,
+    "COMMAND TO LOGICAL UNIT FAILED"
+  },
+  {
+    0x6F, 0x00,
+    SenseDevTypes005,
+    "COPY PROTECTION KEY EXCHANGE FAILURE - AUTHENTICATION FAILURE"
+  },
+  {
+    0x6F, 0x01,
+    SenseDevTypes005,
+    "COPY PROTECTION KEY EXCHANGE FAILURE - KEY NOT PRESENT"
+  },
+  {
+    0x6F, 0x02,
+    SenseDevTypes005,
+    "COPY PROTECTION KEY EXCHANGE FAILURE - KEY NOT ESTABLISHED"
+  },
+  {
+    0x6F, 0x03,
+    SenseDevTypes005,
+    "READ OF SCRAMBLED SECTOR WITHOUT AUTHENTICATION"
+  },
+  {
+    0x6F, 0x04,
+    SenseDevTypes005,
+    "MEDIA REGION CODE IS MISMATCHED TO LOGICAL UNIT REGION"
+  },
+  {
+    0x6F, 0x05,
+    SenseDevTypes005,
+    "DRIVE REGION MUST BE PERMANENT/REGION RESET COUNT ERROR"
+  },
+  {
+    0x70, 0xFF,
+    SenseDevTypes002,
+    "DECOMPRESSION EXCEPTION SHORT ALGORITHM ID OF NN"
+  },
+  {
+    0x71, 0x00,
+    SenseDevTypes002,
+    "DECOMPRESSION EXCEPTION LONG ALGORITHM ID"
+  },
+  {
+    0x72, 0x00,
+    SenseDevTypes005,
+    "SESSION FIXATION ERROR"
+  },
+  {
+    0x72, 0x01,
+    SenseDevTypes005,
+    "SESSION FIXATION ERROR WRITING LEAD-IN"
+  },
+  {
+    0x72, 0x02,
+    SenseDevTypes005,
+    "SESSION FIXATION ERROR WRITING LEAD-OUT"
+  },
+  {
+    0x72, 0x03,
+    SenseDevTypes005,
+    "SESSION FIXATION ERROR - INCOMPLETE TRACK IN SESSION"
+  },
+  {
+    0x72, 0x04,
+    SenseDevTypes005,
+    "EMPTY OR PARTIALLY WRITTEN RESERVED TRACK"
+  },
+  {
+    0x72, 0x05,
+    SenseDevTypes005,
+    "NO MORE TRACK RESERVATIONS ALLOWED"
+  },
+  {
+    0x73, 0x00,
+    SenseDevTypes005,
+    "CD CONTROL ERROR"
+  },
+  {
+    0x73, 0x01,
+    SenseDevTypes005,
+    "POWER CALIBRATION AREA ALMOST FULL"
+  },
+  {
+    0x73, 0x02,
+    SenseDevTypes005,
+    "POWER CALIBRATION AREA IS FULL"
+  },
+  {
+    0x73, 0x03,
+    SenseDevTypes005,
+    "POWER CALIBRATION AREA ERROR"
+  },
+  {
+    0x73, 0x04,
+    SenseDevTypes005,
+    "PROGRAM MEMORY AREA UPDATE FAILURE"
+  },
+  {
+    0x73, 0x05,
+    SenseDevTypes005,
+    "PROGRAM MEMORY AREA IS FULL"
+  },
+  {
+    0x73, 0x06,
+    SenseDevTypes005,
+    "RMA/PMA IS FULL"
+  },
+};
+
+static int ASCQ_TableSize = 463;
+
+
+#endif
diff --git a/drivers/message/fusion/ascq_tbl.sh b/drivers/message/fusion/ascq_tbl.sh
new file mode 100644 (file)
index 0000000..76ba954
--- /dev/null
@@ -0,0 +1,109 @@
+#!/bin/sh
+#
+#  ascq_tbl.sh - Translate SCSI t10.org's "asc-num.txt" file of
+#                SCSI Additional Sense Code & Qualifiers (ASC/ASCQ's)
+#                into something useful in C, creating "ascq_tbl.c" file.
+#
+#*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*#
+
+PREF_INFILE="t10.org/asc-num.txt"      # From SCSI t10.org
+PREF_OUTFILE="ascq_tbl.c"
+
+#*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*#
+
+xlate_ascq() {
+       cat | awk '
+       BEGIN {
+               DQ = "\042";
+               OUTFILE = "'"${PREF_OUTFILE}"'";
+               TRUE = 1;
+               FALSE = 0;
+               #debug = TRUE;
+
+               #  read and discard all lines up to and including the one that begins
+               #  with the "magic token" of "-------  --------------  ---"...
+               headers_gone = FALSE;
+               while (!headers_gone) {
+                       if (getline <= 0)
+                               exit 1;
+                       header_line[++hdrs] = $0;
+                       if (debug)
+                               printf("header_line[%d] = :%s:\n", ++hdrs, $0);
+                       if ($0 ~ /^-------  --------------  ---/) {
+                               headers_gone = TRUE;
+                       }
+               }
+               outcount = 0;
+       }
+
+       (NF > 1) {
+               ++outcount;
+               if (debug)
+                       printf( "DBG: %s\n", $0 );
+               ASC[outcount] = substr($0,1,2);
+               ASCQ[outcount] = substr($0,5,2);
+               devtypes = substr($0,10,14);
+               gsub(/ /, ".", devtypes);
+               DESCRIP[outcount] = substr($0,26);
+
+               if (!(devtypes in DevTypesVoodoo)) {
+                       DevTypesVoodoo[devtypes] = ++voodoo;
+                       DevTypesIdx[voodoo] = devtypes;
+               }
+               DEVTYPES[outcount] = DevTypesVoodoo[devtypes];
+
+               #  Handle 0xNN exception stuff...
+               if (ASCQ[outcount] == "NN" || ASCQ[outcount] == "nn")
+                       ASCQ[outcount] = "FF";
+       }
+
+       END {
+               printf("#ifndef SCSI_ASCQ_TBL_C_INCLUDED\n") > OUTFILE;
+               printf("#define SCSI_ASCQ_TBL_C_INCLUDED\n") >> OUTFILE;
+
+               printf("\n/* AuToMaGiCaLlY generated from: %s'"${FIN}"'%s\n", DQ, DQ) >> OUTFILE;
+               printf(" *******************************************************************************\n") >> OUTFILE;
+               for (i=1; i<=hdrs; i++) {
+                       printf(" * %s\n", header_line[i]) >> OUTFILE;
+               }
+               printf(" */\n") >> OUTFILE;
+
+               printf("\n") >> OUTFILE;
+               for (i=1; i<=voodoo; i++) {
+                       printf("static char SenseDevTypes%03d[] = %s%s%s;\n", i, DQ, DevTypesIdx[i], DQ) >> OUTFILE;
+               }
+
+               printf("\nstatic ASCQ_Table_t ASCQ_Table[] = {\n") >> OUTFILE;
+               for (i=1; i<=outcount; i++) {
+                       printf("  {\n") >> OUTFILE; 
+                       printf("    0x%s, 0x%s,\n", ASC[i], ASCQ[i]) >> OUTFILE;
+                       printf("    SenseDevTypes%03d,\n", DEVTYPES[i]) >> OUTFILE;
+                       printf("    %s%s%s\n", DQ, DESCRIP[i], DQ) >> OUTFILE;
+                       printf("  },\n") >> OUTFILE;
+               }
+               printf( "};\n\n" ) >> OUTFILE;
+
+               printf( "static int ASCQ_TableSize = %d;\n\n", outcount ) >> OUTFILE;
+               printf( "Total of %d ASC/ASCQ records generated\n", outcount );
+               printf("\n#endif\n") >> OUTFILE;
+               close(OUTFILE);
+       }'
+       return
+}
+
+#*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*#
+
+# main()
+if [ $# -lt 1 ]; then
+       echo "INFO: No input filename supplied - using: $PREF_INFILE" >&2
+       FIN=$PREF_INFILE
+else
+       FIN="$1"
+       if [ "$FIN" != "$PREF_INFILE" ]; then
+               echo "INFO: Ok, I'll try chewing on '$FIN' for SCSI ASC/ASCQ combos..." >&2
+       fi
+       shift
+fi
+
+cat $FIN | xlate_ascq
+exit 0
diff --git a/drivers/message/fusion/isense.c b/drivers/message/fusion/isense.c
new file mode 100644 (file)
index 0000000..553c8db
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ *  linux/drivers/message/fusion/isense.c
+ *      Little linux driver / shim that interfaces with the Fusion MPT
+ *      Linux base driver to provide english readable strings in SCSI
+ *      Error Report logging output.  This module implements SCSI-3
+ *      Opcode lookup and a sorted table of SCSI-3 ASC/ASCQ strings.
+ *
+ *  Copyright (c) 1991-2001 Steven J. Ralston
+ *  Written By: Steven J. Ralston
+ *  (yes I wrote some of the orig. code back in 1991!)
+ *  (mailto:Steve.Ralston@lsil.com)
+ *
+ *  $Id: isense.c,v 1.28 2001/01/14 23:11:09 sralston Exp $
+ */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; version 2 of the License.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    NO WARRANTY
+    THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+    CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+    LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+    MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+    solely responsible for determining the appropriateness of using and
+    distributing the Program and assumes all risks associated with its
+    exercise of rights under this Agreement, including but not limited to
+    the risks and costs of program errors, damage to or loss of data,
+    programs or equipment, and unavailability or interruption of operations.
+
+    DISCLAIMER OF LIABILITY
+    NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+    DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
+    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+    TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+    USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+    HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/version.h>
+
+/* Hmmm, avoid undefined spinlock_t on lk-2.2.14-5.0 */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
+#include <asm/spinlock.h>
+#endif
+
+#define MODULEAUTHOR "Steven J. Ralston"
+#define COPYRIGHT "Copyright (c) 2000 " MODULEAUTHOR
+#include "mptbase.h"
+
+#include "isense.h"
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *  Private data...
+ */
+
+/*
+ *  YIKES!  I don't usually #include C source files, but..
+ *  The following #include's pulls in our needed ASCQ_Table[] array,
+ *  ASCQ_TableSz integer, and ScsiOpcodeString[] array!
+ */
+#include "ascq_tbl.c"
+#include "scsiops.c"
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+#define my_NAME                "SCSI-3 Opcodes & ASC/ASCQ Strings"
+#define my_VERSION     MPT_LINUX_VERSION_COMMON
+#define MYNAM          "isense"
+
+EXPORT_NO_SYMBOLS;
+MODULE_AUTHOR(MODULEAUTHOR);
+MODULE_DESCRIPTION(my_NAME);
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+int __init isense_init(void)
+{
+       show_mptmod_ver(my_NAME, my_VERSION);
+
+       /*
+        *  Install our handler
+        */
+       if (mpt_register_ascqops_strings(&ASCQ_Table[0], ASCQ_TableSize, ScsiOpcodeString) != 1)
+       {
+               printk(KERN_ERR MYNAM ": ERROR: Can't register with Fusion MPT base driver!\n");
+               return -EBUSY;
+       }
+       printk(KERN_INFO MYNAM ": Registered SCSI-3 Opcodes & ASC/ASCQ Strings\n");
+       return 0;
+}
+
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static void isense_exit(void)
+{
+#ifdef MODULE
+       mpt_deregister_ascqops_strings();
+#endif
+       printk(KERN_INFO MYNAM ": Deregistered SCSI-3 Opcodes & ASC/ASCQ Strings\n");
+}
+
+module_init(isense_init);
+module_exit(isense_exit);
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
diff --git a/drivers/message/fusion/isense.h b/drivers/message/fusion/isense.h
new file mode 100644 (file)
index 0000000..e1ce503
--- /dev/null
@@ -0,0 +1,95 @@
+#ifndef ISENSE_H_INCLUDED
+#define ISENSE_H_INCLUDED
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+#ifdef __KERNEL__
+#include <linux/types.h>               /* needed for u8, etc. */
+#include <linux/string.h>              /* needed for strcat   */
+#include <linux/kernel.h>              /* needed for sprintf  */
+#else
+    #ifndef U_STUFF_DEFINED
+    #define U_STUFF_DEFINED
+    typedef unsigned char u8;
+    typedef unsigned short u16;
+    typedef unsigned int u32;
+    #endif
+#endif
+
+#include "scsi3.h"                     /* needed for all things SCSI */
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *  Defines and typedefs...
+ */
+
+#ifdef __KERNEL__
+#define PrintF(x) printk x
+#else
+#define PrintF(x) printf x
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#define FALSE 0
+#endif
+
+#define RETRY_STATUS  ((int) 1)
+#define PUT_STATUS    ((int) 0)
+
+/*
+ *    A generic structure to hold info about IO request that caused
+ *    a Request Sense to be performed, and the resulting Sense Data.
+ */
+typedef struct IO_Info
+{
+    char *DevIDStr;   /* String of chars which identifies the device.       */
+    u8   *cdbPtr;     /* Pointer (Virtual/Logical addr) to CDB bytes of
+                           IO request that caused ContAllegianceCond.       */
+    u8   *sensePtr;   /* Pointer (Virtual/Logical addr) to Sense Data
+                           returned by Request Sense operation.             */
+    u8   *dataPtr;    /* Pointer (Virtual/Logical addr) to Data buffer
+                           of IO request caused ContAllegianceCondition.    */
+    u8   *inqPtr;     /* Pointer (Virtual/Logical addr) to Inquiry Data for
+                           IO *Device* that caused ContAllegianceCondition. */
+    u8    SCSIStatus; /* SCSI status byte of IO request that caused
+                           Contingent Allegiance Condition.                 */
+    u8    DoDisplay;  /* Shall we display any messages?                     */
+    u16   rsvd_align1;
+    u32   ComplCode;  /* Four-byte OS-dependent completion code.            */
+    u32   NotifyL;    /* Four-byte OS-dependent notification field.         */
+} IO_Info_t;
+
+/*
+ *  SCSI Additional Sense Code and Additional Sense Code Qualifier table.
+ */
+typedef struct ASCQ_Table
+{
+    u8     ASC;
+    u8     ASCQ;
+    char  *DevTypes;
+    char  *Description;
+} ASCQ_Table_t;
+
+#if 0
+/*
+ *  SCSI Opcodes table.
+ */
+typedef struct SCSI_OPS_Table
+{
+    u8     OpCode;
+    char  *DevTypes;
+    char  *ScsiCmndStr;
+} SCSI_OPS_Table_t;
+#endif
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *  Public entry point prototypes
+ */
+
+/* in scsiherr.c, needed by mptscsih.c */
+extern int      mpt_ScsiHost_ErrorReport(IO_Info_t *ioop);
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+#endif
+
diff --git a/drivers/message/fusion/linux_compat.h b/drivers/message/fusion/linux_compat.h
new file mode 100644 (file)
index 0000000..21d6510
--- /dev/null
@@ -0,0 +1,199 @@
+/* drivers/message/fusion/linux_compat.h */
+
+#ifndef FUSION_LINUX_COMPAT_H
+#define FUSION_LINUX_COMPAT_H
+/*{-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+#include <linux/version.h>
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
+#      if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18)
+               typedef unsigned int dma_addr_t;
+#      endif
+#else
+#      if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,42)
+               typedef unsigned int dma_addr_t;
+#      endif
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18)
+/*{-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+/* This block snipped from lk-2.2.18/include/linux/init.h { */
+/*
+ * Used for initialization calls..
+ */
+typedef int (*initcall_t)(void);
+typedef void (*exitcall_t)(void);
+
+#define __init_call    __attribute__ ((unused,__section__ (".initcall.init")))
+#define __exit_call    __attribute__ ((unused,__section__ (".exitcall.exit")))
+
+extern initcall_t __initcall_start, __initcall_end;
+
+#define __initcall(fn)                                                         \
+       static initcall_t __initcall_##fn __init_call = fn
+#define __exitcall(fn)                                                         \
+       static exitcall_t __exitcall_##fn __exit_call = fn
+
+#ifdef MODULE
+/* These macros create a dummy inline: gcc 2.9x does not count alias
+ as usage, hence the `unused function' warning when __init functions
+ are declared static. We use the dummy __*_module_inline functions
+ both to kill the warning and check the type of the init/cleanup
+ function. */
+typedef int (*__init_module_func_t)(void);
+typedef void (*__cleanup_module_func_t)(void);
+#define module_init(x) \
+       int init_module(void) __attribute__((alias(#x))); \
+       extern inline __init_module_func_t __init_module_inline(void) \
+       { return x; }
+#define module_exit(x) \
+       void cleanup_module(void) __attribute__((alias(#x))); \
+       extern inline __cleanup_module_func_t __cleanup_module_inline(void) \
+       { return x; }
+
+#else 
+#define module_init(x) __initcall(x);
+#define module_exit(x) __exitcall(x);
+#endif
+/* } block snipped from lk-2.2.18/include/linux/init.h */
+
+/* Wait queues. */
+#define DECLARE_WAIT_QUEUE_HEAD(name)  \
+       struct wait_queue * (name) = NULL
+#define DECLARE_WAITQUEUE(name, task)  \
+       struct wait_queue (name) = { (task), NULL }
+
+#if defined(__sparc__) && defined(__sparc_v9__)
+/* The sparc64 ioremap implementation is wrong in 2.2.x,
+ * but fixing it would break all of the drivers which
+ * workaround it.  Fixed in 2.3.x onward. -DaveM
+ */
+#define ARCH_IOREMAP(base)     ((unsigned long) (base))
+#else
+#define ARCH_IOREMAP(base)     ioremap(base)
+#endif
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+#else          /* LINUX_VERSION_CODE must be >= KERNEL_VERSION(2,2,18) */
+
+/* No ioremap bugs in >2.3.x kernels. */
+#define ARCH_IOREMAP(base)     ioremap(base)
+
+/*}-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+#endif         /* LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18) */
+
+
+/* PCI/driver subsystem { */
+#ifndef pci_for_each_dev
+#define pci_for_each_dev(dev)          for((dev)=pci_devices; (dev)!=NULL; (dev)=(dev)->next)
+#define pci_peek_next_dev(dev)         ((dev)->next ? (dev)->next : NULL)
+#define DEVICE_COUNT_RESOURCE           6
+#define PCI_BASEADDR_FLAGS(idx)         base_address[idx]
+#define PCI_BASEADDR_START(idx)         base_address[idx] & ~0xFUL
+/*
+ * We have to keep track of the original value using
+ * a temporary, and not by just sticking pdev->base_address[x]
+ * back.  pdev->base_address[x] is an opaque cookie that can
+ * be used by the PCI implementation on a given Linux port
+ * for any purpose. -DaveM
+ */
+#define PCI_BASEADDR_SIZE(__pdev, __idx) \
+({     unsigned int size, tmp; \
+       pci_read_config_dword(__pdev, PCI_BASE_ADDRESS_0 + (4*(__idx)), &tmp); \
+       pci_write_config_dword(__pdev, PCI_BASE_ADDRESS_0 + (4*(__idx)), 0xffffffff); \
+       pci_read_config_dword(__pdev, PCI_BASE_ADDRESS_0 + (4*(__idx)), &size); \
+       pci_write_config_dword(__pdev, PCI_BASE_ADDRESS_0 + (4*(__idx)), tmp); \
+       (4 - size); \
+})
+#else
+#define pci_peek_next_dev(dev)         ((dev) != pci_dev_g(&pci_devices) ? pci_dev_g((dev)->global_list.next) : NULL)
+#define PCI_BASEADDR_FLAGS(idx)         resource[idx].flags
+#define PCI_BASEADDR_START(idx)         resource[idx].start
+#define PCI_BASEADDR_SIZE(dev,idx)      (dev)->resource[idx].end - (dev)->resource[idx].start + 1
+#endif         /* } ifndef pci_for_each_dev */
+
+
+/* procfs compat stuff... */
+#ifdef CONFIG_PROC_FS
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,28)
+#define CREATE_PROCDIR_ENTRY(x,y)  create_proc_entry(x, S_IFDIR, y)
+/* This is a macro so we don't need to pull all the procfs
+ * headers into this file. -DaveM
+ */
+#define create_proc_read_entry(name, mode, base, __read_proc, __data) \
+({      struct proc_dir_entry *__res=create_proc_entry(name,mode,base); \
+        if (__res) { \
+                __res->read_proc=(__read_proc); \
+                __res->data=(__data); \
+        } \
+        __res; \
+})
+#else
+#define CREATE_PROCDIR_ENTRY(x,y)  proc_mkdir(x, y)
+#endif
+#endif
+
+/* Compatability for the 2.3.x PCI DMA API. */
+#ifndef PCI_DMA_BIDIRECTIONAL
+/*{-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+#define PCI_DMA_BIDIRECTIONAL  0
+#define PCI_DMA_TODEVICE       1
+#define PCI_DMA_FROMDEVICE     2
+#define PCI_DMA_NONE           3
+
+#ifdef __KERNEL__
+#include <asm/page.h>
+/* Pure 2^n version of get_order */
+static __inline__ int __get_order(unsigned long size)
+{
+       int order;
+
+       size = (size-1) >> (PAGE_SHIFT-1);
+       order = -1;
+       do {
+               size >>= 1;
+               order++;
+       } while (size);
+       return order;
+}
+#endif
+
+#define pci_alloc_consistent(hwdev, size, dma_handle) \
+({     void *__ret = (void *)__get_free_pages(GFP_ATOMIC, __get_order(size)); \
+       if (__ret != NULL) { \
+               memset(__ret, 0, size); \
+               *(dma_handle) = virt_to_bus(__ret); \
+       } \
+       __ret; \
+})
+
+#define pci_free_consistent(hwdev, size, vaddr, dma_handle) \
+       free_pages((unsigned long)vaddr, __get_order(size))
+
+#define pci_map_single(hwdev, ptr, size, direction) \
+       virt_to_bus(ptr);
+
+#define pci_unmap_single(hwdev, dma_addr, size, direction) \
+       do { /* Nothing to do */ } while (0)
+
+#define pci_map_sg(hwdev, sg, nents, direction)        (nents)
+#define pci_unmap_sg(hwdev, sg, nents, direction) \
+       do { /* Nothing to do */ } while(0)
+
+#define sg_dma_address(sg)     (virt_to_bus((sg)->address))
+#define sg_dma_len(sg)         ((sg)->length)
+
+/*}-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+#endif /* PCI_DMA_BIDIRECTIONAL */
+
+/*}-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+#endif /* _LINUX_COMPAT_H */
+
diff --git a/drivers/message/fusion/lsi/fc_log.h b/drivers/message/fusion/lsi/fc_log.h
new file mode 100644 (file)
index 0000000..5759717
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ *  Copyright (c) 2000-2001 LSI Logic Corporation. All rights reserved.
+ *
+ *  NAME:           fc_log.h
+ *  SUMMARY:        MPI IocLogInfo definitions for the SYMFC9xx chips
+ *  DESCRIPTION:    Contains the enumerated list of values that may be returned
+ *                  in the IOCLogInfo field of a MPI Default Reply Message.
+ *
+ *  CREATION DATE:  6/02/2000
+ *  ID:             $Id: fc_log.h,v 4.2 2001/03/01 18:28:59 fibre Exp $
+ */
+
+
+/*
+ * MpiIocLogInfo_t enum
+ *
+ * These 32 bit values are used in the IOCLogInfo field of the MPI reply
+ * messages.
+ * The value is 0xabcccccc where
+ *          a = The type of log info as per the MPI spec. Since these codes are
+ *              all for Fibre Channel this value will always be 2.
+ *          b = Specifies a subclass of the firmware where
+ *                  0 = FCP Initiator
+ *                  1 = FCP Target
+ *                  2 = LAN
+ *                  3 = MPI Message Layer
+ *                  4 = FC Link
+ *                  5 = Context Manager
+ *                  6 = Invalid Field Offset
+ *                  7 = State Change Info
+ *                  all others are reserved for future use
+ *          c = A specific value within the subclass.
+ *
+ * NOTE: Any new values should be added to the end of each subclass so that the
+ *       codes remain consistent across firmware releases.
+ */
+typedef enum _MpiIocLogInfoFc
+{
+    MPI_IOCLOGINFO_FC_INIT_BASE                     = 0x20000000,
+    MPI_IOCLOGINFO_FC_INIT_ERROR_OUT_OF_ORDER_FRAME = 0x20000001, /* received an out of order frame - unsupported */
+    MPI_IOCLOGINFO_FC_INIT_ERROR_BAD_START_OF_FRAME = 0x20000002, /* bad start of frame primative */
+    MPI_IOCLOGINFO_FC_INIT_ERROR_BAD_END_OF_FRAME   = 0x20000003, /* bad end of frame primative */
+    MPI_IOCLOGINFO_FC_INIT_ERROR_OVER_RUN           = 0x20000004, /* Receiver hardware detected overrun */
+    MPI_IOCLOGINFO_FC_INIT_ERROR_RX_OTHER           = 0x20000005, /* Other errors caught by IOC which require retries */
+    MPI_IOCLOGINFO_FC_INIT_ERROR_SUBPROC_DEAD       = 0x20000006, /* Main processor could not initialize sub-processor */
+
+    MPI_IOCLOGINFO_FC_TARGET_BASE                   = 0x21000000,
+    MPI_IOCLOGINFO_FC_TARGET_NO_PDISC               = 0x21000001, /* not sent because we are waiting for a PDISC from the initiator */
+    MPI_IOCLOGINFO_FC_TARGET_NO_LOGIN               = 0x21000002, /* not sent because we are not logged in to the remote node */
+    MPI_IOCLOGINFO_FC_TARGET_DOAR_KILLED_BY_LIP     = 0x21000003, /* Data Out, Auto Response, not sent due to a LIP */
+    MPI_IOCLOGINFO_FC_TARGET_DIAR_KILLED_BY_LIP     = 0x21000004, /* Data In, Auto Response, not sent due to a LIP */
+    MPI_IOCLOGINFO_FC_TARGET_DIAR_MISSING_DATA      = 0x21000005, /* Data In, Auto Response, missing data frames */
+    MPI_IOCLOGINFO_FC_TARGET_DONR_KILLED_BY_LIP     = 0x21000006, /* Data Out, No Response, not sent due to a LIP */
+    MPI_IOCLOGINFO_FC_TARGET_WRSP_KILLED_BY_LIP     = 0x21000007, /* Auto-response after a write not sent due to a LIP */
+    MPI_IOCLOGINFO_FC_TARGET_DINR_KILLED_BY_LIP     = 0x21000008, /* Data In, No Response, not completed due to a LIP */
+    MPI_IOCLOGINFO_FC_TARGET_DINR_MISSING_DATA      = 0x21000009, /* Data In, No Response, missing data frames */
+    MPI_IOCLOGINFO_FC_TARGET_MRSP_KILLED_BY_LIP     = 0x2100000a, /* Manual Response not sent due to a LIP */
+    MPI_IOCLOGINFO_FC_TARGET_NO_CLASS_3             = 0x2100000b, /* not sent because remote node does not support Class 3 */
+    MPI_IOCLOGINFO_FC_TARGET_LOGIN_NOT_VALID        = 0x2100000c, /* not sent because login to remote node not validated */
+    MPI_IOCLOGINFO_FC_TARGET_FROM_OUTBOUND          = 0x2100000e, /* cleared from the outbound after a logout */
+    MPI_IOCLOGINFO_FC_TARGET_WAITING_FOR_DATA_IN    = 0x2100000f, /* cleared waiting for data after a logout */
+
+    MPI_IOCLOGINFO_FC_LAN_BASE                      = 0x22000000,
+    MPI_IOCLOGINFO_FC_LAN_TRANS_SGL_MISSING         = 0x22000001, /* Transaction Context Sgl Missing */
+    MPI_IOCLOGINFO_FC_LAN_TRANS_WRONG_PLACE         = 0x22000002, /* Transaction Context found before an EOB */
+    MPI_IOCLOGINFO_FC_LAN_TRANS_RES_BITS_SET        = 0x22000003, /* Transaction Context value has reserved bits set */
+    MPI_IOCLOGINFO_FC_LAN_WRONG_SGL_FLAG            = 0x22000004, /* Invalid SGL Flags */
+
+    MPI_IOCLOGINFO_FC_MSG_BASE                      = 0x23000000,
+
+    MPI_IOCLOGINFO_FC_LINK_BASE                     = 0x24000000,
+    MPI_IOCLOGINFO_FC_LINK_LOOP_INIT_TIMEOUT        = 0x24000001, /* Loop initialization timed out */
+    MPI_IOCLOGINFO_FC_LINK_ALREADY_INITIALIZED      = 0x24000002, /* Another system controller already initialized the loop */
+    MPI_IOCLOGINFO_FC_LINK_LINK_NOT_ESTABLISHED     = 0x24000003, /* Not synchronized to signal or still negotiating (possible cable problem) */
+
+    MPI_IOCLOGINFO_FC_CTX_BASE                      = 0x25000000,
+
+    MPI_IOCLOGINFO_FC_INVALID_FIELD_BYTE_OFFSET     = 0x26000000, /* The lower 24 bits give the byte offset of the field in the request message that is invalid. */
+    MPI_IOCLOGINFO_FC_INVALID_FIELD_MAX_OFFSET      = 0x26ffffff,
+
+    MPI_IOCLOGINFO_FC_STATE_CHANGE                  = 0x27000000  /* The lower 24 bits give additional information concerning state change */
+
+} MpiIocLogInfoFc_t;
diff --git a/drivers/message/fusion/lsi/mpi.h b/drivers/message/fusion/lsi/mpi.h
new file mode 100644 (file)
index 0000000..bf0a662
--- /dev/null
@@ -0,0 +1,643 @@
+/*
+ *  Copyright (c) 2000-2001 LSI Logic Corporation.
+ *
+ *
+ *           Name:  MPI.H
+ *          Title:  MPI Message independent structures and definitions
+ *  Creation Date:  July 27, 2000
+ *
+ *    MPI Version:  01.01.06
+ *
+ *  Version History
+ *  ---------------
+ *
+ *  Date      Version   Description
+ *  --------  --------  ------------------------------------------------------
+ *  05-08-00  00.10.01  Original release for 0.10 spec dated 4/26/2000.
+ *  05-24-00  00.10.02  Added MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH definition.
+ *  06-06-00  01.00.01  Update MPI_VERSION_MAJOR and MPI_VERSION_MINOR.
+ *  06-22-00  01.00.02  Added MPI_IOCSTATUS_LAN_ definitions.
+ *                      Removed LAN_SUSPEND function definition.
+ *                      Added MPI_MSGFLAGS_CONTINUATION_REPLY definition.
+ *  06-30-00  01.00.03  Added MPI_CONTEXT_REPLY_TYPE_LAN definition.
+ *                      Added MPI_GET/SET_CONTEXT_REPLY_TYPE macros.
+ *  07-27-00  01.00.04  Added MPI_FAULT_ definitions.
+ *                      Removed MPI_IOCSTATUS_MSG/DATA_XFER_ERROR definitions.
+ *                      Added MPI_IOCSTATUS_INTERNAL_ERROR definition.
+ *                      Added MPI_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH.
+ *  11-02-00  01.01.01  Original release for post 1.0 work.
+ *  12-04-00  01.01.02  Added new function codes.
+ *  01-09-01  01.01.03  Added more definitions to the system interface section
+ *                      Added MPI_IOCSTATUS_TARGET_STS_DATA_NOT_SENT.
+ *  01-25-01  01.01.04  Changed MPI_VERSION_MINOR from 0x00 to 0x01.
+ *  02-20-01  01.01.05  Started using MPI_POINTER.
+ *                      Fixed value for MPI_DIAG_RW_ENABLE.
+ *                      Added defines for MPI_DIAG_PREVENT_IOC_BOOT and
+ *                      MPI_DIAG_CLEAR_FLASH_BAD_SIG.
+ *                      Obsoleted MPI_IOCSTATUS_TARGET_FC_ defines.
+ *  02-27-01  01.01.06  Removed MPI_HOST_INDEX_REGISTER define.
+ *                      Added function codes for RAID.
+ *  --------------------------------------------------------------------------
+ */
+
+#ifndef MPI_H
+#define MPI_H
+
+
+/*****************************************************************************
+*
+*        M P I    V e r s i o n    D e f i n i t i o n s
+*
+*****************************************************************************/
+
+#define MPI_VERSION_MAJOR                   (0x01)
+#define MPI_VERSION_MINOR                   (0x01)
+#define MPI_VERSION            ((MPI_VERSION_MAJOR << 8) | MPI_VERSION_MINOR)
+
+/* Note: The major versions of 0xe0 through 0xff are reserved */
+
+/*****************************************************************************
+*
+*        I O C    S t a t e    D e f i n i t i o n s
+*
+*****************************************************************************/
+
+#define MPI_IOC_STATE_RESET                 (0x00000000)
+#define MPI_IOC_STATE_READY                 (0x10000000)
+#define MPI_IOC_STATE_OPERATIONAL           (0x20000000)
+#define MPI_IOC_STATE_FAULT                 (0x40000000)
+
+#define MPI_IOC_STATE_MASK                  (0xF0000000)
+#define MPI_IOC_STATE_SHIFT                 (28)
+
+/* Fault state codes (product independent range 0x8000-0xFFFF) */
+
+#define MPI_FAULT_REQUEST_MESSAGE_PCI_PARITY_ERROR  (0x8111)
+#define MPI_FAULT_REQUEST_MESSAGE_PCI_BUS_FAULT     (0x8112)
+#define MPI_FAULT_REPLY_MESSAGE_PCI_PARITY_ERROR    (0x8113)
+#define MPI_FAULT_REPLY_MESSAGE_PCI_BUS_FAULT       (0x8114)
+#define MPI_FAULT_DATA_SEND_PCI_PARITY_ERROR        (0x8115)
+#define MPI_FAULT_DATA_SEND_PCI_BUS_FAULT           (0x8116)
+#define MPI_FAULT_DATA_RECEIVE_PCI_PARITY_ERROR     (0x8117)
+#define MPI_FAULT_DATA_RECEIVE_PCI_BUS_FAULT        (0x8118)
+
+
+/*****************************************************************************
+*
+*        P C I    S y s t e m    I n t e r f a c e    R e g i s t e r s
+*
+*****************************************************************************/
+
+/* S y s t e m    D o o r b e l l */
+#define MPI_DOORBELL_OFFSET                 (0x00000000)
+#define MPI_DOORBELL_ACTIVE                 (0x08000000)
+#define MPI_DOORBELL_ACTIVE_SHIFT           (27)
+#define MPI_DOORBELL_WHO_INIT_MASK          (0x07000000)
+#define MPI_DOORBELL_WHO_INIT_SHIFT         (24)
+#define MPI_DOORBELL_FUNCTION_MASK          (0xFF000000)
+#define MPI_DOORBELL_FUNCTION_SHIFT         (24)
+#define MPI_DOORBELL_ADD_DWORDS_MASK        (0x00FF0000)
+#define MPI_DOORBELL_ADD_DWORDS_SHIFT       (16)
+#define MPI_DOORBELL_DATA_MASK              (0x0000FFFF)
+
+
+#define MPI_WRITE_SEQUENCE_OFFSET           (0x00000004)
+#define MPI_WRSEQ_KEY_VALUE_MASK            (0x0000000F)
+#define MPI_WRSEQ_1ST_KEY_VALUE             (0x04)
+#define MPI_WRSEQ_2ND_KEY_VALUE             (0x0B)
+#define MPI_WRSEQ_3RD_KEY_VALUE             (0x02)
+#define MPI_WRSEQ_4TH_KEY_VALUE             (0x07)
+#define MPI_WRSEQ_5TH_KEY_VALUE             (0x0D)
+
+#define MPI_DIAGNOSTIC_OFFSET               (0x00000008)
+#define MPI_DIAG_CLEAR_FLASH_BAD_SIG        (0x00000400)
+#define MPI_DIAG_PREVENT_IOC_BOOT           (0x00000200)
+#define MPI_DIAG_DRWE                       (0x00000080)
+#define MPI_DIAG_FLASH_BAD_SIG              (0x00000040)
+#define MPI_DIAG_RESET_HISTORY              (0x00000020)
+#define MPI_DIAG_RW_ENABLE                  (0x00000010)
+#define MPI_DIAG_RESET_ADAPTER              (0x00000004)
+#define MPI_DIAG_DISABLE_ARM                (0x00000002)
+#define MPI_DIAG_MEM_ENABLE                 (0x00000001)
+
+#define MPI_TEST_BASE_ADDRESS_OFFSET        (0x0000000C)
+
+#define MPI_DIAG_RW_DATA_OFFSET             (0x00000010)
+
+#define MPI_DIAG_RW_ADDRESS_OFFSET          (0x00000014)
+
+#define MPI_HOST_INTERRUPT_STATUS_OFFSET    (0x00000030)
+#define MPI_HIS_IOP_DOORBELL_STATUS         (0x80000000)
+#define MPI_HIS_REPLY_MESSAGE_INTERRUPT     (0x00000008)
+#define MPI_HIS_DOORBELL_INTERRUPT          (0x00000001)
+
+#define MPI_HOST_INTERRUPT_MASK_OFFSET      (0x00000034)
+#define MPI_HIM_RIM                         (0x00000008)
+#define MPI_HIM_DIM                         (0x00000001)
+
+#define MPI_REQUEST_QUEUE_OFFSET            (0x00000040)
+#define MPI_REQUEST_POST_FIFO_OFFSET        (0x00000040)
+
+#define MPI_REPLY_QUEUE_OFFSET              (0x00000044)
+#define MPI_REPLY_POST_FIFO_OFFSET          (0x00000044)
+#define MPI_REPLY_FREE_FIFO_OFFSET          (0x00000044)
+
+
+
+/*****************************************************************************
+*
+*        M e s s a g e    F r a m e    D e s c r i p t o r s
+*
+*****************************************************************************/
+
+#define MPI_REQ_MF_DESCRIPTOR_NB_MASK       (0x00000003)
+#define MPI_REQ_MF_DESCRIPTOR_F_BIT         (0x00000004)
+#define MPI_REQ_MF_DESCRIPTOR_ADDRESS_MASK  (0xFFFFFFF8)
+
+#define MPI_ADDRESS_REPLY_A_BIT             (0x80000000)
+#define MPI_ADDRESS_REPLY_ADDRESS_MASK      (0x7FFFFFFF)
+
+#define MPI_CONTEXT_REPLY_A_BIT             (0x80000000)
+#define MPI_CONTEXT_REPLY_TYPE_MASK         (0x60000000)
+#define MPI_CONTEXT_REPLY_TYPE_SCSI_INIT    (0x00)
+#define MPI_CONTEXT_REPLY_TYPE_SCSI_TARGET  (0x01)
+#define MPI_CONTEXT_REPLY_TYPE_LAN          (0x02)
+#define MPI_CONTEXT_REPLY_TYPE_SHIFT        (29)
+#define MPI_CONTEXT_REPLY_CONTEXT_MASK      (0x1FFFFFFF)
+
+
+/****************************************************************************/
+/* Context Reply macros                                                     */
+/****************************************************************************/
+
+#define MPI_GET_CONTEXT_REPLY_TYPE(x)  (((x) & MPI_CONTEXT_REPLY_TYPE_MASK) \
+                                          >> MPI_CONTEXT_REPLY_TYPE_SHIFT)
+
+#define MPI_SET_CONTEXT_REPLY_TYPE(x, typ)                                  \
+            ((x) = ((x) & ~MPI_CONTEXT_REPLY_TYPE_MASK) |                   \
+                            (((typ) << MPI_CONTEXT_REPLY_TYPE_SHIFT) &      \
+                                        MPI_CONTEXT_REPLY_TYPE_MASK))
+
+
+/*****************************************************************************
+*
+*        M e s s a g e    F u n c t i o n s
+*              0x80 -> 0x8F reserved for private message use per product
+*
+*
+*****************************************************************************/
+
+#define MPI_FUNCTION_SCSI_IO_REQUEST                (0x00)
+#define MPI_FUNCTION_SCSI_TASK_MGMT                 (0x01)
+#define MPI_FUNCTION_IOC_INIT                       (0x02)
+#define MPI_FUNCTION_IOC_FACTS                      (0x03)
+#define MPI_FUNCTION_CONFIG                         (0x04)
+#define MPI_FUNCTION_PORT_FACTS                     (0x05)
+#define MPI_FUNCTION_PORT_ENABLE                    (0x06)
+#define MPI_FUNCTION_EVENT_NOTIFICATION             (0x07)
+#define MPI_FUNCTION_EVENT_ACK                      (0x08)
+#define MPI_FUNCTION_FW_DOWNLOAD                    (0x09)
+#define MPI_FUNCTION_TARGET_CMD_BUFFER_POST         (0x0A)
+#define MPI_FUNCTION_TARGET_ASSIST                  (0x0B)
+#define MPI_FUNCTION_TARGET_STATUS_SEND             (0x0C)
+#define MPI_FUNCTION_TARGET_MODE_ABORT              (0x0D)
+#define MPI_FUNCTION_TARGET_FC_BUF_POST_LINK_SRVC   (0x0E) /* obsolete name */
+#define MPI_FUNCTION_TARGET_FC_RSP_LINK_SRVC        (0x0F) /* obsolete name */
+#define MPI_FUNCTION_TARGET_FC_EX_SEND_LINK_SRVC    (0x10) /* obsolete name */
+#define MPI_FUNCTION_TARGET_FC_ABORT                (0x11) /* obsolete name */
+#define MPI_FUNCTION_FC_LINK_SRVC_BUF_POST          (0x0E)
+#define MPI_FUNCTION_FC_LINK_SRVC_RSP               (0x0F)
+#define MPI_FUNCTION_FC_EX_LINK_SRVC_SEND           (0x10)
+#define MPI_FUNCTION_FC_ABORT                       (0x11)
+#define MPI_FUNCTION_FW_UPLOAD                      (0x12)
+#define MPI_FUNCTION_FC_COMMON_TRANSPORT_SEND       (0x13)
+#define MPI_FUNCTION_FC_PRIMITIVE_SEND              (0x14)
+
+#define MPI_FUNCTION_RAID_VOLUME                    (0x15)
+#define MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH       (0x16)
+
+#define MPI_FUNCTION_LAN_SEND                       (0x20)
+#define MPI_FUNCTION_LAN_RECEIVE                    (0x21)
+#define MPI_FUNCTION_LAN_RESET                      (0x22)
+
+#define MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET         (0x40)
+#define MPI_FUNCTION_IO_UNIT_RESET                  (0x41)
+#define MPI_FUNCTION_HANDSHAKE                      (0x42)
+#define MPI_FUNCTION_REPLY_FRAME_REMOVAL            (0x43)
+
+
+
+/*****************************************************************************
+*
+*        S c a t t e r    G a t h e r    E l e m e n t s
+*
+*****************************************************************************/
+
+/****************************************************************************/
+/*  Simple element structures                                               */
+/****************************************************************************/
+
+typedef struct _SGE_SIMPLE32
+{
+    U32                     FlagsLength;
+    U32                     Address;
+} SGE_SIMPLE32, MPI_POINTER PTR_SGE_SIMPLE32,
+  SGESimple32_t, MPI_POINTER pSGESimple32_t;
+
+typedef struct _SGE_SIMPLE64
+{
+    U32                     FlagsLength;
+    U64                     Address;
+} SGE_SIMPLE64, MPI_POINTER PTR_SGE_SIMPLE64,
+  SGESimple64_t, MPI_POINTER pSGESimple64_t;
+
+typedef struct _SGE_SIMPLE_UNION
+{
+    U32                     FlagsLength;
+    union
+    {
+        U32                 Address32;
+        U64                 Address64;
+    }u;
+} SGESimpleUnion_t, MPI_POINTER pSGESimpleUnion_t,
+  SGE_SIMPLE_UNION, MPI_POINTER PTR_SGE_SIMPLE_UNION;
+
+/****************************************************************************/
+/*  Chain element structures                                                */
+/****************************************************************************/
+
+typedef struct _SGE_CHAIN32
+{
+    U16                     Length;
+    U8                      NextChainOffset;
+    U8                      Flags;
+    U32                     Address;
+} SGE_CHAIN32, MPI_POINTER PTR_SGE_CHAIN32,
+  SGEChain32_t, MPI_POINTER pSGEChain32_t;
+
+typedef struct _SGE_CHAIN64
+{
+    U16                     Length;
+    U8                      NextChainOffset;
+    U8                      Flags;
+    U64                     Address;
+} SGE_CHAIN64, MPI_POINTER PTR_SGE_CHAIN64,
+  SGEChain64_t, MPI_POINTER pSGEChain64_t;
+
+typedef struct _SGE_CHAIN_UNION
+{
+    U16                     Length;
+    U8                      NextChainOffset;
+    U8                      Flags;
+    union
+    {
+        U32                 Address32;
+        U64                 Address64;
+    }u;
+} SGE_CHAIN_UNION, MPI_POINTER PTR_SGE_CHAIN_UNION,
+  SGEChainUnion_t, MPI_POINTER pSGEChainUnion_t;
+
+/****************************************************************************/
+/*  Transaction Context element                                             */
+/****************************************************************************/
+
+typedef struct _SGE_TRANSACTION32
+{
+    U8                      Reserved;
+    U8                      ContextSize;
+    U8                      DetailsLength;
+    U8                      Flags;
+    U32                     TransactionContext[1];
+    U32                     TransactionDetails[1];
+} SGE_TRANSACTION32, MPI_POINTER PTR_SGE_TRANSACTION32,
+  SGETransaction32_t, MPI_POINTER pSGETransaction32_t;
+
+typedef struct _SGE_TRANSACTION64
+{
+    U8                      Reserved;
+    U8                      ContextSize;
+    U8                      DetailsLength;
+    U8                      Flags;
+    U32                     TransactionContext[2];
+    U32                     TransactionDetails[1];
+} SGE_TRANSACTION64, MPI_POINTER PTR_SGE_TRANSACTION64,
+  SGETransaction64_t, MPI_POINTER pSGETransaction64_t;
+
+typedef struct _SGE_TRANSACTION96
+{
+    U8                      Reserved;
+    U8                      ContextSize;
+    U8                      DetailsLength;
+    U8                      Flags;
+    U32                     TransactionContext[3];
+    U32                     TransactionDetails[1];
+} SGE_TRANSACTION96, MPI_POINTER PTR_SGE_TRANSACTION96,
+  SGETransaction96_t, MPI_POINTER pSGETransaction96_t;
+
+typedef struct _SGE_TRANSACTION128
+{
+    U8                      Reserved;
+    U8                      ContextSize;
+    U8                      DetailsLength;
+    U8                      Flags;
+    U32                     TransactionContext[4];
+    U32                     TransactionDetails[1];
+} SGE_TRANSACTION128, MPI_POINTER PTR_SGE_TRANSACTION128,
+  SGETransaction_t128, MPI_POINTER pSGETransaction_t128;
+
+typedef struct _SGE_TRANSACTION_UNION
+{
+    U8                      Reserved;
+    U8                      ContextSize;
+    U8                      DetailsLength;
+    U8                      Flags;
+    union
+    {
+        U32                 TransactionContext32[1];
+        U32                 TransactionContext64[2];
+        U32                 TransactionContext96[3];
+        U32                 TransactionContext128[4];
+    }u;
+    U32                     TransactionDetails[1];
+} SGE_TRANSACTION_UNION, MPI_POINTER PTR_SGE_TRANSACTION_UNION,
+  SGETransactionUnion_t, MPI_POINTER pSGETransactionUnion_t;
+
+
+/****************************************************************************/
+/*  SGE IO types union  for IO SGL's                                        */
+/****************************************************************************/
+
+typedef struct _SGE_IO_UNION
+{
+    union
+    {
+        SGE_SIMPLE_UNION    Simple;
+        SGE_CHAIN_UNION     Chain;
+    } u;
+} SGE_IO_UNION, MPI_POINTER PTR_SGE_IO_UNION,
+  SGEIOUnion_t, MPI_POINTER pSGEIOUnion_t;
+
+/****************************************************************************/
+/*  SGE union for SGL's with Simple and Transaction elements                */
+/****************************************************************************/
+
+typedef struct _SGE_TRANS_SIMPLE_UNION
+{
+    union
+    {
+        SGE_SIMPLE_UNION        Simple;
+        SGE_TRANSACTION_UNION   Transaction;
+    } u;
+} SGE_TRANS_SIMPLE_UNION, MPI_POINTER PTR_SGE_TRANS_SIMPLE_UNION,
+  SGETransSimpleUnion_t, MPI_POINTER pSGETransSimpleUnion_t;
+
+/****************************************************************************/
+/*  All SGE types union                                                     */
+/****************************************************************************/
+
+typedef struct _SGE_MPI_UNION
+{
+    union
+    {
+        SGE_SIMPLE_UNION        Simple;
+        SGE_CHAIN_UNION         Chain;
+        SGE_TRANSACTION_UNION   Transaction;
+    } u;
+} SGE_MPI_UNION, MPI_POINTER PTR_SGE_MPI_UNION,
+  MPI_SGE_UNION_t, MPI_POINTER pMPI_SGE_UNION_t,
+  SGEAllUnion_t, MPI_POINTER pSGEAllUnion_t;
+
+
+/****************************************************************************/
+/*  SGE field definition and masks                                          */
+/****************************************************************************/
+
+/* Flags field bit definitions */
+
+#define MPI_SGE_FLAGS_LAST_ELEMENT              (0x80)
+#define MPI_SGE_FLAGS_END_OF_BUFFER             (0x40)
+#define MPI_SGE_FLAGS_ELEMENT_TYPE_MASK         (0x30)
+#define MPI_SGE_FLAGS_LOCAL_ADDRESS             (0x08)
+#define MPI_SGE_FLAGS_DIRECTION                 (0x04)
+#define MPI_SGE_FLAGS_ADDRESS_SIZE              (0x02)
+#define MPI_SGE_FLAGS_END_OF_LIST               (0x01)
+
+#define MPI_SGE_FLAGS_SHIFT                     (24)
+
+#define MPI_SGE_LENGTH_MASK                     (0x00FFFFFF)
+#define MPI_SGE_CHAIN_LENGTH_MASK               (0x0000FFFF)
+
+/* Element Type */
+
+#define MPI_SGE_FLAGS_TRANSACTION_ELEMENT       (0x00)
+#define MPI_SGE_FLAGS_SIMPLE_ELEMENT            (0x10)
+#define MPI_SGE_FLAGS_CHAIN_ELEMENT             (0x30)
+#define MPI_SGE_FLAGS_ELEMENT_MASK              (0x30)
+
+/* Address location */
+
+#define MPI_SGE_FLAGS_SYSTEM_ADDRESS            (0x00)
+
+/* Direction */
+
+#define MPI_SGE_FLAGS_IOC_TO_HOST               (0x00)
+#define MPI_SGE_FLAGS_HOST_TO_IOC               (0x04)
+
+/* Address Size */
+
+#define MPI_SGE_FLAGS_32_BIT_ADDRESSING         (0x00)
+#define MPI_SGE_FLAGS_64_BIT_ADDRESSING         (0x02)
+
+/* Context Size */
+
+#define MPI_SGE_FLAGS_32_BIT_CONTEXT            (0x00)
+#define MPI_SGE_FLAGS_64_BIT_CONTEXT            (0x02)
+#define MPI_SGE_FLAGS_96_BIT_CONTEXT            (0x04)
+#define MPI_SGE_FLAGS_128_BIT_CONTEXT           (0x06)
+
+#define MPI_SGE_CHAIN_OFFSET_MASK               (0x00FF0000)
+#define MPI_SGE_CHAIN_OFFSET_SHIFT              (16)
+
+
+/****************************************************************************/
+/*  SGE operation Macros                                                    */
+/****************************************************************************/
+
+         /* SIMPLE FlagsLength manipulations... */
+#define  MPI_SGE_SET_FLAGS(f)           ((U32)(f) << MPI_SGE_FLAGS_SHIFT)
+#define  MPI_SGE_GET_FLAGS(fl)          (((fl) & ~MPI_SGE_LENGTH_MASK) >> MPI_SGE_FLAGS_SHIFT)
+#define  MPI_SGE_LENGTH(fl)             ((fl) & MPI_SGE_LENGTH_MASK)
+#define  MPI_SGE_CHAIN_LENGTH(fl)       ((fl) & MPI_SGE_CHAIN_LENGTH_MASK)
+
+#define  MPI_SGE_SET_FLAGS_LENGTH(f,l)  (MPI_SGE_SET_FLAGS(f) | MPI_SGE_LENGTH(l))
+
+#define  MPI_pSGE_GET_FLAGS(psg)        MPI_SGE_GET_FLAGS((psg)->FlagsLength)
+#define  MPI_pSGE_GET_LENGTH(psg)       MPI_SGE_LENGTH((psg)->FlagsLength)
+#define  MPI_pSGE_SET_FLAGS_LENGTH(psg,f,l)  (psg)->FlagsLength = MPI_SGE_SET_FLAGS_LENGTH(f,l)
+         /* CAUTION - The following are READ-MODIFY-WRITE! */
+#define  MPI_pSGE_SET_FLAGS(psg,f)      (psg)->FlagsLength |= MPI_SGE_SET_FLAGS(f)
+#define  MPI_pSGE_SET_LENGTH(psg,l)     (psg)->FlagsLength |= MPI_SGE_LENGTH(l)
+
+#define  MPI_GET_CHAIN_OFFSET(x) ((x&MPI_SGE_CHAIN_OFFSET_MASK)>>MPI_SGE_CHAIN_OFFSET_SHIFT)
+
+
+
+/*****************************************************************************
+*
+*        S t a n d a r d    M e s s a g e    S t r u c t u r e s
+*
+*****************************************************************************/
+
+/****************************************************************************/
+/* Standard message request header for all request messages                 */
+/****************************************************************************/
+
+typedef struct _MSG_REQUEST_HEADER
+{
+    U8                      Reserved[2];      /* function specific */
+    U8                      ChainOffset;
+    U8                      Function;
+    U8                      Reserved1[3];     /* function specific */
+    U8                      MsgFlags;
+    U32                     MsgContext;
+} MSG_REQUEST_HEADER, MPI_POINTER PTR_MSG_REQUEST_HEADER,
+  MPIHeader_t, MPI_POINTER pMPIHeader_t;
+
+
+/****************************************************************************/
+/*  Default Reply                                                           */
+/****************************************************************************/
+
+typedef struct _MSG_DEFAULT_REPLY
+{
+    U8                      Reserved[2];      /* function specific */
+    U8                      MsgLength;
+    U8                      Function;
+    U8                      Reserved1[3];     /* function specific */
+    U8                      MsgFlags;
+    U32                     MsgContext;
+    U8                      Reserved2[2];     /* function specific */
+    U16                     IOCStatus;
+    U32                     IOCLogInfo;
+} MSG_DEFAULT_REPLY, MPI_POINTER PTR_MSG_DEFAULT_REPLY,
+  MPIDefaultReply_t, MPI_POINTER pMPIDefaultReply_t;
+
+
+/* MsgFlags definition for all replies */
+
+#define MPI_MSGFLAGS_CONTINUATION_REPLY         (0x80)
+
+
+/*****************************************************************************
+*
+*               I O C    S t a t u s   V a l u e s
+*
+*****************************************************************************/
+
+/****************************************************************************/
+/*  Common IOCStatus values for all replies                                 */
+/****************************************************************************/
+
+#define MPI_IOCSTATUS_SUCCESS                  (0x0000)
+#define MPI_IOCSTATUS_INVALID_FUNCTION         (0x0001)
+#define MPI_IOCSTATUS_BUSY                     (0x0002)
+#define MPI_IOCSTATUS_INVALID_SGL              (0x0003)
+#define MPI_IOCSTATUS_INTERNAL_ERROR           (0x0004)
+#define MPI_IOCSTATUS_RESERVED                 (0x0005)
+#define MPI_IOCSTATUS_INSUFFICIENT_RESOURCES   (0x0006)
+#define MPI_IOCSTATUS_INVALID_FIELD            (0x0007)
+#define MPI_IOCSTATUS_INVALID_STATE            (0x0008)
+
+/****************************************************************************/
+/*  Config IOCStatus values                                                 */
+/****************************************************************************/
+
+#define MPI_IOCSTATUS_CONFIG_INVALID_ACTION    (0x0020)
+#define MPI_IOCSTATUS_CONFIG_INVALID_TYPE      (0x0021)
+#define MPI_IOCSTATUS_CONFIG_INVALID_PAGE      (0x0022)
+#define MPI_IOCSTATUS_CONFIG_INVALID_DATA      (0x0023)
+#define MPI_IOCSTATUS_CONFIG_NO_DEFAULTS       (0x0024)
+#define MPI_IOCSTATUS_CONFIG_CANT_COMMIT       (0x0025)
+
+/****************************************************************************/
+/*  SCSIIO Reply (SPI & FCP) initiator values                               */
+/****************************************************************************/
+
+#define MPI_IOCSTATUS_SCSI_RECOVERED_ERROR     (0x0040)
+#define MPI_IOCSTATUS_SCSI_INVALID_BUS         (0x0041)
+#define MPI_IOCSTATUS_SCSI_INVALID_TARGETID    (0x0042)
+#define MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE    (0x0043)
+#define MPI_IOCSTATUS_SCSI_DATA_OVERRUN        (0x0044)
+#define MPI_IOCSTATUS_SCSI_DATA_UNDERRUN       (0x0045)
+#define MPI_IOCSTATUS_SCSI_IO_DATA_ERROR       (0x0046)
+#define MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR      (0x0047)
+#define MPI_IOCSTATUS_SCSI_TASK_TERMINATED     (0x0048)
+#define MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH   (0x0049)
+#define MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED    (0x004A)
+#define MPI_IOCSTATUS_SCSI_IOC_TERMINATED      (0x004B)
+#define MPI_IOCSTATUS_SCSI_EXT_TERMINATED      (0x004C)
+
+/****************************************************************************/
+/*  SCSI (SPI & FCP) target values                                          */
+/****************************************************************************/
+
+#define MPI_IOCSTATUS_TARGET_PRIORITY_IO         (0x0060)
+#define MPI_IOCSTATUS_TARGET_INVALID_PORT        (0x0061)
+#define MPI_IOCSTATUS_TARGET_INVALID_IOCINDEX    (0x0062)
+#define MPI_IOCSTATUS_TARGET_ABORTED             (0x0063)
+#define MPI_IOCSTATUS_TARGET_NO_CONN_RETRYABLE   (0x0064)
+#define MPI_IOCSTATUS_TARGET_NO_CONNECTION       (0x0065)
+#define MPI_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH (0x006A)
+#define MPI_IOCSTATUS_TARGET_STS_DATA_NOT_SENT   (0x006B)
+
+/****************************************************************************/
+/*  Additional FCP target values                                            */
+/****************************************************************************/
+
+#define MPI_IOCSTATUS_TARGET_FC_ABORTED         (0x0066)    /* obsolete */
+#define MPI_IOCSTATUS_TARGET_FC_RX_ID_INVALID   (0x0067)    /* obsolete */
+#define MPI_IOCSTATUS_TARGET_FC_DID_INVALID     (0x0068)    /* obsolete */
+#define MPI_IOCSTATUS_TARGET_FC_NODE_LOGGED_OUT (0x0069)    /* obsolete */
+
+/****************************************************************************/
+/*  Fibre Channel Direct Access values                                      */
+/****************************************************************************/
+
+#define MPI_IOCSTATUS_FC_ABORTED                (0x0066)
+#define MPI_IOCSTATUS_FC_RX_ID_INVALID          (0x0067)
+#define MPI_IOCSTATUS_FC_DID_INVALID            (0x0068)
+#define MPI_IOCSTATUS_FC_NODE_LOGGED_OUT        (0x0069)
+
+/****************************************************************************/
+/*  LAN values                                                              */
+/****************************************************************************/
+
+#define MPI_IOCSTATUS_LAN_DEVICE_NOT_FOUND      (0x0080)
+#define MPI_IOCSTATUS_LAN_DEVICE_FAILURE        (0x0081)
+#define MPI_IOCSTATUS_LAN_TRANSMIT_ERROR        (0x0082)
+#define MPI_IOCSTATUS_LAN_TRANSMIT_ABORTED      (0x0083)
+#define MPI_IOCSTATUS_LAN_RECEIVE_ERROR         (0x0084)
+#define MPI_IOCSTATUS_LAN_RECEIVE_ABORTED       (0x0085)
+#define MPI_IOCSTATUS_LAN_PARTIAL_PACKET        (0x0086)
+#define MPI_IOCSTATUS_LAN_CANCELED              (0x0087)
+
+
+/****************************************************************************/
+/*  IOCStatus flag to indicate that log info is available                   */
+/****************************************************************************/
+
+#define MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE   (0x8000)
+#define MPI_IOCSTATUS_MASK                      (0x7FFF)
+
+/****************************************************************************/
+/*  LogInfo Types                                                           */
+/****************************************************************************/
+
+#define MPI_IOCLOGINFO_TYPE_MASK                (0xF0000000)
+#define MPI_IOCLOGINFO_TYPE_NONE                (0x00)
+#define MPI_IOCLOGINFO_TYPE_SCSI                (0x01)
+#define MPI_IOCLOGINFO_TYPE_FC                  (0x02)
+#define MPI_IOCLOGINFO_LOG_DATA_MASK            (0x0FFFFFFF)
+
+
+#endif
diff --git a/drivers/message/fusion/lsi/mpi_cnfg.h b/drivers/message/fusion/lsi/mpi_cnfg.h
new file mode 100644 (file)
index 0000000..dd81a65
--- /dev/null
@@ -0,0 +1,971 @@
+/*
+ *  Copyright (c) 2000-2001 LSI Logic Corporation.
+ *
+ *
+ *           Name:  MPI_CNFG.H
+ *          Title:  MPI Config message, structures, and Pages
+ *  Creation Date:  July 27, 2000
+ *
+ *    MPI Version:  01.01.09
+ *
+ *  Version History
+ *  ---------------
+ *
+ *  Date      Version   Description
+ *  --------  --------  ------------------------------------------------------
+ *  05-08-00  00.10.01  Original release for 0.10 spec dated 4/26/2000.
+ *  06-06-00  01.00.01  Update version number for 1.0 release.
+ *  06-08-00  01.00.02  Added _PAGEVERSION definitions for all pages.
+ *                      Added FcPhLowestVersion, FcPhHighestVersion, Reserved2
+ *                      fields to FC_DEVICE_0 page, updated the page version.
+ *                      Changed _FREE_RUNNING_CLOCK to _PACING_TRANSFERS in
+ *                      SCSI_PORT_0, SCSI_DEVICE_0 and SCSI_DEVICE_1 pages
+ *                      and updated the page versions.
+ *                      Added _RESPONSE_ID_MASK definition to SCSI_PORT_1
+ *                      page and updated the page version.
+ *                      Added Information field and _INFO_PARAMS_NEGOTIATED
+ *                      definitionto SCSI_DEVICE_0 page.
+ *  06-22-00  01.00.03  Removed batch controls from LAN_0 page and updated the
+ *                      page version.
+ *                      Added BucketsRemaining to LAN_1 page, redefined the
+ *                      state values, and updated the page version.
+ *                      Revised bus width definitions in SCSI_PORT_0,
+ *                      SCSI_DEVICE_0 and SCSI_DEVICE_1 pages.
+ *  06-30-00  01.00.04  Added MaxReplySize to LAN_1 page and updated the page
+ *                      version.
+ *                      Moved FC_DEVICE_0 PageAddress description to spec.
+ *  07-27-00  01.00.05  Corrected the SubsystemVendorID and SubsystemID field
+ *                      widths in IOC_0 page and updated the page version.
+ *  11-02-00  01.01.01  Original release for post 1.0 work
+ *                      Added Manufacturing pages, IO Unit Page 2, SCSI SPI
+ *                      Port Page 2, FC Port Page 4, FC Port Page 5
+ *  11-15-00  01.01.02  Interim changes to match proposals
+ *  12-04-00  01.01.03  Config page changes to match MPI rev 1.00.01.
+ *  12-05-00  01.01.04  Modified config page actions.
+ *  01-09-01  01.01.05  Added defines for page address formats.
+ *                      Data size for Manufacturing pages 2 and 3 no longer
+ *                      defined here.
+ *                      Io Unit Page 2 size is fixed at 4 adapters and some
+ *                      flags were changed.
+ *                      SCSI Port Page 2 Device Settings modified.
+ *                      New fields added to FC Port Page 0 and some flags
+ *                      cleaned up.
+ *                      Removed impedance flash from FC Port Page 1.
+ *                      Added FC Port pages 6 and 7.
+ *  01-25-01  01.01.06  Added MaxInitiators field to FcPortPage0.
+ *  01-29-01  01.01.07  Changed some defines to make them 32 character unique.
+ *                      Added some LinkType defines for FcPortPage0.
+ *  02-20-01  01.01.08  Started using MPI_POINTER.
+ *  02-27-01  01.01.09  Replaced MPI_CONFIG_PAGETYPE_SCSI_LUN with
+ *                      MPI_CONFIG_PAGETYPE_RAID_VOLUME.
+ *                      Added definitions and structures for IOC Page 2 and
+ *                      RAID Volume Page 2.
+ *  --------------------------------------------------------------------------
+ */
+
+#ifndef MPI_CNFG_H
+#define MPI_CNFG_H
+
+
+/*****************************************************************************
+*
+*       C o n f i g    M e s s a g e    a n d    S t r u c t u r e s
+*
+*****************************************************************************/
+
+typedef struct _CONFIG_PAGE_HEADER
+{
+    U8                      PageVersion;
+    U8                      PageLength;
+    U8                      PageNumber;
+    U8                      PageType;
+} fCONFIG_PAGE_HEADER, MPI_POINTER PTR_CONFIG_PAGE_HEADER,
+  ConfigPageHeader_t, MPI_POINTER pConfigPageHeader_t;
+
+typedef union _CONFIG_PAGE_HEADER_UNION
+{
+   ConfigPageHeader_t  Struct;
+   U8                  Bytes[4];
+   U16                 Word16[2];
+   U32                 Word32;
+} ConfigPageHeaderUnion, MPI_POINTER pConfigPageHeaderUnion,
+  fCONFIG_PAGE_HEADER_UNION, MPI_POINTER PTR_CONFIG_PAGE_HEADER_UNION;
+
+
+/****************************************************************************/
+/*  PageType field values                                                   */
+/****************************************************************************/
+#define MPI_CONFIG_PAGEATTR_READ_ONLY               (0x00)
+#define MPI_CONFIG_PAGEATTR_CHANGEABLE              (0x10)
+#define MPI_CONFIG_PAGEATTR_PERSISTENT              (0x20)
+#define MPI_CONFIG_PAGEATTR_MASK                    (0xF0)
+
+#define MPI_CONFIG_PAGETYPE_IO_UNIT                 (0x00)
+#define MPI_CONFIG_PAGETYPE_IOC                     (0x01)
+#define MPI_CONFIG_PAGETYPE_BIOS                    (0x02)
+#define MPI_CONFIG_PAGETYPE_SCSI_PORT               (0x03)
+#define MPI_CONFIG_PAGETYPE_SCSI_DEVICE             (0x04)
+#define MPI_CONFIG_PAGETYPE_FC_PORT                 (0x05)
+#define MPI_CONFIG_PAGETYPE_FC_DEVICE               (0x06)
+#define MPI_CONFIG_PAGETYPE_LAN                     (0x07)
+#define MPI_CONFIG_PAGETYPE_RAID_VOLUME             (0x08)
+#define MPI_CONFIG_PAGETYPE_MANUFACTURING           (0x09)
+#define MPI_CONFIG_PAGETYPE_MASK                    (0x0F)
+
+#define MPI_CONFIG_TYPENUM_MASK                     (0x0FFF)
+
+
+/****************************************************************************
+ *  PageAddres field values
+ ****************************************************************************/
+#define MPI_SCSI_PORT_PGAD_PORT_MASK                (0x000000FF)
+
+#define MPI_SCSI_DEVICE_TARGET_ID_MASK              (0x000000FF)
+#define MPI_SCSI_DEVICE_TARGET_ID_SHIFT             (0)
+#define MPI_SCSI_DEVICE_BUS_MASK                    (0x0000FF00)
+#define MPI_SCSI_DEVICE_BUS_SHIFT                   (8)
+
+#define MPI_SCSI_LUN_TARGET_ID_MASK                 (0x000000FF)
+#define MPI_SCSI_LUN_TARGET_ID_SHIFT                (0)
+#define MPI_SCSI_LUN_BUS_MASK                       (0x0000FF00)
+#define MPI_SCSI_LUN_BUS_SHIFT                      (8)
+#define MPI_SCSI_LUN_LUN_MASK                       (0x00FF0000)
+#define MPI_SCSI_LUN_LUN_SHIFT                      (16)
+
+#define MPI_FC_PORT_PGAD_PORT_MASK                  (0xF0000000)
+#define MPI_FC_PORT_PGAD_PORT_SHIFT                 (28)
+#define MPI_FC_PORT_PGAD_FORM_MASK                  (0x0F000000)
+#define MPI_FC_PORT_PGAD_FORM_INDEX                 (0x01000000)
+#define MPI_FC_PORT_PGAD_INDEX_MASK                 (0x0000FFFF)
+#define MPI_FC_PORT_PGAD_INDEX_SHIFT                (0)
+
+#define MPI_FC_DEVICE_PGAD_PORT_MASK                (0xF0000000)
+#define MPI_FC_DEVICE_PGAD_PORT_SHIFT               (28)
+#define MPI_FC_DEVICE_PGAD_FORM_MASK                (0x0F000000)
+#define MPI_FC_DEVICE_PGAD_FORM_NEXT_DID            (0x00000000)
+#define MPI_FC_DEVICE_PGAD_ND_PORT_MASK             (0xF0000000)
+#define MPI_FC_DEVICE_PGAD_ND_PORT_SHIFT            (28)
+#define MPI_FC_DEVICE_PGAD_ND_DID_MASK              (0x00FFFFFF)
+#define MPI_FC_DEVICE_PGAD_ND_DID_SHIFT             (0)
+#define MPI_FC_DEVICE_PGAD_FORM_BUS_TID             (0x01000000)
+#define MPI_FC_DEVICE_PGAD_BT_BUS_MASK              (0x0000FF00)
+#define MPI_FC_DEVICE_PGAD_BT_BUS_SHIFT             (8)
+#define MPI_FC_DEVICE_PGAD_BT_TID_MASK              (0x000000FF)
+#define MPI_FC_DEVICE_PGAD_BT_TID_SHIFT             (0)
+
+
+/****************************************************************************/
+/*  Config Request Message                                                          */
+/****************************************************************************/
+typedef struct _MSG_CONFIG
+{
+    U8                      Action;
+    U8                      Reserved;
+    U8                      ChainOffset;
+    U8                      Function;
+    U8                      Reserved1[3];
+    U8                      MsgFlags;
+    U32                     MsgContext;
+    U8                      Reserved2[8];
+   fCONFIG_PAGE_HEADER      Header;
+    U32                     PageAddress;
+    SGE_IO_UNION            PageBufferSGE;
+} MSG_CONFIG, MPI_POINTER PTR_MSG_CONFIG,
+  Config_t, MPI_POINTER pConfig_t;
+
+
+/****************************************************************************/
+/*  Action field values                                                     */
+/****************************************************************************/
+#define MPI_CONFIG_ACTION_PAGE_HEADER               (0x00)
+/*#define MPI_CONFIG_ACTION_PAGE_READ                 (0x01) *//* obsolete */
+#define MPI_CONFIG_ACTION_PAGE_READ_CURRENT         (0x01)
+/*#define MPI_CONFIG_ACTION_PAGE_WRITE                (0x02) *//* obsolete */
+#define MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT        (0x02)
+#define MPI_CONFIG_ACTION_PAGE_DEFAULT              (0x03)
+/*#define MPI_CONFIG_ACTION_PAGE_WRITE_COMMIT         (0x04) */ /* obsolete */
+#define MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM          (0x04)
+#define MPI_CONFIG_ACTION_PAGE_READ_DEFAULT         (0x05)
+#define MPI_CONFIG_ACTION_PAGE_READ_NVRAM           (0x06)
+
+
+/* Config Reply Message */
+typedef struct _MSG_CONFIG_REPLY
+{
+    U8                      Action;
+    U8                      Reserved;
+    U8                      MsgLength;
+    U8                      Function;
+    U8                      Reserved1[3];
+    U8                      MsgFlags;
+    U32                     MsgContext;
+    U8                      Reserved2[2];
+    U16                     IOCStatus;
+    U32                     IOCLogInfo;
+   fCONFIG_PAGE_HEADER      Header;
+} MSG_CONFIG_REPLY, MPI_POINTER PTR_MSG_CONFIG_REPLY,
+  ConfigReply_t, MPI_POINTER pConfigReply_t;
+
+
+
+/*****************************************************************************
+*
+*               C o n f i g u r a t i o n    P a g e s
+*
+*****************************************************************************/
+
+/****************************************************************************/
+/*  Manufacturing Config pages                                              */
+/****************************************************************************/
+#define MPI_MANUFACTPAGE_DEVICEID_FC909             (0x0621)
+#define MPI_MANUFACTPAGE_DEVICEID_FC919             (0x0624)
+#define MPI_MANUFACTPAGE_DEVICEID_FC929             (0x0622)
+#define MPI_MANUFACTPAGE_DEVID_53C1030              (0x0030)
+#define MPI_MANUFACTPAGE_DEVID_53C1030ZC            (0x0031)
+#define MPI_MANUFACTPAGE_DEVID_53C1035              (0x0035)
+
+typedef struct _CONFIG_PAGE_MANUFACTURING_0
+{
+   fCONFIG_PAGE_HEADER      Header;
+    U8                      ChipName[16];
+    U8                      ChipRevision[8];
+    U8                      BoardName[16];
+    U8                      BoardAssembly[16];
+    U8                      BoardTracerNumber[16];
+
+} fCONFIG_PAGE_MANUFACTURING_0, MPI_POINTER PTR_CONFIG_PAGE_MANUFACTURING_0,
+  ManufacturingPage0_t, MPI_POINTER pManufacturingPage0_t;
+
+#define MPI_MANUFACTURING0_PAGEVERSION                 (0x00)
+
+
+typedef struct _CONFIG_PAGE_MANUFACTURING_1
+{
+   fCONFIG_PAGE_HEADER      Header;
+    U8                      VPD[256];
+} fCONFIG_PAGE_MANUFACTURING_1, MPI_POINTER PTR_CONFIG_PAGE_MANUFACTURING_1,
+  ManufacturingPage1_t, MPI_POINTER pManufacturingPage1_t;
+
+#define MPI_MANUFACTURING1_PAGEVERSION                 (0x00)
+
+
+typedef struct _MPI_CHIP_REVISION_ID
+{
+    U16 DeviceID;
+    U8  PCIRevisionID;
+    U8  Reserved;
+} MPI_CHIP_REVISION_ID, MPI_POINTER PTR_MPI_CHIP_REVISION_ID,
+  MpiChipRevisionId_t, MPI_POINTER pMpiChipRevisionId_t;
+
+
+typedef struct _CONFIG_PAGE_MANUFACTURING_2
+{
+   fCONFIG_PAGE_HEADER                  Header;
+    MPI_CHIP_REVISION_ID                ChipId;
+    U32                                 HwSettings[1];
+} fCONFIG_PAGE_MANUFACTURING_2, MPI_POINTER PTR_CONFIG_PAGE_MANUFACTURING_2,
+  ManufacturingPage2_t, MPI_POINTER pManufacturingPage2_t;
+
+#define MPI_MANUFACTURING2_PAGEVERSION                  (0x00)
+
+
+typedef struct _CONFIG_PAGE_MANUFACTURING_3
+{
+   fCONFIG_PAGE_HEADER                  Header;
+    MPI_CHIP_REVISION_ID                ChipId;
+    U32                                 Info[1];
+} fCONFIG_PAGE_MANUFACTURING_3, MPI_POINTER PTR_CONFIG_PAGE_MANUFACTURING_3,
+  ManufacturingPage3_t, MPI_POINTER pManufacturingPage3_t;
+
+#define MPI_MANUFACTURING3_PAGEVERSION                  (0x00)
+
+
+/****************************************************************************/
+/*  IO Unit Config Pages                                                    */
+/****************************************************************************/
+
+typedef struct _CONFIG_PAGE_IO_UNIT_0
+{
+   fCONFIG_PAGE_HEADER      Header;
+    U64                     UniqueValue;
+} fCONFIG_PAGE_IO_UNIT_0, MPI_POINTER PTR_CONFIG_PAGE_IO_UNIT_0,
+  IOUnitPage0_t, MPI_POINTER pIOUnitPage0_t;
+
+#define MPI_IOUNITPAGE0_PAGEVERSION                     (0x00)
+
+
+typedef struct _CONFIG_PAGE_IO_UNIT_1
+{
+   fCONFIG_PAGE_HEADER      Header;
+    U32                     Flags;
+} fCONFIG_PAGE_IO_UNIT_1, MPI_POINTER PTR_CONFIG_PAGE_IO_UNIT_1,
+  IOUnitPage1_t, MPI_POINTER pIOUnitPage1_t;
+
+#define MPI_IOUNITPAGE1_PAGEVERSION                     (0x00)
+
+#define MPI_IOUNITPAGE1_MULTI_FUNCTION                  (0x00000000)
+#define MPI_IOUNITPAGE1_SINGLE_FUNCTION                 (0x00000001)
+#define MPI_IOUNITPAGE1_MULTI_PATHING                   (0x00000002)
+#define MPI_IOUNITPAGE1_SINGLE_PATHING                  (0x00000000)
+
+#define MPI_IOUNITPAGE1_FORCE_32                        (0x00000080)
+
+
+typedef struct _MPI_ADAPTER_INFO
+{
+    U8      PciBusNumber;
+    U8      PciDeviceAndFunctionNumber;
+    U16     AdapterFlags;
+} MPI_ADAPTER_INFO, MPI_POINTER PTR_MPI_ADAPTER_INFO,
+  MpiAdapterInfo_t, MPI_POINTER pMpiAdapterInfo_t;
+
+#define MPI_ADAPTER_INFO_FLAGS_EMBEDDED                 (0x0001)
+#define MPI_ADAPTER_INFO_FLAGS_INIT_STATUS              (0x0002)
+
+typedef struct _CONFIG_PAGE_IO_UNIT_2
+{
+   fCONFIG_PAGE_HEADER      Header;
+    U32                     Flags;
+    U32                     BiosVersion;
+    MPI_ADAPTER_INFO        AdapterOrder[4];
+} fCONFIG_PAGE_IO_UNIT_2, MPI_POINTER PTR_CONFIG_PAGE_IO_UNIT_2,
+  IOUnitPage2_t, MPI_POINTER pIOUnitPage2_t;
+
+#define MPI_IOUNITPAGE2_PAGEVERSION                     (0x00)
+
+#define MPI_IOUNITPAGE2_FLAGS_RAID_DISABLE              (0x00000001)
+#define MPI_IOUNITPAGE2_FLAGS_PAUSE_ON_ERROR            (0x00000002)
+#define MPI_IOUNITPAGE2_FLAGS_VERBOSE_ENABLE            (0x00000004)
+#define MPI_IOUNITPAGE2_FLAGS_COLOR_VIDEO_DISABLE       (0x00000008)
+#define MPI_IOUNITPAGE2_FLAGS_DONT_HOOK_INT_40          (0x00000010)
+
+
+/****************************************************************************/
+/*  IOC Config Pages                                                        */
+/****************************************************************************/
+
+typedef struct _CONFIG_PAGE_IOC_0
+{
+   fCONFIG_PAGE_HEADER      Header;
+    U32                     TotalNVStore;
+    U32                     FreeNVStore;
+    U16                     VendorID;
+    U16                     DeviceID;
+    U8                      RevisionID;
+    U8                      Reserved[3];
+    U32                     ClassCode;
+    U16                     SubsystemVendorID;
+    U16                     SubsystemID;
+} fCONFIG_PAGE_IOC_0, MPI_POINTER PTR_CONFIG_PAGE_IOC_0,
+  IOCPage0_t, MPI_POINTER pIOCPage0_t;
+
+#define MPI_IOCPAGE0_PAGEVERSION                        (0x01)
+
+typedef struct _CONFIG_PAGE_IOC_1
+{
+   fCONFIG_PAGE_HEADER      Header;
+    U32                     Flags;
+    U32                     CoalescingTimeout;
+    U8                      CoalescingDepth;
+    U8                      Reserved[3];
+} fCONFIG_PAGE_IOC_1, MPI_POINTER PTR_CONFIG_PAGE_IOC_1,
+  IOCPage1_t, MPI_POINTER pIOCPage1_t;
+
+#define MPI_IOCPAGE1_PAGEVERSION                        (0x00)
+
+#define MPI_IOCPAGE1_REPLY_COALESCING                   (0x00000001)
+
+typedef struct _CONFIG_PAGE_IOC_2_RAID_VOL
+{
+    U8                      VolumeTargetID;
+    U8                      VolumeBus;
+    U16                     Reserved;
+    U8                      VolumeVersionMinor;
+    U8                      VolumeVersionMajor;
+    U8                      VolumeRaidType;
+    U8                      Reserved1;
+} fCONFIG_PAGE_IOC_2_RAID_VOL, MPI_POINTER PTR_CONFIG_PAGE_IOC_2_RAID_VOL,
+  ConfigPageIoc2RaidVol_t, MPI_POINTER pConfigPageIoc2RaidVol_t;
+
+typedef struct _CONFIG_PAGE_IOC_2
+{
+   fCONFIG_PAGE_HEADER          Header;
+    U32                         CapabilitiesFlags;
+    U8                          NumActiveVolumes;
+    U8                          MaxVolumes;
+    U16                         Reserved;
+   fCONFIG_PAGE_IOC_2_RAID_VOL  RaidVolume[1];
+} fCONFIG_PAGE_IOC_2, MPI_POINTER PTR_CONFIG_PAGE_IOC_2,
+  IOCPage2_t, MPI_POINTER pIOCPage2_t;
+
+#define MPI_IOCPAGE2_PAGEVERSION                        (0x00)
+
+/* IOC Page 2 Capabilities flags */
+
+#define MPI_IOCPAGE2_CAP_FLAGS_RAID_0_SUPPORT           (0x00000001)
+#define MPI_IOCPAGE2_CAP_FLAGS_RAID_1_SUPPORT           (0x00000002)
+#define MPI_IOCPAGE2_CAP_FLAGS_LSI_MIRROR_SUPPORT       (0x00000004)
+#define MPI_IOCPAGE2_CAP_FLAGS_RAID_5_SUPPORT           (0x00000008)
+#define MPI_IOCPAGE2_CAP_FLAGS_RAID_10_SUPPORT          (0x00000010)
+
+/* IOC Page 2 Volume RAID Type values */
+
+#define MPI_IOCPAGE2_VOL_TYPE_RAID_0                    (0x00)
+#define MPI_IOCPAGE2_VOL_TYPE_RAID_1                    (0x01)
+#define MPI_IOCPAGE2_VOL_TYPE_LSI_MIRROR                (0x02)
+#define MPI_IOCPAGE2_VOL_TYPE_RAID_5                    (0x05)
+#define MPI_IOCPAGE2_VOL_TYPE_RAID_10                   (0x0A)
+
+
+/****************************************************************************/
+/*  SCSI Port Config Pages                                                  */
+/****************************************************************************/
+
+typedef struct _CONFIG_PAGE_SCSI_PORT_0
+{
+   fCONFIG_PAGE_HEADER      Header;
+    U32                     Capabilities;
+    U32                     PhysicalInterface;
+} fCONFIG_PAGE_SCSI_PORT_0, MPI_POINTER PTR_CONFIG_PAGE_SCSI_PORT_0,
+  SCSIPortPage0_t, MPI_POINTER pSCSIPortPage0_t;
+
+#define MPI_SCSIPORTPAGE0_PAGEVERSION                   (0x01)
+
+#define MPI_SCSIPORTPAGE0_CAP_IU                        (0x00000001)
+#define MPI_SCSIPORTPAGE0_CAP_DT                        (0x00000002)
+#define MPI_SCSIPORTPAGE0_CAP_QAS                       (0x00000004)
+#define MPI_SCSIPORTPAGE0_CAP_PACING_TRANSFERS          (0x00000008)
+#define MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK      (0x0000FF00)
+#define MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK      (0x00FF0000)
+#define MPI_SCSIPORTPAGE0_CAP_WIDE                      (0x20000000)
+#define MPI_SCSIPORTPAGE0_CAP_AIP                       (0x80000000)
+
+#define MPI_SCSIPORTPAGE0_PHY_SIGNAL_TYPE_MASK          (0x00000003)
+#define MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD                (0x01)
+#define MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE                 (0x02)
+#define MPI_SCSIPORTPAGE0_PHY_SIGNAL_LVD                (0x03)
+
+typedef struct _CONFIG_PAGE_SCSI_PORT_1
+{
+   fCONFIG_PAGE_HEADER      Header;
+    U32                     Configuration;
+} fCONFIG_PAGE_SCSI_PORT_1, MPI_POINTER PTR_CONFIG_PAGE_SCSI_PORT_1,
+  SCSIPortPage1_t, MPI_POINTER pSCSIPortPage1_t;
+
+#define MPI_SCSIPORTPAGE1_PAGEVERSION                   (0x01)
+
+#define MPI_SCSIPORTPAGE1_CFG_PORT_SCSI_ID_MASK         (0x000000FF)
+#define MPI_SCSIPORTPAGE1_CFG_PORT_RESPONSE_ID_MASK     (0xFFFF0000)
+
+typedef struct _MPI_DEVICE_INFO
+{
+    U8      Timeout;
+    U8      SyncFactor;
+    U16     DeviceFlags;
+} MPI_DEVICE_INFO, MPI_POINTER PTR_MPI_DEVICE_INFO,
+  MpiDeviceInfo_t, MPI_POINTER pMpiDeviceInfo_t;
+
+typedef struct _CONFIG_PAGE_SCSI_PORT_2
+{
+   fCONFIG_PAGE_HEADER  Header;
+    U32                 PortFlags;
+    U32                 PortSettings;
+    MPI_DEVICE_INFO     DeviceSettings[16];
+} fCONFIG_PAGE_SCSI_PORT_2, MPI_POINTER PTR_CONFIG_PAGE_SCSI_PORT_2,
+  SCSIPortPage2_t, MPI_POINTER pSCSIPortPage2_t;
+
+#define MPI_SCSIPORTPAGE2_PAGEVERSION                       (0x01)
+
+#define MPI_SCSIPORTPAGE2_PORT_FLAGS_SCAN_HIGH_TO_LOW       (0x00000001)
+#define MPI_SCSIPORTPAGE2_PORT_FLAGS_PARITY_ENABLE          (0x00000002)
+#define MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET       (0x00000004)
+#define MPI_SCSIPORTPAGE2_PORT_FLAGS_ALTERNATE_CHS          (0x00000008)
+#define MPI_SCSIPORTPAGE2_PORT_FLAGS_TERMINATION_DISABLE    (0x00000010)
+
+#define MPI_SCSIPORTPAGE2_PORT_HOST_ID_MASK                 (0x0000000F)
+#define MPI_SCSIPORTPAGE2_PORT_MASK_INIT_HBA                (0x00000030)
+#define MPI_SCSIPORTPAGE2_PORT_DISABLE_INIT_HBA             (0x00000000)
+#define MPI_SCSIPORTPAGE2_PORT_BIOS_INIT_HBA                (0x00000010)
+#define MPI_SCSIPORTPAGE2_PORT_OS_INIT_HBA                  (0x00000020)
+#define MPI_SCSIPORTPAGE2_PORT_BIOS_OS_INIT_HBA             (0x00000030)
+#define MPI_SCSIPORTPAGE2_PORT_REMOVABLE_MEDIA              (0x000000C0)
+#define MPI_SCSIPORTPAGE2_PORT_SPINUP_DELAY_MASK            (0x00000F00)
+#define MPI_SCSIPORTPAGE2_PORT_MASK_NEGO_MASTER_SETTINGS    (0x00003000)
+#define MPI_SCSIPORTPAGE2_PORT_NEGO_MASTER_SETTINGS         (0x00000000)
+#define MPI_SCSIPORTPAGE2_PORT_NONE_MASTER_SETTINGS         (0x00000001)
+#define MPI_SCSIPORTPAGE2_PORT_ALL_MASTER_SETTINGS          (0x00000003)
+
+#define MPI_SCSIPORTPAGE2_DEVICE_DISCONNECT_ENABLE          (0x00000001)
+#define MPI_SCSIPORTPAGE2_DEVICE_ID_SCAN_ENABLE             (0x00000002)
+#define MPI_SCSIPORTPAGE2_DEVICE_LUN_SCAN_ENABLE            (0x00000004)
+#define MPI_SCSIPORTPAGE2_DEVICE_TAG_QUEUE_ENABLE           (0x00000008)
+#define MPI_SCSIPORTPAGE2_DEVICE_WIDE_DISABLE               (0x00000010)
+#define MPI_SCSIPORTPAGE2_DEVICE_BOOT_CHOICE                (0x00000020)
+
+
+/****************************************************************************/
+/*  SCSI Target Device Config Pages                                         */
+/****************************************************************************/
+
+typedef struct _CONFIG_PAGE_SCSI_DEVICE_0
+{
+   fCONFIG_PAGE_HEADER      Header;
+    U32                     NegotiatedParameters;
+    U32                     Information;
+} fCONFIG_PAGE_SCSI_DEVICE_0, MPI_POINTER PTR_CONFIG_PAGE_SCSI_DEVICE_0,
+  SCSIDevicePage0_t, MPI_POINTER pSCSIDevicePage0_t;
+
+#define MPI_SCSIDEVPAGE0_PAGEVERSION                    (0x01)
+
+#define MPI_SCSIDEVPAGE0_NP_IU                          (0x00000001)
+#define MPI_SCSIDEVPAGE0_NP_DT                          (0x00000002)
+#define MPI_SCSIDEVPAGE0_NP_QAS                         (0x00000004)
+#define MPI_SCSIDEVPAGE0_NP_PACING_TRANSFERS            (0x00000008)
+#define MPI_SCSIDEVPAGE0_NP_NEG_SYNC_PERIOD_MASK        (0x0000FF00)
+#define MPI_SCSIDEVPAGE0_NP_NEG_SYNC_OFFSET_MASK        (0x00FF0000)
+#define MPI_SCSIDEVPAGE0_NP_WIDE                        (0x20000000)
+#define MPI_SCSIDEVPAGE0_NP_AIP                         (0x80000000)
+
+#define MPI_SCSIDEVPAGE0_INFO_PARAMS_NEGOTIATED         (0x00000001)
+
+typedef struct _CONFIG_PAGE_SCSI_DEVICE_1
+{
+   fCONFIG_PAGE_HEADER      Header;
+    U32                     RequestedParameters;
+    U32                     DomainValidation;
+    U32                     Configuration;
+} fCONFIG_PAGE_SCSI_DEVICE_1, MPI_POINTER PTR_CONFIG_PAGE_SCSI_DEVICE_1,
+  SCSIDevicePage1_t, MPI_POINTER pSCSIDevicePage1_t;
+
+#define MPI_SCSIDEVPAGE1_PAGEVERSION                    (0x01)
+
+#define MPI_SCSIDEVPAGE1_RP_IU                          (0x00000001)
+#define MPI_SCSIDEVPAGE1_RP_DT                          (0x00000002)
+#define MPI_SCSIDEVPAGE1_RP_QAS                         (0x00000004)
+#define MPI_SCSIDEVPAGE1_RP_PACING_TRANSFERS            (0x00000008)
+#define MPI_SCSIDEVPAGE1_RP_MIN_SYNC_PERIOD_MASK        (0x0000FF00)
+#define MPI_SCSIDEVPAGE1_RP_MAX_SYNC_OFFSET_MASK        (0x00FF0000)
+#define MPI_SCSIDEVPAGE1_RP_WIDE                        (0x20000000)
+#define MPI_SCSIDEVPAGE1_RP_AIP                         (0x80000000)
+
+#define MPI_SCSIDEVPAGE1_DV_LVD_DRIVE_STRENGTH_MASK     (0x00000003)
+#define MPI_SCSIDEVPAGE1_DV_SE_SLEW_RATE_MASK           (0x00000300)
+
+#define MPI_SCSIDEVPAGE1_CONF_PPR_ALLOWED               (0x00000001)
+
+/****************************************************************************/
+/*  FC Port Config Pages                                                    */
+/****************************************************************************/
+
+typedef struct _CONFIG_PAGE_FC_PORT_0
+{
+   fCONFIG_PAGE_HEADER      Header;
+    U32                     Flags;
+    U8                      MPIPortNumber;
+    U8                      LinkType;
+    U8                      PortState;
+    U8                      Reserved;
+    U32                     PortIdentifier;
+    U64                     WWNN;
+    U64                     WWPN;
+    U32                     SupportedServiceClass;
+    U32                     SupportedSpeeds;
+    U32                     CurrentSpeed;
+    U32                     MaxFrameSize;
+    U64                     FabricWWNN;
+    U64                     FabricWWPN;
+    U32                     DiscoveredPortsCount;
+    U32                     MaxInitiators;
+} fCONFIG_PAGE_FC_PORT_0, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_0,
+  FCPortPage0_t, MPI_POINTER pFCPortPage0_t;
+
+#define MPI_FCPORTPAGE0_PAGEVERSION                     (0x01)
+
+#define MPI_FCPORTPAGE0_FLAGS_PROT_MASK                 (0x0000000F)
+#define MPI_FCPORTPAGE0_FLAGS_PROT_FCP_INIT             (MPI_PORTFACTS_PROTOCOL_INITIATOR)
+#define MPI_FCPORTPAGE0_FLAGS_PROT_FCP_TARG             (MPI_PORTFACTS_PROTOCOL_TARGET)
+#define MPI_FCPORTPAGE0_FLAGS_PROT_LAN                  (MPI_PORTFACTS_PROTOCOL_LAN)
+#define MPI_FCPORTPAGE0_FLAGS_PROT_LOGBUSADDR           (MPI_PORTFACTS_PROTOCOL_LOGBUSADDR)
+
+#define MPI_FCPORTPAGE0_FLAGS_ALIAS_ALPA_SUPPORTED      (0x00000010)
+#define MPI_FCPORTPAGE0_FLAGS_ALIAS_WWN_SUPPORTED       (0x00000020)
+#define MPI_FCPORTPAGE0_FLAGS_FABRIC_WWN_VALID          (0x00000030)
+
+#define MPI_FCPORTPAGE0_FLAGS_ATTACH_TYPE_MASK          (0x00000700)
+#define MPI_FCPORTPAGE0_FLAGS_ATTACH_POINT_TO_POINT     (0x00000000)
+#define MPI_FCPORTPAGE0_FLAGS_ATTACH_PRIVATE_LOOP       (0x00000100)
+#define MPI_FCPORTPAGE0_FLAGS_ATTACH_FABRIC_DIRECT      (0x00000200)
+#define MPI_FCPORTPAGE0_FLAGS_ATTACH_PUBLIC_LOOP        (0x00000300)
+#define MPI_FCPORTPAGE0_FLAGS_ATTACH_NO_INIT            (0x00000700)
+
+#define MPI_FCPORTPAGE0_LTYPE_RESERVED                  (0x00)
+#define MPI_FCPORTPAGE0_LTYPE_OTHER                     (0x01)
+#define MPI_FCPORTPAGE0_LTYPE_UNKNOWN                   (0x02)
+#define MPI_FCPORTPAGE0_LTYPE_COPPER                    (0x03)
+#define MPI_FCPORTPAGE0_LTYPE_SINGLE_1300               (0x04)
+#define MPI_FCPORTPAGE0_LTYPE_SINGLE_1500               (0x05)
+#define MPI_FCPORTPAGE0_LTYPE_50_LASER_MULTI            (0x06)
+#define MPI_FCPORTPAGE0_LTYPE_50_LED_MULTI              (0x07)
+#define MPI_FCPORTPAGE0_LTYPE_62_LASER_MULTI            (0x08)
+#define MPI_FCPORTPAGE0_LTYPE_62_LED_MULTI              (0x09)
+#define MPI_FCPORTPAGE0_LTYPE_MULTI_LONG_WAVE           (0x0A)
+#define MPI_FCPORTPAGE0_LTYPE_MULTI_SHORT_WAVE          (0x0B)
+#define MPI_FCPORTPAGE0_LTYPE_LASER_SHORT_WAVE          (0x0C)
+#define MPI_FCPORTPAGE0_LTYPE_LED_SHORT_WAVE            (0x0D)
+#define MPI_FCPORTPAGE0_LTYPE_1300_LONG_WAVE            (0x0E)
+#define MPI_FCPORTPAGE0_LTYPE_1500_LONG_WAVE            (0x0F)
+
+#define MPI_FCPORTPAGE0_PORTSTATE_UNKNOWN               (0x01)      /*(SNIA)HBA_PORTSTATE_UNKNOWN       1 Unknown */
+#define MPI_FCPORTPAGE0_PORTSTATE_ONLINE                (0x02)      /*(SNIA)HBA_PORTSTATE_ONLINE        2 Operational */
+#define MPI_FCPORTPAGE0_PORTSTATE_OFFLINE               (0x03)      /*(SNIA)HBA_PORTSTATE_OFFLINE       3 User Offline */
+#define MPI_FCPORTPAGE0_PORTSTATE_BYPASSED              (0x04)      /*(SNIA)HBA_PORTSTATE_BYPASSED      4 Bypassed */
+#define MPI_FCPORTPAGE0_PORTSTATE_DIAGNOST              (0x05)      /*(SNIA)HBA_PORTSTATE_DIAGNOSTICS   5 In diagnostics mode */
+#define MPI_FCPORTPAGE0_PORTSTATE_LINKDOWN              (0x06)      /*(SNIA)HBA_PORTSTATE_LINKDOWN      6 Link Down */
+#define MPI_FCPORTPAGE0_PORTSTATE_ERROR                 (0x07)      /*(SNIA)HBA_PORTSTATE_ERROR         7 Port Error */
+#define MPI_FCPORTPAGE0_PORTSTATE_LOOPBACK              (0x08)      /*(SNIA)HBA_PORTSTATE_LOOPBACK      8 Loopback */
+
+#define MPI_FCPORTPAGE0_SUPPORT_CLASS_1                 (0x00000001)
+#define MPI_FCPORTPAGE0_SUPPORT_CLASS_2                 (0x00000002)
+#define MPI_FCPORTPAGE0_SUPPORT_CLASS_3                 (0x00000004)
+
+#define MPI_FCPORTPAGE0_SUPPORT_1GBIT_SPEED             (0x00000001) /* (SNIA)HBA_PORTSPEED_1GBIT 1  1 GBit/sec  */
+#define MPI_FCPORTPAGE0_SUPPORT_2GBIT_SPEED             (0x00000002) /* (SNIA)HBA_PORTSPEED_2GBIT 2  2 GBit/sec  */
+#define MPI_FCPORTPAGE0_SUPPORT_10GBIT_SPEED            (0x00000004) /* (SNIA)HBA_PORTSPEED_10GBIT 4 10 GBit/sec */
+
+#define MPI_FCPORTPAGE0_CURRENT_SPEED_1GBIT             MPI_FCPORTPAGE0_SUPPORT_1GBIT_SPEED
+#define MPI_FCPORTPAGE0_CURRENT_SPEED_2GBIT             MPI_FCPORTPAGE0_SUPPORT_2GBIT_SPEED
+#define MPI_FCPORTPAGE0_CURRENT_SPEED_10GBIT            MPI_FCPORTPAGE0_SUPPORT_10GBIT_SPEED
+
+
+typedef struct _CONFIG_PAGE_FC_PORT_1
+{
+   fCONFIG_PAGE_HEADER      Header;
+    U32                     Flags;
+    U64                     NoSEEPROMWWNN;
+    U64                     NoSEEPROMWWPN;
+    U8                      HardALPA;
+    U8                      LinkConfig;
+    U8                      TopologyConfig;
+    U8                      Reserved;
+} fCONFIG_PAGE_FC_PORT_1, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_1,
+  FCPortPage1_t, MPI_POINTER pFCPortPage1_t;
+
+#define MPI_FCPORTPAGE1_PAGEVERSION                     (0x01)
+
+#define MPI_FCPORTPAGE1_FLAGS_SORT_BY_DID               (0x00000001)
+#define MPI_FCPORTPAGE1_FLAGS_SORT_BY_WWN               (0x00000000)
+
+#define MPI_FCPORTPAGE1_FLAGS_PROT_MASK                 (0xF0000000)
+#define MPI_FCPORTPAGE1_FLAGS_PROT_SHIFT                (28)
+#define MPI_FCPORTPAGE1_FLAGS_PROT_FCP_INIT             ((U32)MPI_PORTFACTS_PROTOCOL_INITIATOR << MPI_FCPORTPAGE1_FLAGS_PROT_SHIFT)
+#define MPI_FCPORTPAGE1_FLAGS_PROT_FCP_TARG             ((U32)MPI_PORTFACTS_PROTOCOL_TARGET << MPI_FCPORTPAGE1_FLAGS_PROT_SHIFT)
+#define MPI_FCPORTPAGE1_FLAGS_PROT_LAN                  ((U32)MPI_PORTFACTS_PROTOCOL_LAN << MPI_FCPORTPAGE1_FLAGS_PROT_SHIFT)
+#define MPI_FCPORTPAGE1_FLAGS_PROT_LOGBUSADDR           ((U32)MPI_PORTFACTS_PROTOCOL_LOGBUSADDR << MPI_FCPORTPAGE1_FLAGS_PROT_SHIFT)
+
+#define MPI_FCPORTPAGE1_HARD_ALPA_NOT_USED              (0xFF)
+
+#define MPI_FCPORTPAGE1_LCONFIG_SPEED_MASK              (0x0F)
+#define MPI_FCPORTPAGE1_LCONFIG_SPEED_1GIG              (0x00)
+#define MPI_FCPORTPAGE1_LCONFIG_SPEED_2GIG              (0x01)
+#define MPI_FCPORTPAGE1_LCONFIG_SPEED_4GIG              (0x02)
+#define MPI_FCPORTPAGE1_LCONFIG_SPEED_10GIG             (0x03)
+#define MPI_FCPORTPAGE1_LCONFIG_SPEED_AUTO              (0x0F)
+
+#define MPI_FCPORTPAGE1_TOPOLGY_MASK                    (0x0F)
+#define MPI_FCPORTPAGE1_TOPOLGY_NLPORT                  (0x01)
+#define MPI_FCPORTPAGE1_TOPOLGY_NPORT                   (0x02)
+#define MPI_FCPORTPAGE1_TOPOLGY_AUTO                    (0x0F)
+
+
+typedef struct _CONFIG_PAGE_FC_PORT_2
+{
+   fCONFIG_PAGE_HEADER      Header;
+    U8                      NumberActive;
+    U8                      ALPA[126];
+    U8                      Reserved;
+} fCONFIG_PAGE_FC_PORT_2, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_2,
+  FCPortPage2_t, MPI_POINTER pFCPortPage2_t;
+
+#define MPI_FCPORTPAGE2_PAGEVERSION                     (0x00)
+
+
+typedef struct _FC_PORT_PERSISTENT
+{
+    U64                     WWNN;
+    U64                     WWPN;
+    U8                      TargetID;
+    U8                      Bus;
+    U16                     Flags;
+} FC_PORT_PERSISTENT, MPI_POINTER PTR_FC_PORT_PERSISTENT,
+  PersistentData_t, MPI_POINTER pPersistentData_t;
+
+#define MPI_PERSISTENT_FLAGS_SHIFT                      (16)
+#define MPI_PERSISTENT_FLAGS_ENTRY_VALID                (0x0001)
+#define MPI_PERSISTENT_FLAGS_SCAN_ID                    (0x0002)
+#define MPI_PERSISTENT_FLAGS_SCAN_LUNS                  (0x0004)
+#define MPI_PERSISTENT_FLAGS_BOOT_DEVICE                (0x0008)
+
+typedef struct _CONFIG_PAGE_FC_PORT_3
+{
+   fCONFIG_PAGE_HEADER      Header;
+    FC_PORT_PERSISTENT      Entry[1];
+} fCONFIG_PAGE_FC_PORT_3, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_3,
+  FCPortPage3_t, MPI_POINTER pFCPortPage3_t;
+
+#define MPI_FCPORTPAGE3_PAGEVERSION                     (0x00)
+
+
+typedef struct _CONFIG_PAGE_FC_PORT_4
+{
+   fCONFIG_PAGE_HEADER      Header;
+    U32                     PortFlags;
+    U32                     PortSettings;
+} fCONFIG_PAGE_FC_PORT_4, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_4,
+  FCPortPage4_t, MPI_POINTER pFCPortPage4_t;
+
+#define MPI_FCPORTPAGE4_PAGEVERSION                     (0x00)
+
+#define MPI_FCPORTPAGE4_PORT_FLAGS_ALTERNATE_CHS        (0x00000008)
+
+#define MPI_FCPORTPAGE4_PORT_MASK_INIT_HBA              (0x00000030)
+#define MPI_FCPORTPAGE4_PORT_DISABLE_INIT_HBA           (0x00000000)
+#define MPI_FCPORTPAGE4_PORT_BIOS_INIT_HBA              (0x00000010)
+#define MPI_FCPORTPAGE4_PORT_OS_INIT_HBA                (0x00000020)
+#define MPI_FCPORTPAGE4_PORT_BIOS_OS_INIT_HBA           (0x00000030)
+#define MPI_FCPORTPAGE4_PORT_REMOVABLE_MEDIA            (0x000000C0)
+#define MPI_FCPORTPAGE4_PORT_SPINUP_DELAY_MASK          (0x00000F00)
+
+
+typedef struct _CONFIG_PAGE_FC_PORT_5_ALIAS_INFO
+{
+    U8      Flags;
+    U8      AliasAlpa;
+    U16     Reserved;
+    U64     AliasWWNN;
+    U64     AliasWWPN;
+} fCONFIG_PAGE_FC_PORT_5_ALIAS_INFO, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_5_ALIAS_INFO,
+  FcPortPage5AliasInfo_t, MPI_POINTER pFcPortPage5AliasInfo_t;
+
+typedef struct _CONFIG_PAGE_FC_PORT_5
+{
+   fCONFIG_PAGE_HEADER                  Header;
+   fCONFIG_PAGE_FC_PORT_5_ALIAS_INFO    AliasInfo[1];
+} fCONFIG_PAGE_FC_PORT_5, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_5,
+  FCPortPage5_t, MPI_POINTER pFCPortPage5_t;
+
+#define MPI_FCPORTPAGE5_PAGEVERSION                     (0x00)
+
+#define MPI_FCPORTPAGE5_FLAGS_ALIAS_ALPA_VALID          (0x01)
+#define MPI_FCPORTPAGE5_FLAGS_ALIAS_WWN_VALID           (0x02)
+
+
+typedef struct _CONFIG_PAGE_FC_PORT_6
+{
+   fCONFIG_PAGE_HEADER      Header;
+    U32                     Reserved;
+    U64                     TimeSinceReset;
+    U64                     TxFrames;
+    U64                     RxFrames;
+    U64                     TxWords;
+    U64                     RxWords;
+    U64                     LipCount;
+    U64                     NosCount;
+    U64                     ErrorFrames;
+    U64                     DumpedFrames;
+    U64                     LinkFailureCount;
+    U64                     LossOfSyncCount;
+    U64                     LossOfSignalCount;
+    U64                     PrimativeSeqErrCount;
+    U64                     InvalidTxWordCount;
+    U64                     InvalidCrcCount;
+    U64                     FcpInitiatorIoCount;
+} fCONFIG_PAGE_FC_PORT_6, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_6,
+  FCPortPage6_t, MPI_POINTER pFCPortPage6_t;
+
+#define MPI_FCPORTPAGE6_PAGEVERSION                     (0x00)
+
+
+typedef struct _CONFIG_PAGE_FC_PORT_7
+{
+   fCONFIG_PAGE_HEADER      Header;
+    U32                     Reserved;
+    U8                      PortSymbolicName[256];
+} fCONFIG_PAGE_FC_PORT_7, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_7,
+  FCPortPage7_t, MPI_POINTER pFCPortPage7_t;
+
+#define MPI_FCPORTPAGE7_PAGEVERSION                     (0x00)
+
+
+/****************************************************************************/
+/*  FC Device Config Pages                                                  */
+/****************************************************************************/
+
+typedef struct _CONFIG_PAGE_FC_DEVICE_0
+{
+   fCONFIG_PAGE_HEADER      Header;
+    U64                     WWNN;
+    U64                     WWPN;
+    U32                     PortIdentifier;
+    U8                      Protocol;
+    U8                      Flags;
+    U16                     BBCredit;
+    U16                     MaxRxFrameSize;
+    U8                      Reserved1;
+    U8                      PortNumber;
+    U8                      FcPhLowestVersion;
+    U8                      FcPhHighestVersion;
+    U8                      CurrentTargetID;
+    U8                      CurrentBus;
+} fCONFIG_PAGE_FC_DEVICE_0, MPI_POINTER PTR_CONFIG_PAGE_FC_DEVICE_0,
+  FCDevicePage0_t, MPI_POINTER pFCDevicePage0_t;
+
+#define MPI_FC_DEVICE_PAGE0_PAGEVERSION                 (0x02)
+
+#define MPI_FC_DEVICE_PAGE0_FLAGS_TARGETID_BUS_VALID    (0x01)
+
+#define MPI_FC_DEVICE_PAGE0_PROT_IP                     (0x01)
+#define MPI_FC_DEVICE_PAGE0_PROT_FCP_TARGET             (0x02)
+#define MPI_FC_DEVICE_PAGE0_PROT_FCP_INITIATOR          (0x04)
+
+#define MPI_FC_DEVICE_PAGE0_PGAD_PORT_MASK              (MPI_FC_DEVICE_PGAD_PORT_MASK)
+#define MPI_FC_DEVICE_PAGE0_PGAD_FORM_MASK              (MPI_FC_DEVICE_PGAD_FORM_MASK)
+#define MPI_FC_DEVICE_PAGE0_PGAD_FORM_NEXT_DID          (MPI_FC_DEVICE_PGAD_FORM_NEXT_DID)
+#define MPI_FC_DEVICE_PAGE0_PGAD_FORM_BUS_TID           (MPI_FC_DEVICE_PGAD_FORM_BUS_TID)
+#define MPI_FC_DEVICE_PAGE0_PGAD_DID_MASK               (MPI_FC_DEVICE_PGAD_ND_DID_MASK)
+#define MPI_FC_DEVICE_PAGE0_PGAD_BUS_MASK               (MPI_FC_DEVICE_PGAD_BT_BUS_MASK)
+#define MPI_FC_DEVICE_PAGE0_PGAD_BUS_SHIFT              (MPI_FC_DEVICE_PGAD_BT_BUS_SHIFT)
+#define MPI_FC_DEVICE_PAGE0_PGAD_TID_MASK               (MPI_FC_DEVICE_PGAD_BT_TID_MASK)
+
+
+/****************************************************************************/
+/*  RAID Volume Config Pages                                                  */
+/****************************************************************************/
+
+typedef struct _RAIDVOL2_EM_PHYS_ID
+{
+    U8                      TargetID;
+    U8                      Bus;
+    U8                      IocNumber;
+    U8                      PhysDiskNumber;
+    U8                      Reserved[8];
+    U8                      PhysicalDiskIdentifier[16];
+    U8                      ProductId[16];
+    U8                      InfoOffset0;
+    U8                      InfoSize0;
+    U8                      InfoOffset1;
+    U8                      InfoSize1;
+    U8                      Info[32];
+} RAIDVOL2_EM_PHYS_ID, MPI_POINTER PTR_RAIDVOL2_EM_PHYS_ID,
+  RaidVol2EmPhysicalID_t, MPI_POINTER pRaidVol2EmPhysicalID_t;
+
+typedef struct _RAIDVOL2_EM_DISK_INFO
+{
+    U32                     DiskStatus;
+    U32                     DeviceSettings;
+    U16                     ErrorCount;
+    U16                     Reserved;
+    U8                      ErrorCdbByte;
+    U8                      ErrorSenseKey;
+    U8                      ErrorASC;
+    U8                      ErrorASCQ;
+    U16                     SmartCount;
+    U8                      SmartASC;
+    U8                      SmartASCQ;
+} RAIDVOL2_EM_DISK_INFO, MPI_POINTER PTR_RAIDVOL2_EM_DISK_INFO,
+  RaidVol2EmDiskInfo_t, MPI_POINTER pRaidVol2EmDiskInfo_t;
+
+/* RAID Volume 2 EM Physical Disk DiskStatus flags */
+
+#define MPI_RAIDVOLPAGE2_PHYS_DISK_PRIMARY              (0x00000001)
+#define MPI_RAIDVOLPAGE2_PHYS_DISK_SECONDARY            (0x00000002)
+#define MPI_RAIDVOLPAGE2_PHYS_DISK_HOT_SPARE            (0x00000004)
+#define MPI_RAIDVOLPAGE2_PHYS_DISK_OUT_OF_SYNC          (0x00000008)
+#define MPI_RAIDVOLPAGE2_PHYS_DISK_OFFLINE              (0x00000010)
+#define MPI_RAIDVOLPAGE2_PHYS_DISK_NOT_RESPONDING       (0x00000020)
+
+typedef struct _RAIDVOL2_EM_PHYSICAL_DISK
+{
+    RAIDVOL2_EM_PHYS_ID     Id;
+    RAIDVOL2_EM_DISK_INFO   Info;
+} RAIDVOL2_EM_PHYSICAL_DISK, MPI_POINTER PTR_RAIDVOL2_EM_PHYSICAL_DISK,
+  RaidVol2EmPhysicalDisk_t, MPI_POINTER pRaidVol2EmPhysicalDisk_t;
+
+#define MPI_RAIDVOLPAGE2_MAX_DISKS                      (3)
+
+typedef struct _CONFIG_PAGE_RAID_VOL_2
+{
+   fCONFIG_PAGE_HEADER          Header;
+    U32                         VolumeStatus;
+    U32                         VolumeSettings;
+    U32                         Reserved;
+    U64                         MaxLba;
+    U32                         BlockSize;
+    U8                          InquirySize;
+    U8                          NumPhysicalDisks;
+    U16                         Reserved1;
+    U8                          InquiryData[56];
+    RAIDVOL2_EM_PHYSICAL_DISK   EMPhysicalDisk[MPI_RAIDVOLPAGE2_MAX_DISKS];
+} fCONFIG_PAGE_RAID_VOL_2, MPI_POINTER PTR_CONFIG_PAGE_RAID_VOL_2,
+  RaidVolumePage2_t, MPI_POINTER pRaidVolumePage2_t;
+
+#define MPI_RAIDVOLPAGE2_PAGEVERSION                    (0x00)
+
+/* RAID Volume Page 2 VolumeStatus defines */
+
+#define MPI_RAIDVOLPAGE2_STATUS_ENABLED                 (0x00000001)
+#define MPI_RAIDVOLPAGE2_STATUS_QUIESCED                (0x00000002)
+#define MPI_RAIDVOLPAGE2_STATUS_RESYNC_IN_PROGRESS      (0x00000004)
+#define MPI_RAIDVOLPAGE2_STATUS_DEGRADED                (0x00000008)
+
+/* RAID Volume Page 2 VolumeSettings defines */
+
+#define MPI_RAIDVOLPAGE2_SETTING_WRITE_CACHING_ENABLE   (0x00000001)
+#define MPI_RAIDVOLPAGE2_SETTING_OFFLINE_ON_SMART       (0x00000002)
+#define MPI_RAIDVOLPAGE2_SETTING_AUTO_CONFIGURE         (0x00000004)
+
+
+/****************************************************************************/
+/* LAN Config Pages                                                         */
+/****************************************************************************/
+
+typedef struct _CONFIG_PAGE_LAN_0
+{
+    ConfigPageHeader_t      Header;
+    U16                     TxRxModes;
+    U16                     Reserved;
+    U32                     PacketPrePad;
+} fCONFIG_PAGE_LAN_0, MPI_POINTER PTR_CONFIG_PAGE_LAN_0,
+  LANPage0_t, MPI_POINTER pLANPage0_t;
+
+#define MPI_LAN_PAGE0_PAGEVERSION                       (0x01)
+
+#define MPI_LAN_PAGE0_RETURN_LOOPBACK                   (0x0000)
+#define MPI_LAN_PAGE0_SUPPRESS_LOOPBACK                 (0x0001)
+#define MPI_LAN_PAGE0_LOOPBACK_MASK                     (0x0001)
+
+typedef struct _CONFIG_PAGE_LAN_1
+{
+    ConfigPageHeader_t      Header;
+    U16                     Reserved;
+    U8                      CurrentDeviceState;
+    U8                      Reserved1;
+    U32                     MinPacketSize;
+    U32                     MaxPacketSize;
+    U32                     HardwareAddressLow;
+    U32                     HardwareAddressHigh;
+    U32                     MaxWireSpeedLow;
+    U32                     MaxWireSpeedHigh;
+    U32                     BucketsRemaining;
+    U32                     MaxReplySize;
+    U32                     NegWireSpeedHigh;
+    U32                     NegWireSpeedLow;
+} fCONFIG_PAGE_LAN_1, MPI_POINTER PTR_CONFIG_PAGE_LAN_1,
+  LANPage1_t, MPI_POINTER pLANPage1_t;
+
+#define MPI_LAN_PAGE1_PAGEVERSION                       (0x03)
+
+#define MPI_LAN_PAGE1_DEV_STATE_RESET                   (0x00)
+#define MPI_LAN_PAGE1_DEV_STATE_OPERATIONAL             (0x01)
+
+#endif
+
diff --git a/drivers/message/fusion/lsi/mpi_fc.h b/drivers/message/fusion/lsi/mpi_fc.h
new file mode 100644 (file)
index 0000000..73d17d2
--- /dev/null
@@ -0,0 +1,350 @@
+/*
+ *  Copyright (c) 2000-2001 LSI Logic Corporation.
+ *
+ *
+ *           Name:  MPI_FC.H
+ *          Title:  MPI Fibre Channel messages and structures
+ *  Creation Date:  June 12, 2000
+ *
+ *    MPI Version:  01.01.05
+ *
+ *  Version History
+ *  ---------------
+ *
+ *  Date      Version   Description
+ *  --------  --------  ------------------------------------------------------
+ *  05-08-00  00.10.01  Original release for 0.10 spec dated 4/26/2000.
+ *  06-06-00  01.00.01  Update version number for 1.0 release.
+ *  06-12-00  01.00.02  Added _MSG_FC_ABORT_REPLY structure.
+ *  11-02-00  01.01.01  Original release for post 1.0 work
+ *  12-04-00  01.01.02  Added messages for Common Transport Send and
+ *                      Primitive Send.
+ *  01-09-01  01.01.03  Modifed some of the new flags to have an MPI prefix
+ *                      and modified the FcPrimitiveSend flags.
+ *  01-25-01  01.01.04  Move InitiatorIndex in LinkServiceRsp reply to a larger
+ *                      field.
+ *                      Added FC_ABORT_TYPE_CT_SEND_REQUEST and
+ *                      FC_ABORT_TYPE_EXLINKSEND_REQUEST for FcAbort request.
+ *                      Added MPI_FC_PRIM_SEND_FLAGS_STOP_SEND.
+ *  02-20-01  01.01.05  Started using MPI_POINTER.
+ *  --------------------------------------------------------------------------
+ */
+
+#ifndef MPI_FC_H
+#define MPI_FC_H
+
+
+/*****************************************************************************
+*
+*        F C    T a r g e t    M o d e    M e s s a g e s
+*
+*****************************************************************************/
+
+/****************************************************************************/
+/* Link Service Buffer Post messages                                        */
+/****************************************************************************/
+
+typedef struct _MSG_LINK_SERVICE_BUFFER_POST_REQUEST
+{
+    U8                      BufferPostFlags;    /* 00h */
+    U8                      BufferCount;        /* 01h */
+    U8                      ChainOffset;        /* 02h */
+    U8                      Function;           /* 03h */
+    U16                     Reserved;           /* 04h */
+    U8                      Reserved1;          /* 06h */
+    U8                      MsgFlags;           /* 07h */
+    U32                     MsgContext;         /* 08h */
+    SGE_TRANS_SIMPLE_UNION  SGL;
+} MSG_LINK_SERVICE_BUFFER_POST_REQUEST,
+ MPI_POINTER PTR_MSG_LINK_SERVICE_BUFFER_POST_REQUEST,
+  LinkServiceBufferPostRequest_t, MPI_POINTER pLinkServiceBufferPostRequest_t;
+
+#define LINK_SERVICE_BUFFER_POST_FLAGS_PORT_MASK (0x01)
+
+typedef struct _WWNFORMAT
+{
+    U32                     PortNameHigh;       /* 00h */
+    U32                     PortNameLow;        /* 04h */
+    U32                     NodeNameHigh;       /* 08h */
+    U32                     NodeNameLow;        /* 0Ch */
+} WWNFORMAT,
+  WwnFormat_t;
+
+/* Link Service Buffer Post Reply */
+typedef struct _MSG_LINK_SERVICE_BUFFER_POST_REPLY
+{
+    U8                      Flags;              /* 00h */
+    U8                      Reserved;           /* 01h */
+    U8                      MsgLength;          /* 02h */
+    U8                      Function;           /* 03h */
+    U16                     Reserved1;          /* 04h */
+    U8                      PortNumber;         /* 06h */
+    U8                      MsgFlags;           /* 07h */
+    U32                     MsgContext;         /* 08h */
+    U16                     Reserved2;          /* 0Ch */
+    U16                     IOCStatus;          /* 0Eh */
+    U32                     IOCLogInfo;         /* 10h */
+    U32                     TransferLength;     /* 14h */
+    U32                     TransactionContext; /* 18h */
+    U32                     Rctl_Did;           /* 1Ch */
+    U32                     Csctl_Sid;          /* 20h */
+    U32                     Type_Fctl;          /* 24h */
+    U16                     SeqCnt;             /* 28h */
+    U8                      Dfctl;              /* 2Ah */
+    U8                      SeqId;              /* 2Bh */
+    U16                     Rxid;               /* 2Ch */
+    U16                     Oxid;               /* 2Eh */
+    U32                     Parameter;          /* 30h */
+    WWNFORMAT               Wwn;                /* 34h */
+} MSG_LINK_SERVICE_BUFFER_POST_REPLY, MPI_POINTER PTR_MSG_LINK_SERVICE_BUFFER_POST_REPLY,
+  LinkServiceBufferPostReply_t, MPI_POINTER pLinkServiceBufferPostReply_t;
+
+#define MPI_LS_BUF_POST_REPLY_FLAG_NO_RSP_NEEDED    (0x80)
+
+#define MPI_FC_DID_MASK                             (0x00FFFFFF)
+#define MPI_FC_DID_SHIFT                            (0)
+#define MPI_FC_RCTL_MASK                            (0xFF000000)
+#define MPI_FC_RCTL_SHIFT                           (24)
+#define MPI_FC_SID_MASK                             (0x00FFFFFF)
+#define MPI_FC_SID_SHIFT                            (0)
+#define MPI_FC_CSCTL_MASK                           (0xFF000000)
+#define MPI_FC_CSCTL_SHIFT                          (24)
+#define MPI_FC_FCTL_MASK                            (0x00FFFFFF)
+#define MPI_FC_FCTL_SHIFT                           (0)
+#define MPI_FC_TYPE_MASK                            (0xFF000000)
+#define MPI_FC_TYPE_SHIFT                           (24)
+
+/* obsolete name for the above */
+#define FCP_TARGET_DID_MASK                         (0x00FFFFFF)
+#define FCP_TARGET_DID_SHIFT                        (0)
+#define FCP_TARGET_RCTL_MASK                        (0xFF000000)
+#define FCP_TARGET_RCTL_SHIFT                       (24)
+#define FCP_TARGET_SID_MASK                         (0x00FFFFFF)
+#define FCP_TARGET_SID_SHIFT                        (0)
+#define FCP_TARGET_CSCTL_MASK                       (0xFF000000)
+#define FCP_TARGET_CSCTL_SHIFT                      (24)
+#define FCP_TARGET_FCTL_MASK                        (0x00FFFFFF)
+#define FCP_TARGET_FCTL_SHIFT                       (0)
+#define FCP_TARGET_TYPE_MASK                        (0xFF000000)
+#define FCP_TARGET_TYPE_SHIFT                       (24)
+
+
+/****************************************************************************/
+/* Link Service Response messages                                           */
+/****************************************************************************/
+
+typedef struct _MSG_LINK_SERVICE_RSP_REQUEST
+{
+    U8                      RspFlags;           /* 00h */
+    U8                      Reserved;           /* 01h */
+    U8                      ChainOffset;        /* 02h */
+    U8                      Function;           /* 03h */
+    U16                     Reserved1;          /* 04h */
+    U8                      Reserved2;          /* 06h */
+    U8                      MsgFlags;           /* 07h */
+    U32                     MsgContext;         /* 08h */
+    U32                     Rctl_Did;           /* 0Ch */
+    U32                     Csctl_Sid;          /* 10h */
+    U32                     Type_Fctl;          /* 14h */
+    U16                     SeqCnt;             /* 18h */
+    U8                      Dfctl;              /* 1Ah */
+    U8                      SeqId;              /* 1Bh */
+    U16                     Rxid;               /* 1Ch */
+    U16                     Oxid;               /* 1Eh */
+    U32                     Parameter;          /* 20h */
+    SGE_SIMPLE_UNION        SGL;                /* 24h */
+} MSG_LINK_SERVICE_RSP_REQUEST, MPI_POINTER PTR_MSG_LINK_SERVICE_RSP_REQUEST,
+  LinkServiceRspRequest_t, MPI_POINTER pLinkServiceRspRequest_t;
+
+#define LINK_SERVICE_RSP_FLAGS_IMMEDIATE        (0x80)
+#define LINK_SERVICE_RSP_FLAGS_PORT_MASK        (0x01)
+
+
+/* Link Service Response Reply  */
+typedef struct _MSG_LINK_SERVICE_RSP_REPLY
+{
+    U16                     Reserved;           /* 00h */
+    U8                      MsgLength;          /* 02h */
+    U8                      Function;           /* 03h */
+    U16                     Reserved1;          /* 04h */
+    U8                      Reserved2;          /* 06h */
+    U8                      MsgFlags;           /* 07h */
+    U32                     MsgContext;         /* 08h */
+    U16                     Reserved3;          /* 0Ch */
+    U16                     IOCStatus;          /* 0Eh */
+    U32                     IOCLogInfo;         /* 10h */
+    U32                     InitiatorIndex;     /* 14h */
+} MSG_LINK_SERVICE_RSP_REPLY, MPI_POINTER PTR_MSG_LINK_SERVICE_RSP_REPLY,
+  LinkServiceRspReply_t, MPI_POINTER pLinkServiceRspReply_t;
+
+
+/****************************************************************************/
+/* Extended Link Service Send messages                                      */
+/****************************************************************************/
+
+typedef struct _MSG_EXLINK_SERVICE_SEND_REQUEST
+{
+    U8                      SendFlags;          /* 00h */
+    U8                      Reserved;           /* 01h */
+    U8                      ChainOffset;        /* 02h */
+    U8                      Function;           /* 03h */
+    U32                     MsgFlags_Did;       /* 04h */
+    U32                     MsgContext;         /* 08h */
+    U32                     ElsCommandCode;     /* 0Ch */
+    SGE_SIMPLE_UNION        SGL;                /* 10h */
+} MSG_EXLINK_SERVICE_SEND_REQUEST, MPI_POINTER PTR_MSG_EXLINK_SERVICE_SEND_REQUEST,
+  ExLinkServiceSendRequest_t, MPI_POINTER pExLinkServiceSendRequest_t;
+
+#define EX_LINK_SERVICE_SEND_DID_MASK           (0x00FFFFFF)
+#define EX_LINK_SERVICE_SEND_DID_SHIFT          (0)
+#define EX_LINK_SERVICE_SEND_MSGFLAGS_MASK      (0xFF000000)
+#define EX_LINK_SERVICE_SEND_MSGFLAGS_SHIFT     (24)
+
+
+/* Extended Link Service Send Reply */
+typedef struct _MSG_EXLINK_SERVICE_SEND_REPLY
+{
+    U16                     Reserved;           /* 00h */
+    U8                      MsgLength;          /* 02h */
+    U8                      Function;           /* 03h */
+    U16                     Reserved1;          /* 04h */
+    U8                      Reserved2;          /* 06h */
+    U8                      MsgFlags;           /* 07h */
+    U32                     MsgContext;         /* 08h */
+    U16                     Reserved3;          /* 0Ch */
+    U16                     IOCStatus;          /* 0Eh */
+    U32                     IOCLogInfo;         /* 10h */
+    U32                     ResponseLength;     /* 14h */
+} MSG_EXLINK_SERVICE_SEND_REPLY, MPI_POINTER PTR_MSG_EXLINK_SERVICE_SEND_REPLY,
+  ExLinkServiceSendReply_t, MPI_POINTER pExLinkServiceSendReply_t;
+
+/****************************************************************************/
+/* FC Abort messages                                                        */
+/****************************************************************************/
+
+typedef struct _MSG_FC_ABORT_REQUEST
+{
+    U8                      AbortFlags;         /* 00h */
+    U8                      AbortType;          /* 01h */
+    U8                      ChainOffset;        /* 02h */
+    U8                      Function;           /* 03h */
+    U16                     Reserved1;          /* 04h */
+    U8                      Reserved2;          /* 06h */
+    U8                      MsgFlags;           /* 07h */
+    U32                     MsgContext;         /* 08h */
+    U32                     TransactionContextToAbort;  /* 0Ch */
+} MSG_FC_ABORT_REQUEST, MPI_POINTER PTR_MSG_FC_ABORT_REQUEST,
+  FcAbortRequest_t, MPI_POINTER pFcAbortRequest_t;
+
+#define FC_ABORT_FLAG_PORT_MASK                 (0x01)
+
+#define FC_ABORT_TYPE_ALL_FC_BUFFERS            (0x00)
+#define FC_ABORT_TYPE_EXACT_FC_BUFFER           (0x01)
+#define FC_ABORT_TYPE_CT_SEND_REQUEST           (0x02)
+#define FC_ABORT_TYPE_EXLINKSEND_REQUEST        (0x03)
+
+/* FC Abort Reply */
+typedef struct _MSG_FC_ABORT_REPLY
+{
+    U16                     Reserved;           /* 00h */
+    U8                      MsgLength;          /* 02h */
+    U8                      Function;           /* 03h */
+    U16                     Reserved1;          /* 04h */
+    U8                      Reserved2;          /* 06h */
+    U8                      MsgFlags;           /* 07h */
+    U32                     MsgContext;         /* 08h */
+    U16                     Reserved3;          /* 0Ch */
+    U16                     IOCStatus;          /* 0Eh */
+    U32                     IOCLogInfo;         /* 10h */
+} MSG_FC_ABORT_REPLY, MPI_POINTER PTR_MSG_FC_ABORT_REPLY,
+  FcAbortReply_t, MPI_POINTER pFcAbortReply_t;
+
+
+/****************************************************************************/
+/* FC Common Transport Send messages                                        */
+/****************************************************************************/
+
+typedef struct _MSG_FC_COMMON_TRANSPORT_SEND_REQUEST
+{
+    U8                      SendFlags;          /* 00h */
+    U8                      Reserved;           /* 01h */
+    U8                      ChainOffset;        /* 02h */
+    U8                      Function;           /* 03h */
+    U32                     MsgFlags_Did;       /* 04h */
+    U32                     MsgContext;         /* 08h */
+    U16                     CTCommandCode;      /* 0Ch */
+    U8                      FsType;             /* 0Eh */
+    U8                      Reserved1;          /* 0Fh */
+    SGE_SIMPLE_UNION        SGL;                /* 10h */
+} MSG_FC_COMMON_TRANSPORT_SEND_REQUEST,
+ MPI_POINTER PTR_MSG_FC_COMMON_TRANSPORT_SEND_REQUEST,
+  FcCommonTransportSendRequest_t, MPI_POINTER pFcCommonTransportSendRequest_t;
+
+#define MPI_FC_CT_SEND_DID_MASK                 (0x00FFFFFF)
+#define MPI_FC_CT_SEND_DID_SHIFT                (0)
+#define MPI_FC_CT_SEND_MSGFLAGS_MASK            (0xFF000000)
+#define MPI_FC_CT_SEND_MSGFLAGS_SHIFT           (24)
+
+
+/* FC Common Transport Send Reply */
+typedef struct _MSG_FC_COMMON_TRANSPORT_SEND_REPLY
+{
+    U16                     Reserved;           /* 00h */
+    U8                      MsgLength;          /* 02h */
+    U8                      Function;           /* 03h */
+    U16                     Reserved1;          /* 04h */
+    U8                      Reserved2;          /* 06h */
+    U8                      MsgFlags;           /* 07h */
+    U32                     MsgContext;         /* 08h */
+    U16                     Reserved3;          /* 0Ch */
+    U16                     IOCStatus;          /* 0Eh */
+    U32                     IOCLogInfo;         /* 10h */
+    U32                     ResponseLength;     /* 14h */
+} MSG_FC_COMMON_TRANSPORT_SEND_REPLY, MPI_POINTER PTR_MSG_FC_COMMON_TRANSPORT_SEND_REPLY,
+  FcCommonTransportSendReply_t, MPI_POINTER pFcCommonTransportSendReply_t;
+
+
+/****************************************************************************/
+/* FC Primitive Send messages                                               */
+/****************************************************************************/
+
+typedef struct _MSG_FC_PRIMITIVE_SEND_REQUEST
+{
+    U8                      SendFlags;          /* 00h */
+    U8                      Reserved;           /* 01h */
+    U8                      ChainOffset;        /* 02h */
+    U8                      Function;           /* 03h */
+    U16                     Reserved1;          /* 04h */
+    U8                      Reserved2;          /* 06h */
+    U8                      MsgFlags;           /* 07h */
+    U32                     MsgContext;         /* 08h */
+    U8                      FcPrimitive[4];     /* 0Ch */
+} MSG_FC_PRIMITIVE_SEND_REQUEST, MPI_POINTER PTR_MSG_FC_PRIMITIVE_SEND_REQUEST,
+  FcPrimitiveSendRequest_t, MPI_POINTER pFcPrimitiveSendRequest_t;
+
+#define MPI_FC_PRIM_SEND_FLAGS_PORT_MASK       (0x01)
+#define MPI_FC_PRIM_SEND_FLAGS_STOP_SEND       (0x08)
+#define MPI_FC_PRIM_SEND_FLAGS_SEND_ONCE       (0x10)
+#define MPI_FC_PRIM_SEND_FLAGS_SEND_AROUND     (0x20)
+#define MPI_FC_PRIM_SEND_FLAGS_UNTIL_FULL      (0x40)
+#define MPI_FC_PRIM_SEND_FLAGS_FOREVER         (0x80)
+
+/* FC Primitive Send Reply */
+typedef struct _MSG_FC_PRIMITIVE_SEND_REPLY
+{
+    U8                      SendFlags;          /* 00h */
+    U8                      Reserved;           /* 01h */
+    U8                      MsgLength;          /* 02h */
+    U8                      Function;           /* 03h */
+    U16                     Reserved1;          /* 04h */
+    U8                      Reserved2;          /* 06h */
+    U8                      MsgFlags;           /* 07h */
+    U32                     MsgContext;         /* 08h */
+    U16                     Reserved3;          /* 0Ch */
+    U16                     IOCStatus;          /* 0Eh */
+    U32                     IOCLogInfo;         /* 10h */
+} MSG_FC_PRIMITIVE_SEND_REPLY, MPI_POINTER PTR_MSG_FC_PRIMITIVE_SEND_REPLY,
+  FcPrimitiveSendReply_t, MPI_POINTER pFcPrimitiveSendReply_t;
+
+#endif
+
diff --git a/drivers/message/fusion/lsi/mpi_history.txt b/drivers/message/fusion/lsi/mpi_history.txt
new file mode 100644 (file)
index 0000000..5ac3e06
--- /dev/null
@@ -0,0 +1,237 @@
+
+ ==============================
+ MPI Header File Change History
+ ==============================
+
+ Copyright (c) 2000-2001 LSI Logic Corporation.
+
+ ---------------------------------------
+ Header Set Release Version:    01.01.08
+ Header Set Release Date:       02-27-01
+ ---------------------------------------
+
+ Filename               Current version     Prior version
+ ----------             ---------------     -------------
+ mpi.h                  01.01.06            01.01.05
+ mpi_ioc.h              01.01.05            01.01.04
+ mpi_cnfg.h             01.01.09            01.01.08
+ mpi_init.h             01.01.03            01.01.03
+ mpi_targ.h             01.01.03            01.01.03
+ mpi_fc.h               01.01.05            01.01.05
+ mpi_lan.h              01.01.02            01.01.02
+ mpi_raid.h             01.01.01            none
+ mpi_type.h             01.01.02            01.01.02
+ mpi_history.txt        01.01.08            01.01.07
+
+
+ *  Date      Version   Description
+ *  --------  --------  ------------------------------------------------------
+
+mpi.h
+ *  05-08-00  00.10.01  Original release for 0.10 spec dated 4/26/2000.
+ *  05-24-00  00.10.02  Added MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH definition.
+ *  06-06-00  01.00.01  Update MPI_VERSION_MAJOR and MPI_VERSION_MINOR.
+ *  06-22-00  01.00.02  Added MPI_IOCSTATUS_LAN_ definitions.
+ *                      Removed LAN_SUSPEND function definition.
+ *                      Added MPI_MSGFLAGS_CONTINUATION_REPLY definition.
+ *  06-30-00  01.00.03  Added MPI_CONTEXT_REPLY_TYPE_LAN definition.
+ *                      Added MPI_GET/SET_CONTEXT_REPLY_TYPE macros.
+ *  07-27-00  01.00.04  Added MPI_FAULT_ definitions.
+ *                      Removed MPI_IOCSTATUS_MSG/DATA_XFER_ERROR definitions.
+ *                      Added MPI_IOCSTATUS_INTERNAL_ERROR definition.
+ *                      Added MPI_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH.
+ *  11-02-00  01.01.01  Original release for post 1.0 work
+ *  12-04-00  01.01.02  Added new function codes.
+ *  01-09-01  01.01.03  Added more definitions to the system interface section
+ *                      Added MPI_IOCSTATUS_TARGET_STS_DATA_NOT_SENT.
+ *  01-25-01  01.01.04  Changed MPI_VERSION_MINOR from 0x00 to 0x01.
+ *  02-20-01  01.01.05  Started using MPI_POINTER.
+ *                      Added defines for MPI_DIAG_PREVENT_IOC_BOOT and
+ *                      MPI_DIAG_CLEAR_FLASH_BAD_SIG.
+ *                      Obsoleted MPI_IOCSTATUS_TARGET_FC_ defines.
+ *  02-27-01  01.01.06  Removed MPI_HOST_INDEX_REGISTER define.
+ *                      Added function codes for RAID.
+ *  --------------------------------------------------------------------------
+
+mpi_ioc.h
+ *  05-08-00  00.10.01  Original release for 0.10 spec dated 4/26/2000.
+ *  05-24-00  00.10.02  Added _MSG_IOC_INIT_REPLY structure.
+ *  06-06-00  01.00.01  Added CurReplyFrameSize field to _MSG_IOC_FACTS_REPLY.
+ *  06-12-00  01.00.02  Added _MSG_PORT_ENABLE_REPLY structure.
+ *                      Added _MSG_EVENT_ACK_REPLY structure.
+ *                      Added _MSG_FW_DOWNLOAD_REPLY structure.
+ *                      Added _MSG_TOOLBOX_REPLY structure.
+ *  06-30-00  01.00.03  Added MaxLanBuckets to _PORT_FACT_REPLY structure.
+ *  07-27-00  01.00.04  Added _EVENT_DATA structure definitions for _SCSI,
+ *                      _LINK_STATUS, _LOOP_STATE and _LOGOUT.
+ *  08-11-00  01.00.05  Switched positions of MsgLength and Function fields in
+ *                      _MSG_EVENT_ACK_REPLY structure to match specification.
+ *  11-02-00  01.01.01  Original release for post 1.0 work
+ *                      Added a value for Manufacturer to WhoInit
+ *  12-04-00  01.01.02  Modified IOCFacts reply, added FWUpload messages, and
+ *                      removed toolbox message.
+ *  01-09-01  01.01.03  Added event enabled and disabled defines.
+ *                      Added structures for FwHeader and DataHeader.
+ *                      Added ImageType to FwUpload reply.
+ *  02-20-01  01.01.04  Started using MPI_POINTER.
+ *  02-27-01  01.01.05  Added event for RAID status change and its event data.
+ *                      Added IocNumber field to MSG_IOC_FACTS_REPLY.
+ *  --------------------------------------------------------------------------
+
+mpi_cnfg.h
+ *  05-08-00  00.10.01  Original release for 0.10 spec dated 4/26/2000.
+ *  06-06-00  01.00.01  Update version number for 1.0 release.
+ *  06-08-00  01.00.02  Added _PAGEVERSION definitions for all pages.
+ *                      Added FcPhLowestVersion, FcPhHighestVersion, Reserved2
+ *                      fields to FC_DEVICE_0 page, updated the page version.
+ *                      Changed _FREE_RUNNING_CLOCK to _PACING_TRANSFERS in
+ *                      SCSI_PORT_0, SCSI_DEVICE_0 and SCSI_DEVICE_1 pages
+ *                      and updated the page versions.
+ *                      Added _RESPONSE_ID_MASK definition to SCSI_PORT_1
+ *                      page and updated the page version.
+ *                      Added Information field and _INFO_PARAMS_NEGOTIATED
+ *                      definitionto SCSI_DEVICE_0 page.
+ *  06-22-00  01.00.03  Removed batch controls from LAN_0 page and updated the
+ *                      page version.
+ *                      Added BucketsRemaining to LAN_1 page, redefined the
+ *                      state values, and updated the page version.
+ *                      Revised bus width definitions in SCSI_PORT_0,
+ *                      SCSI_DEVICE_0 and SCSI_DEVICE_1 pages.
+ *  06-30-00  01.00.04  Added MaxReplySize to LAN_1 page and updated the page
+ *                      version.
+ *                      Moved FC_DEVICE_0 PageAddress description to spec.
+ *  07-27-00  01.00.05  Corrected the SubsystemVendorID and SubsystemID field
+ *                      widths in IOC_0 page and updated the page version.
+ *  11-02-00  01.01.01  Original release for post 1.0 work
+ *                      Added Manufacturing pages, IO Unit Page 2, SCSI SPI
+ *                      Port Page 2, FC Port Page 4, FC Port Page 5
+ *  12-04-00  01.01.03  Config page changes to match MPI rev 1.00.01.
+ *  12-05-00  01.01.04  Modified config page actions.
+ *  01-09-01  01.01.05  Added defines for page address formats.
+ *                      Data size for Manufacturing pages 2 and 3 no longer
+ *                      defined here.
+ *                      Io Unit Page 2 size is fixed at 4 adapters and some
+ *                      flags were changed.
+ *                      SCSI Port Page 2 Device Settings modified.
+ *                      New fields added to FC Port Page 0 and some flags
+ *                      cleaned up.
+ *                      Removed impedance flash from FC Port Page 1.
+ *                      Added FC Port pages 6 and 7.
+ *  01-25-01  01.01.06  Added MaxInitiators field to FcPortPage0.
+ *  01-29-01  01.01.07  Changed some defines to make them 32 character unique.
+ *                      Added some LinkType defines for FcPortPage0.
+ *  02-20-01  01.01.08  Started using MPI_POINTER.
+ *  02-27-01  01.01.09  Replaced MPI_CONFIG_PAGETYPE_SCSI_LUN with
+ *                      MPI_CONFIG_PAGETYPE_RAID_VOLUME.
+ *                      Added definitions and structures for IOC Page 2 and
+ *                      RAID Volume Page 2.
+ *  --------------------------------------------------------------------------
+
+mpi_init.h
+ *  05-08-00  00.10.01  Original release for 0.10 spec dated 4/26/2000.
+ *  05-24-00  00.10.02  Added SenseBufferLength to _MSG_SCSI_IO_REPLY.
+ *  06-06-00  01.00.01  Update version number for 1.0 release.
+ *  06-08-00  01.00.02  Added MPI_SCSI_RSP_INFO_ definitions.
+ *  11-02-00  01.01.01  Original release for post 1.0 work
+ *  12-04-00  01.01.02  Added MPI_SCSIIO_CONTROL_NO_DISCONNECT.
+ *  02-20-01  01.01.03  Started using MPI_POINTER.
+ *  --------------------------------------------------------------------------
+
+mpi_targ.h
+ *  05-08-00  00.10.01  Original release for 0.10 spec dated 4/26/2000.
+ *  06-06-00  01.00.01  Update version number for 1.0 release.
+ *  06-22-00  01.00.02  Added _MSG_TARGET_CMD_BUFFER_POST_REPLY structure.
+ *                      Corrected DECSRIPTOR typo to DESCRIPTOR.
+ *  11-02-00  01.01.01  Original release for post 1.0 work
+ *                      Modified target mode to use IoIndex instead of
+ *                      HostIndex and IocIndex. Added Alias.
+ *  01-09-01  01.01.02  Added defines for TARGET_ASSIST_FLAGS_REPOST_CMD_BUFFER
+ *                      and TARGET_STATUS_SEND_FLAGS_REPOST_CMD_BUFFER.
+ *  02-20-01  01.01.03  Started using MPI_POINTER.
+ *                      Added structures for MPI_TARGET_SCSI_SPI_CMD_BUFFER and
+ *                      MPI_TARGET_FCP_CMD_BUFFER.
+ *  --------------------------------------------------------------------------
+
+mpi_fc.h
+ *  05-08-00  00.10.01  Original release for 0.10 spec dated 4/26/2000.
+ *  06-06-00  01.00.01  Update version number for 1.0 release.
+ *  06-12-00  01.00.02  Added _MSG_FC_ABORT_REPLY structure.
+ *  11-02-00  01.01.01  Original release for post 1.0 work
+ *  12-04-00  01.01.02  Added messages for Common Transport Send and
+ *                      Primitive Send.
+ *  01-09-01  01.01.03  Modifed some of the new flags to have an MPI prefix
+ *                      and modified the FcPrimitiveSend flags.
+ *  01-25-01  01.01.04  Move InitiatorIndex in LinkServiceRsp reply to a larger
+ *                      field.
+ *                      Added FC_ABORT_TYPE_CT_SEND_REQUEST and
+ *                      FC_ABORT_TYPE_EXLINKSEND_REQUEST for FcAbort request.
+ *                      Added MPI_FC_PRIM_SEND_FLAGS_STOP_SEND.
+ *  02-20-01  01.01.05  Started using MPI_POINTER.
+ *  --------------------------------------------------------------------------
+
+mpi_lan.h
+ *  05-08-00  00.10.01  Original release for 0.10 spec dated 4/26/2000.
+ *  05-24-00  00.10.02  Added LANStatus field to _MSG_LAN_SEND_REPLY.
+ *                      Added LANStatus field to _MSG_LAN_RECEIVE_POST_REPLY.
+ *                      Moved ListCount field in _MSG_LAN_RECEIVE_POST_REPLY.
+ *  06-06-00  01.00.01  Update version number for 1.0 release.
+ *  06-12-00  01.00.02  Added MPI_ to BUCKETSTATUS_ definitions.
+ *  06-22-00  01.00.03  Major changes to match new LAN definition in 1.0 spec.
+ *  06-30-00  01.00.04  Added Context Reply definitions per revised proposal.
+ *                      Changed transaction context usage to bucket/buffer.
+ *  07-05-00  01.00.05  Removed LAN_RECEIVE_POST_BUCKET_CONTEXT_MASK definition
+ *                      to lan private header file
+ *  11-02-00  01.01.01  Original release for post 1.0 work
+ *  02-20-01  01.01.02  Started using MPI_POINTER.
+ *  --------------------------------------------------------------------------
+
+mpi_raid.h
+ *  02-27-01  01.01.01  Original release for this file.
+ *  --------------------------------------------------------------------------
+
+mpi_type.h
+ *  05-08-00  00.10.01  Original release for 0.10 spec dated 4/26/2000.
+ *  06-06-00  01.00.01  Update version number for 1.0 release.
+ *  11-02-00  01.01.01  Original release for post 1.0 work
+ *  02-20-01  01.01.02  Added define and ifdef for MPI_POINTER.
+ *  --------------------------------------------------------------------------
+
+mpi_history.txt         Parts list history
+
+Filename    01.01.08   01.01.07   01.01.06   01.01.05   01.01.04
+----------  --------   --------   --------   --------   --------
+mpi.h       01.01.06   01.01.05   01.01.04   01.01.04   01.01.03
+mpi_ioc.h   01.01.05   01.01.04   01.01.03   01.01.03   01.01.03
+mpi_cnfg.h  01.01.09   01.01.08   01.01.07   01.01.06   01.01.05
+mpi_init.h  01.01.03   01.01.03   01.01.02   01.01.02   01.01.02
+mpi_targ.h  01.01.03   01.01.03   01.01.02   01.01.02   01.01.02
+mpi_fc.h    01.01.05   01.01.05   01.01.04   01.01.04   01.01.03
+mpi_lan.h   01.01.02   01.01.02   01.01.01   01.01.01   01.01.01
+mpi_raid.h  01.01.01
+mpi_type.h  01.01.02   01.01.02   01.01.01   01.01.01   01.01.01
+
+Filename    01.01.03   01.01.02   01.01.01   01.00.07   01.00.06   01.00.05
+----------  --------   --------   --------   --------   --------   --------
+mpi.h       01.01.02   01.01.02   01.01.01   01.00.04   01.00.04   01.00.03
+mpi_ioc.h   01.01.02   01.01.02   01.01.01   01.00.05   01.00.04   01.00.03
+mpi_cnfg.h  01.01.04   01.01.03   01.01.01   01.00.05   01.00.05   01.00.04
+mpi_init.h  01.01.02   01.01.02   01.01.01   01.00.02   01.00.02   01.00.02
+mpi_targ.h  01.01.01   01.01.01   01.01.01   01.00.02   01.00.02   01.00.02
+mpi_fc.h    01.01.02   01.01.02   01.01.01   01.00.02   01.00.02   01.00.02
+mpi_lan.h   01.01.01   01.01.01   01.01.01   01.00.05   01.00.05   01.00.05
+mpi_type.h  01.01.01   01.01.01   01.01.01   01.00.01   01.00.01   01.00.01
+
+Filename     01.00.04   01.00.03   01.00.02   01.00.01   00.10.02   00.10.01
+----------   --------   --------   --------   --------   --------   --------
+mpi.h        01.00.02   01.00.01   01.00.01   01.00.01   00.10.02   00.10.01
+mpi_ioc.h    01.00.02   01.00.02   01.00.01   01.00.01   00.10.02   00.10.01
+mpi_cnfg.h   01.00.03   01.00.02   01.00.02   01.00.01   00.10.01   00.10.01
+mpi_init.h   01.00.02   01.00.02   01.00.02   01.00.01   00.10.02   00.10.01
+mpi_targ.h   01.00.02   01.00.01   01.00.01   01.00.01   00.10.01   00.10.01
+mpi_fc.h     01.00.02   01.00.02   01.00.01   01.00.01   00.10.01   00.10.01
+mpi_lan.h    01.00.03   01.00.02   01.00.01   01.00.01   00.10.02   00.10.01
+mpi_type.h   01.00.01   01.00.01   01.00.01   01.00.01   00.10.01   00.10.01
+
+
+ *  --------------------------------------------------------------------------
+
diff --git a/drivers/message/fusion/lsi/mpi_init.h b/drivers/message/fusion/lsi/mpi_init.h
new file mode 100644 (file)
index 0000000..4f3c8dc
--- /dev/null
@@ -0,0 +1,215 @@
+/*
+ *  Copyright (c) 2000-2001 LSI Logic Corporation.
+ *
+ *
+ *           Name:  MPI_INIT.H
+ *          Title:  MPI initiator mode messages and structures
+ *  Creation Date:  June 8, 2000
+ *
+ *    MPI Version:  01.01.03
+ *
+ *  Version History
+ *  ---------------
+ *
+ *  Date      Version   Description
+ *  --------  --------  ------------------------------------------------------
+ *  05-08-00  00.10.01  Original release for 0.10 spec dated 4/26/2000.
+ *  05-24-00  00.10.02  Added SenseBufferLength to _MSG_SCSI_IO_REPLY.
+ *  06-06-00  01.00.01  Update version number for 1.0 release.
+ *  06-08-00  01.00.02  Added MPI_SCSI_RSP_INFO_ definitions.
+ *  11-02-00  01.01.01  Original release for post 1.0 work.
+ *  12-04-00  01.01.02  Added MPI_SCSIIO_CONTROL_NO_DISCONNECT.
+ *  02-20-01  01.01.03  Started using MPI_POINTER.
+ *  --------------------------------------------------------------------------
+ */
+
+#ifndef MPI_INIT_H
+#define MPI_INIT_H
+
+
+/*****************************************************************************
+*
+*               S C S I    I n i t i a t o r    M e s s a g e s
+*
+*****************************************************************************/
+
+/****************************************************************************/
+/*  SCSI IO messages and assocaited structures                              */
+/****************************************************************************/
+
+typedef struct _MSG_SCSI_IO_REQUEST
+{
+    U8                      TargetID;
+    U8                      Bus;
+    U8                      ChainOffset;
+    U8                      Function;
+    U8                      CDBLength;
+    U8                      SenseBufferLength;
+    U8                      Reserved;
+    U8                      MsgFlags;
+    U32                     MsgContext;
+    U8                      LUN[8];
+    U32                     Control;
+    U8                      CDB[16];
+    U32                     DataLength;
+    U32                     SenseBufferLowAddr;
+    SGE_IO_UNION            SGL;
+} MSG_SCSI_IO_REQUEST, MPI_POINTER PTR_MSG_SCSI_IO_REQUEST,
+  SCSIIORequest_t, MPI_POINTER pSCSIIORequest_t;
+
+
+/* SCSIO MsgFlags bits */
+
+#define MPI_SCSIIO_MSGFLGS_SENSE_WIDTH          (0x01)
+#define MPI_SCSIIO_MSGFLGS_SENSE_WIDTH_32       (0x00)
+#define MPI_SCSIIO_MSGFLGS_SENSE_WIDTH_64       (0x01)
+#define MPI_SCSIIO_MSGFLGS_SENSE_LOCATION       (0x02)
+#define MPI_SCSIIO_MSGFLGS_SENSE_LOC_HOST       (0x00)
+#define MPI_SCSIIO_MSGFLGS_SENSE_LOC_IOC        (0x02)
+
+/* SCSIIO LUN fields */
+
+#define MPI_SCSIIO_LUN_FIRST_LEVEL_ADDRESSING   (0x0000FFFF)
+#define MPI_SCSIIO_LUN_SECOND_LEVEL_ADDRESSING  (0xFFFF0000)
+#define MPI_SCSIIO_LUN_THIRD_LEVEL_ADDRESSING   (0x0000FFFF)
+#define MPI_SCSIIO_LUN_FOURTH_LEVEL_ADDRESSING  (0xFFFF0000)
+#define MPI_SCSIIO_LUN_LEVEL_1_WORD             (0xFF00)
+#define MPI_SCSIIO_LUN_LEVEL_1_DWORD            (0x0000FF00)
+
+/* SCSIO Control bits */
+
+#define MPI_SCSIIO_CONTROL_DATADIRECTION_MASK   (0x03000000)
+#define MPI_SCSIIO_CONTROL_NODATATRANSFER       (0x00000000)
+#define MPI_SCSIIO_CONTROL_WRITE                (0x01000000)
+#define MPI_SCSIIO_CONTROL_READ                 (0x02000000)
+
+#define MPI_SCSIIO_CONTROL_ADDCDBLEN_MASK       (0x3C000000)
+#define MPI_SCSIIO_CONTROL_ADDCDBLEN_SHIFT      (26)
+
+#define MPI_SCSIIO_CONTROL_TASKATTRIBUTE_MASK   (0x00000700)
+#define MPI_SCSIIO_CONTROL_SIMPLEQ              (0x00000000)
+#define MPI_SCSIIO_CONTROL_HEADOFQ              (0x00000100)
+#define MPI_SCSIIO_CONTROL_ORDEREDQ             (0x00000200)
+#define MPI_SCSIIO_CONTROL_ACAQ                 (0x00000400)
+#define MPI_SCSIIO_CONTROL_UNTAGGED             (0x00000500)
+#define MPI_SCSIIO_CONTROL_NO_DISCONNECT        (0x00000700)
+
+#define MPI_SCSIIO_CONTROL_TASKMANAGE_MASK      (0x00FF0000)
+#define MPI_SCSIIO_CONTROL_OBSOLETE             (0x00800000)
+#define MPI_SCSIIO_CONTROL_CLEAR_ACA_RSV        (0x00400000)
+#define MPI_SCSIIO_CONTROL_TARGET_RESET         (0x00200000)
+#define MPI_SCSIIO_CONTROL_LUN_RESET_RSV        (0x00100000)
+#define MPI_SCSIIO_CONTROL_RESERVED             (0x00080000)
+#define MPI_SCSIIO_CONTROL_CLR_TASK_SET_RSV     (0x00040000)
+#define MPI_SCSIIO_CONTROL_ABORT_TASK_SET       (0x00020000)
+#define MPI_SCSIIO_CONTROL_RESERVED2            (0x00010000)
+
+
+/* SCSIIO reply structure */
+typedef struct _MSG_SCSI_IO_REPLY
+{
+    U8                      TargetID;
+    U8                      Bus;
+    U8                      MsgLength;
+    U8                      Function;
+    U8                      CDBLength;
+    U8                      SenseBufferLength;
+    U8                      Reserved;
+    U8                      MsgFlags;
+    U32                     MsgContext;
+    U8                      SCSIStatus;
+    U8                      SCSIState;
+    U16                     IOCStatus;
+    U32                     IOCLogInfo;
+    U32                     TransferCount;
+    U32                     SenseCount;
+    U32                     ResponseInfo;
+} MSG_SCSI_IO_REPLY, MPI_POINTER PTR_MSG_SCSI_IO_REPLY,
+  SCSIIOReply_t, MPI_POINTER pSCSIIOReply_t;
+
+
+/* SCSIIO Reply SCSIStatus values (SAM-2 status codes) */
+
+#define MPI_SCSI_STATUS_SUCCESS                 (0x00)
+#define MPI_SCSI_STATUS_CHECK_CONDITION         (0x02)
+#define MPI_SCSI_STATUS_CONDITION_MET           (0x04)
+#define MPI_SCSI_STATUS_BUSY                    (0x08)
+#define MPI_SCSI_STATUS_INTERMEDIATE            (0x10)
+#define MPI_SCSI_STATUS_INTERMEDIATE_CONDMET    (0x14)
+#define MPI_SCSI_STATUS_RESERVATION_CONFLICT    (0x18)
+#define MPI_SCSI_STATUS_COMMAND_TERMINATED      (0x22)
+#define MPI_SCSI_STATUS_TASK_SET_FULL           (0x28)
+#define MPI_SCSI_STATUS_ACA_ACTIVE              (0x30)
+
+
+/* SCSIIO Reply SCSIState values */
+
+#define MPI_SCSI_STATE_AUTOSENSE_VALID          (0x01)
+#define MPI_SCSI_STATE_AUTOSENSE_FAILED         (0x02)
+#define MPI_SCSI_STATE_NO_SCSI_STATUS           (0x04)
+#define MPI_SCSI_STATE_TERMINATED               (0x08)
+#define MPI_SCSI_STATE_RESPONSE_INFO_VALID      (0x10)
+
+/* SCSIIO Reply ResponseInfo values */
+/* (FCP-1 RSP_CODE values and SPI-3 Packetized Failure codes) */
+
+#define MPI_SCSI_RSP_INFO_FUNCTION_COMPLETE     (0x00000000)
+#define MPI_SCSI_RSP_INFO_FCP_BURST_LEN_ERROR   (0x01000000)
+#define MPI_SCSI_RSP_INFO_CMND_FIELDS_INVALID   (0x02000000)
+#define MPI_SCSI_RSP_INFO_FCP_DATA_RO_ERROR     (0x03000000)
+#define MPI_SCSI_RSP_INFO_TASK_MGMT_UNSUPPORTED (0x04000000)
+#define MPI_SCSI_RSP_INFO_TASK_MGMT_FAILED      (0x05000000)
+#define MPI_SCSI_RSP_INFO_SPI_LQ_INVALID_TYPE   (0x06000000)
+
+
+/****************************************************************************/
+/*  SCSI Task Management messages                                           */
+/****************************************************************************/
+
+typedef struct _MSG_SCSI_TASK_MGMT
+{
+    U8                      TargetID;
+    U8                      Bus;
+    U8                      ChainOffset;
+    U8                      Function;
+    U8                      Reserved;
+    U8                      TaskType;
+    U8                      Reserved1;
+    U8                      MsgFlags;
+    U32                     MsgContext;
+    U8                      LUN[8];
+    U32                     Reserved2[7];
+    U32                     TaskMsgContext;
+} MSG_SCSI_TASK_MGMT, MPI_POINTER PTR_SCSI_TASK_MGMT,
+  SCSITaskMgmt_t, MPI_POINTER pSCSITaskMgmt_t;
+
+/* TaskType values */
+
+#define MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK        (0x00000001)
+#define MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET     (0x00000002)
+#define MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET      (0x00000003)
+#define MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS         (0x00000004)
+
+/* MsgFlags bits */
+#define MPI_SCSITASKMGMT_MSGFLAGS_LIP_RESET_OPTION  (0x00000002)
+
+/* SCSI Task Management Reply */
+typedef struct _MSG_SCSI_TASK_MGMT_REPLY
+{
+    U8                      TargetID;
+    U8                      Bus;
+    U8                      MsgLength;
+    U8                      Function;
+    U8                      Reserved;
+    U8                      TaskType;
+    U8                      Reserved1;
+    U8                      MsgFlags;
+    U32                     MsgContext;
+    U8                      Reserved2[2];
+    U16                     IOCStatus;
+    U32                     IOCLogInfo;
+    U32                     TerminationCount;
+} MSG_SCSI_TASK_MGMT_REPLY, MPI_POINTER PTR_MSG_SCSI_TASK_MGMT_REPLY,
+  SCSITaskMgmtReply_t, MPI_POINTER pSCSITaskMgmtReply_t;
+
+#endif
diff --git a/drivers/message/fusion/lsi/mpi_ioc.h b/drivers/message/fusion/lsi/mpi_ioc.h
new file mode 100644 (file)
index 0000000..0411671
--- /dev/null
@@ -0,0 +1,583 @@
+/*
+ *  Copyright (c) 2000-2001 LSI Logic Corporation.
+ *
+ *
+ *           Name:  MPI_IOC.H
+ *          Title:  MPI IOC, Port, Event, FW Load, and ToolBox messages
+ *  Creation Date:  August 11, 2000
+ *
+ *    MPI Version:  01.01.05
+ *
+ *  Version History
+ *  ---------------
+ *
+ *  Date      Version   Description
+ *  --------  --------  ------------------------------------------------------
+ *  05-08-00  00.10.01  Original release for 0.10 spec dated 4/26/2000.
+ *  05-24-00  00.10.02  Added _MSG_IOC_INIT_REPLY structure.
+ *  06-06-00  01.00.01  Added CurReplyFrameSize field to _MSG_IOC_FACTS_REPLY.
+ *  06-12-00  01.00.02  Added _MSG_PORT_ENABLE_REPLY structure.
+ *                      Added _MSG_EVENT_ACK_REPLY structure.
+ *                      Added _MSG_FW_DOWNLOAD_REPLY structure.
+ *                      Added _MSG_TOOLBOX_REPLY structure.
+ *  06-30-00  01.00.03  Added MaxLanBuckets to _PORT_FACT_REPLY structure.
+ *  07-27-00  01.00.04  Added _EVENT_DATA structure definitions for _SCSI,
+ *                      _LINK_STATUS, _LOOP_STATE and _LOGOUT.
+ *  08-11-00  01.00.05  Switched positions of MsgLength and Function fields in
+ *                      _MSG_EVENT_ACK_REPLY structure to match specification.
+ *  11-02-00  01.01.01  Original release for post 1.0 work.
+ *                      Added a value for Manufacturer to WhoInit.
+ *  12-04-00  01.01.02  Modified IOCFacts reply, added FWUpload messages, and
+ *                      removed toolbox message.
+ *  01-09-01  01.01.03  Added event enabled and disabled defines.
+ *                      Added structures for FwHeader and DataHeader.
+ *                      Added ImageType to FwUpload reply.
+ *  02-20-01  01.01.04  Started using MPI_POINTER.
+ *  02-27-01  01.01.05  Added event for RAID status change and its event data.
+ *                      Added IocNumber field to MSG_IOC_FACTS_REPLY.
+ *  --------------------------------------------------------------------------
+ */
+
+#ifndef MPI_IOC_H
+#define MPI_IOC_H
+
+
+/*****************************************************************************
+*
+*               I O C    M e s s a g e s
+*
+*****************************************************************************/
+
+/****************************************************************************/
+/*  IOCInit message                                                         */
+/****************************************************************************/
+
+typedef struct _MSG_IOC_INIT
+{
+    U8                      WhoInit;
+    U8                      Reserved;
+    U8                      ChainOffset;
+    U8                      Function;
+    U8                      Flags;
+    U8                      MaxDevices;
+    U8                      MaxBuses;
+    U8                      MsgFlags;
+    U32                     MsgContext;
+    U16                     ReplyFrameSize;
+    U8                      Reserved1[2];
+    U32                     HostMfaHighAddr;
+    U32                     SenseBufferHighAddr;
+} MSG_IOC_INIT, MPI_POINTER PTR_MSG_IOC_INIT,
+  IOCInit_t, MPI_POINTER pIOCInit_t;
+
+typedef struct _MSG_IOC_INIT_REPLY
+{
+    U8                      WhoInit;
+    U8                      Reserved;
+    U8                      MsgLength;
+    U8                      Function;
+    U8                      Flags;
+    U8                      MaxDevices;
+    U8                      MaxBuses;
+    U8                      MsgFlags;
+    U32                     MsgContext;
+    U16                     Reserved2;
+    U16                     IOCStatus;
+    U32                     IOCLogInfo;
+} MSG_IOC_INIT_REPLY, MPI_POINTER PTR_MSG_IOC_INIT_REPLY,
+  IOCInitReply_t, MPI_POINTER pIOCInitReply_t;
+
+/* WhoInit values */
+
+#define MPI_WHOINIT_NO_ONE                      (0x00)
+#define MPI_WHOINIT_SYSTEM_BIOS                 (0x01)
+#define MPI_WHOINIT_ROM_BIOS                    (0x02)
+#define MPI_WHOINIT_PCI_PEER                    (0x03)
+#define MPI_WHOINIT_HOST_DRIVER                 (0x04)
+#define MPI_WHOINIT_MANUFACTURER                (0x05)
+
+
+/****************************************************************************/
+/*  IOC Facts message                                                       */
+/****************************************************************************/
+
+typedef struct _MSG_IOC_FACTS
+{
+    U8                      Reserved[2];
+    U8                      ChainOffset;
+    U8                      Function;
+    U8                      Reserved1[3];
+    U8                      MsgFlags;
+    U32                     MsgContext;
+} MSG_IOC_FACTS, MPI_POINTER PTR_IOC_FACTS,
+  IOCFacts_t, MPI_POINTER pIOCFacts_t;
+
+/* IOC Facts Reply */
+
+typedef struct _MSG_IOC_FACTS_REPLY
+{
+    U16                     MsgVersion;
+    U8                      MsgLength;
+    U8                      Function;
+    U16                     Reserved;
+    U8                      IOCNumber;
+    U8                      MsgFlags;
+    U32                     MsgContext;
+    U16                     Reserved2;
+    U16                     IOCStatus;
+    U32                     IOCLogInfo;
+    U8                      MaxChainDepth;
+    U8                      WhoInit;
+    U8                      BlockSize;
+    U8                      Flags;
+    U16                     ReplyQueueDepth;
+    U16                     RequestFrameSize;
+    U16                     FWVersion;
+    U16                     ProductID;
+    U32                     CurrentHostMfaHighAddr;
+    U16                     GlobalCredits;
+    U8                      NumberOfPorts;
+    U8                      EventState;
+    U32                     CurrentSenseBufferHighAddr;
+    U16                     CurReplyFrameSize;
+    U8                      MaxDevices;
+    U8                      MaxBuses;
+    U32                     FWImageSize;
+    U32                     DataImageSize;
+} MSG_IOC_FACTS_REPLY, MPI_POINTER PTR_MSG_IOC_FACTS_REPLY,
+  IOCFactsReply_t, MPI_POINTER pIOCFactsReply_t;
+
+#define MPI_IOCFACTS_MSGVERSION_MAJOR_MASK      (0xFF00)
+#define MPI_IOCFACTS_MSGVERSION_MINOR_MASK      (0x00FF)
+
+#define MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT     (0x01)
+#define MPI_IOCFACTS_FLAGS_DATA_IMAGE_UPLOAD    (0x02)
+
+#define MPI_IOCFACTS_EVENTSTATE_DISABLED        (0x00)
+#define MPI_IOCFACTS_EVENTSTATE_ENABLED         (0x01)
+
+
+
+/*****************************************************************************
+*
+*               P o r t    M e s s a g e s
+*
+*****************************************************************************/
+
+/****************************************************************************/
+/*  Port Facts message and Reply                                            */
+/****************************************************************************/
+
+typedef struct _MSG_PORT_FACTS
+{
+     U8                     Reserved[2];
+     U8                     ChainOffset;
+     U8                     Function;
+     U8                     Reserved1[2];
+     U8                     PortNumber;
+     U8                     MsgFlags;
+     U32                    MsgContext;
+} MSG_PORT_FACTS, MPI_POINTER PTR_MSG_PORT_FACTS,
+  PortFacts_t, MPI_POINTER pPortFacts_t;
+
+typedef struct _MSG_PORT_FACTS_REPLY
+{
+     U16                    Reserved;
+     U8                     MsgLength;
+     U8                     Function;
+     U16                    Reserved1;
+     U8                     PortNumber;
+     U8                     MsgFlags;
+     U32                    MsgContext;
+     U16                    Reserved2;
+     U16                    IOCStatus;
+     U32                    IOCLogInfo;
+     U8                     Reserved3;
+     U8                     PortType;
+     U16                    MaxDevices;
+     U16                    PortSCSIID;
+     U16                    ProtocolFlags;
+     U16                    MaxPostedCmdBuffers;
+     U16                    MaxPersistentIDs;
+     U16                    MaxLanBuckets;
+     U16                    Reserved4;
+     U32                    Reserved5;
+} MSG_PORT_FACTS_REPLY, MPI_POINTER PTR_MSG_PORT_FACTS_REPLY,
+  PortFactsReply_t, MPI_POINTER pPortFactsReply_t;
+
+
+/* PortTypes values */
+
+#define MPI_PORTFACTS_PORTTYPE_INACTIVE         (0x00)
+#define MPI_PORTFACTS_PORTTYPE_SCSI             (0x01)
+#define MPI_PORTFACTS_PORTTYPE_FC               (0x10)
+
+/* ProtocolFlags values */
+
+#define MPI_PORTFACTS_PROTOCOL_LOGBUSADDR       (0x01)
+#define MPI_PORTFACTS_PROTOCOL_LAN              (0x02)
+#define MPI_PORTFACTS_PROTOCOL_TARGET           (0x04)
+#define MPI_PORTFACTS_PROTOCOL_INITIATOR        (0x08)
+
+
+/****************************************************************************/
+/*  Port Enable Message                                                     */
+/****************************************************************************/
+
+typedef struct _MSG_PORT_ENABLE
+{
+    U8                      Reserved[2];
+    U8                      ChainOffset;
+    U8                      Function;
+    U8                      Reserved1[2];
+    U8                      PortNumber;
+    U8                      MsgFlags;
+    U32                     MsgContext;
+} MSG_PORT_ENABLE, MPI_POINTER PTR_MSG_PORT_ENABLE,
+  PortEnable_t, MPI_POINTER pPortEnable_t;
+
+typedef struct _MSG_PORT_ENABLE_REPLY
+{
+    U8                      Reserved[2];
+    U8                      MsgLength;
+    U8                      Function;
+    U8                      Reserved1[2];
+    U8                      PortNumber;
+    U8                      MsgFlags;
+    U32                     MsgContext;
+    U16                     Reserved2;
+    U16                     IOCStatus;
+    U32                     IOCLogInfo;
+} MSG_PORT_ENABLE_REPLY, MPI_POINTER PTR_MSG_PORT_ENABLE_REPLY,
+  PortEnableReply_t, MPI_POINTER pPortEnableReply_t;
+
+
+/*****************************************************************************
+*
+*               E v e n t    M e s s a g e s
+*
+*****************************************************************************/
+
+/****************************************************************************/
+/*  Event Notification messages                                             */
+/****************************************************************************/
+
+typedef struct _MSG_EVENT_NOTIFY
+{
+    U8                      Switch;
+    U8                      Reserved;
+    U8                      ChainOffset;
+    U8                      Function;
+    U8                      Reserved1[3];
+    U8                      MsgFlags;
+    U32                     MsgContext;
+} MSG_EVENT_NOTIFY, MPI_POINTER PTR_MSG_EVENT_NOTIFY,
+  EventNotification_t, MPI_POINTER pEventNotification_t;
+
+/* Event Notification Reply */
+
+typedef struct _MSG_EVENT_NOTIFY_REPLY
+{
+     U16                    EventDataLength;
+     U8                     MsgLength;
+     U8                     Function;
+     U8                     Reserved1[2];
+     U8                     AckRequired;
+     U8                     MsgFlags;
+     U32                    MsgContext;
+     U8                     Reserved2[2];
+     U16                    IOCStatus;
+     U32                    IOCLogInfo;
+     U32                    Event;
+     U32                    EventContext;
+     U32                    Data[1];
+} MSG_EVENT_NOTIFY_REPLY, MPI_POINTER PTR_MSG_EVENT_NOTIFY_REPLY,
+  EventNotificationReply_t, MPI_POINTER pEventNotificationReply_t;
+
+/* Event Acknowledge */
+
+typedef struct _MSG_EVENT_ACK
+{
+    U8                      Reserved[2];
+    U8                      ChainOffset;
+    U8                      Function;
+    U8                      Reserved1[3];
+    U8                      MsgFlags;
+    U32                     MsgContext;
+    U32                     Event;
+    U32                     EventContext;
+} MSG_EVENT_ACK, MPI_POINTER PTR_MSG_EVENT_ACK,
+  EventAck_t, MPI_POINTER pEventAck_t;
+
+typedef struct _MSG_EVENT_ACK_REPLY
+{
+    U8                      Reserved[2];
+    U8                      MsgLength;
+    U8                      Function;
+    U8                      Reserved1[3];
+    U8                      MsgFlags;
+    U32                     MsgContext;
+    U16                     Reserved2;
+    U16                     IOCStatus;
+    U32                     IOCLogInfo;
+} MSG_EVENT_ACK_REPLY, MPI_POINTER PTR_MSG_EVENT_ACK_REPLY,
+  EventAckReply_t, MPI_POINTER pEventAckReply_t;
+
+
+/* Switch */
+
+#define MPI_EVENT_NOTIFICATION_SWITCH_OFF   (0x00)
+#define MPI_EVENT_NOTIFICATION_SWITCH_ON    (0x01)
+
+/* Event */
+
+#define MPI_EVENT_NONE                      (0x00000000)
+#define MPI_EVENT_LOG_DATA                  (0x00000001)
+#define MPI_EVENT_STATE_CHANGE              (0x00000002)
+#define MPI_EVENT_UNIT_ATTENTION            (0x00000003)
+#define MPI_EVENT_IOC_BUS_RESET             (0x00000004)
+#define MPI_EVENT_EXT_BUS_RESET             (0x00000005)
+#define MPI_EVENT_RESCAN                    (0x00000006)
+#define MPI_EVENT_LINK_STATUS_CHANGE        (0x00000007)
+#define MPI_EVENT_LOOP_STATE_CHANGE         (0x00000008)
+#define MPI_EVENT_LOGOUT                    (0x00000009)
+#define MPI_EVENT_EVENT_CHANGE              (0x0000000A)
+#define MPI_EVENT_RAID_STATUS_CHANGE        (0x0000000B)
+
+/* AckRequired field values */
+
+#define MPI_EVENT_NOTIFICATION_ACK_NOT_REQUIRED (0x00)
+#define MPI_EVENT_NOTIFICATION_ACK_REQUIRED     (0x01)
+
+/* SCSI Event data for Port, Bus and Device forms) */
+
+typedef struct _EVENT_DATA_SCSI
+{
+    U8                      TargetID;
+    U8                      BusPort;
+    U16                     Reserved;
+} EVENT_DATA_SCSI, MPI_POINTER PTR_EVENT_DATA_SCSI,
+  EventDataScsi_t, MPI_POINTER pEventDataScsi_t;
+
+/* MPI Link Status Change Event data */
+
+typedef struct _EVENT_DATA_LINK_STATUS
+{
+    U8                      State;
+    U8                      Reserved;
+    U16                     Reserved1;
+    U8                      Reserved2;
+    U8                      Port;
+    U16                     Reserved3;
+} EVENT_DATA_LINK_STATUS, MPI_POINTER PTR_EVENT_DATA_LINK_STATUS,
+  EventDataLinkStatus_t, MPI_POINTER pEventDataLinkStatus_t;
+
+#define MPI_EVENT_LINK_STATUS_FAILURE       (0x00000000)
+#define MPI_EVENT_LINK_STATUS_ACTIVE        (0x00000001)
+
+/* MPI Loop State Change Event data */
+
+typedef struct _EVENT_DATA_LOOP_STATE
+{
+    U8                      Character4;
+    U8                      Character3;
+    U8                      Type;
+    U8                      Reserved;
+    U8                      Reserved1;
+    U8                      Port;
+    U16                     Reserved2;
+} EVENT_DATA_LOOP_STATE, MPI_POINTER PTR_EVENT_DATA_LOOP_STATE,
+  EventDataLoopState_t, MPI_POINTER pEventDataLoopState_t;
+
+#define MPI_EVENT_LOOP_STATE_CHANGE_LIP     (0x0001)
+#define MPI_EVENT_LOOP_STATE_CHANGE_LPE     (0x0002)
+#define MPI_EVENT_LOOP_STATE_CHANGE_LPB     (0x0003)
+
+/* MPI LOGOUT Event data */
+
+typedef struct _EVENT_DATA_LOGOUT
+{
+    U32                     NPortID;
+    U8                      Reserved;
+    U8                      Port;
+    U16                     Reserved1;
+} EVENT_DATA_LOGOUT, MPI_POINTER PTR_EVENT_DATA_LOGOUT,
+  EventDataLogout_t, MPI_POINTER pEventDataLogout_t;
+
+/* MPI RAID Status Change Event data */
+
+typedef struct _EVENT_DATA_RAID_STATUS_CHANGE
+{
+    U8                      VolumeTargetID;
+    U8                      VolumeBus;
+    U8                      ReasonCode;
+    U8                      PhysDiskNum;
+    U8                      ASC;
+    U8                      ASCQ;
+    U16                     Reserved;
+} EVENT_DATA_RAID_STATUS_CHANGE, MPI_POINTER PTR_EVENT_DATA_RAID_STATUS_CHANGE,
+  MpiEventDataRaidStatusChange_t, MPI_POINTER pMpiEventDataRaidStatusChange_t;
+
+
+/* MPI RAID Status Change Event data ReasonCode values */
+
+#define MPI_EVENT_RAID_DATA_RC_VOLUME_OPTIMAL       (0x00)
+#define MPI_EVENT_RAID_DATA_RC_VOLUME_DEGRADED      (0x01)
+#define MPI_EVENT_RAID_DATA_RC_STARTED_RESYNC       (0x02)
+#define MPI_EVENT_RAID_DATA_RC_DISK_ADDED           (0x03)
+#define MPI_EVENT_RAID_DATA_RC_DISK_NOT_RESPONDING  (0x04)
+#define MPI_EVENT_RAID_DATA_RC_SMART_DATA           (0x05)
+
+
+/*****************************************************************************
+*
+*               F i r m w a r e    L o a d    M e s s a g e s
+*
+*****************************************************************************/
+
+/****************************************************************************/
+/*  Firmware Download message and associated structures                     */
+/****************************************************************************/
+
+typedef struct _MSG_FW_DOWNLOAD
+{
+    U8                      ImageType;
+    U8                      Reserved;
+    U8                      ChainOffset;
+    U8                      Function;
+    U8                      Reserved1[3];
+    U8                      MsgFlags;
+    U32                     MsgContext;
+    SGE_MPI_UNION           SGL;
+} MSG_FW_DOWNLOAD, MPI_POINTER PTR_MSG_FW_DOWNLOAD,
+  FWDownload_t, MPI_POINTER pFWDownload_t;
+
+#define MPI_FW_DOWNLOAD_ITYPE_RESERVED      (0x00)
+#define MPI_FW_DOWNLOAD_ITYPE_FW            (0x01)
+#define MPI_FW_DOWNLOAD_ITYPE_BIOS          (0x02)
+
+
+typedef struct _FWDownloadTCSGE
+{
+    U8                      Reserved;
+    U8                      ContextSize;
+    U8                      DetailsLength;
+    U8                      Flags;
+    U32                     Reserved1;
+    U32                     ImageOffset;
+    U32                     ImageSize;
+} FW_DOWNLOAD_TCSGE, MPI_POINTER PTR_FW_DOWNLOAD_TCSGE,
+  FWDownloadTCSGE_t, MPI_POINTER pFWDownloadTCSGE_t;
+
+/* Firmware Download reply */
+typedef struct _MSG_FW_DOWNLOAD_REPLY
+{
+    U8                      ImageType;
+    U8                      Reserved;
+    U8                      MsgLength;
+    U8                      Function;
+    U8                      Reserved1[3];
+    U8                      MsgFlags;
+    U32                     MsgContext;
+    U16                     Reserved2;
+    U16                     IOCStatus;
+    U32                     IOCLogInfo;
+} MSG_FW_DOWNLOAD_REPLY, MPI_POINTER PTR_MSG_FW_DOWNLOAD_REPLY,
+  FWDownloadReply_t, MPI_POINTER pFWDownloadReply_t;
+
+
+/****************************************************************************/
+/*  Firmware Upload message and associated structures                       */
+/****************************************************************************/
+
+typedef struct _MSG_FW_UPLOAD
+{
+    U8                      ImageType;
+    U8                      Reserved;
+    U8                      ChainOffset;
+    U8                      Function;
+    U8                      Reserved1[3];
+    U8                      MsgFlags;
+    U32                     MsgContext;
+    SGE_MPI_UNION           SGL;
+} MSG_FW_UPLOAD, MPI_POINTER PTR_MSG_FW_UPLOAD,
+  FWUpload_t, MPI_POINTER pFWUpload_t;
+
+#define MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM      (0x00)
+#define MPI_FW_UPLOAD_ITYPE_FW_FLASH        (0x01)
+#define MPI_FW_UPLOAD_ITYPE_BIOS_FLASH      (0x02)
+#define MPI_FW_UPLOAD_ITYPE_DATA_IOC_MEM    (0x03)
+
+typedef struct _FWUploadTCSGE
+{
+    U8                      Reserved;
+    U8                      ContextSize;
+    U8                      DetailsLength;
+    U8                      Flags;
+    U32                     Reserved1;
+    U32                     ImageOffset;
+    U32                     ImageSize;
+} FW_UPLOAD_TCSGE, MPI_POINTER PTR_FW_UPLOAD_TCSGE,
+  FWUploadTCSGE_t, MPI_POINTER pFWUploadTCSGE_t;
+
+/* Firmware Upload reply */
+typedef struct _MSG_FW_UPLOAD_REPLY
+{
+    U8                      ImageType;
+    U8                      Reserved;
+    U8                      MsgLength;
+    U8                      Function;
+    U8                      Reserved1[3];
+    U8                      MsgFlags;
+    U32                     MsgContext;
+    U16                     Reserved2;
+    U16                     IOCStatus;
+    U32                     IOCLogInfo;
+    U32                     ActualImageSize;
+} MSG_FW_UPLOAD_REPLY, MPI_POINTER PTR_MSG_FW_UPLOAD_REPLY,
+  FWUploadReply_t, MPI_POINTER pFWUploadReply_t;
+
+
+typedef struct _MPI_FW_HEADER
+{
+    U32                     ArmBranchInstruction0;
+    U32                     Signature0;
+    U32                     Signature1;
+    U32                     Signature2;
+    U32                     ArmBranchInstruction1;
+    U32                     ArmBranchInstruction2;
+    U32                     Reserved;
+    U32                     Checksum;
+    U16                     VendorId;
+    U16                     ProductId;
+    U16                     FwVersion;
+    U16                     Reserved1;
+    U32                     SeqCodeVersion;
+    U32                     ImageSize;
+    U32                     Reserved2;
+    U32                     LoadStartAddress;
+    U32                     IopResetVectorValue;
+    U32                     IopResetRegAddr;
+    U32                     VersionNameWhat;
+    U8                      VersionName[32];
+    U32                     VendorNameWhat;
+    U8                      VendorName[32];
+} MPI_FW_HEADER, MPI_POINTER PTR_MPI_FW_HEADER,
+  MpiFwHeader_t, MPI_POINTER pMpiFwHeader_t;
+
+#define MPI_FW_HEADER_WHAT_SIGNATURE    (0x29232840)
+
+
+typedef struct _MPI_DATA_HEADER
+{
+    U32                     Signature;
+    U16                     FunctionNumber;
+    U16                     Length;
+    U32                     Checksum;
+    U32                     LoadStartAddress;
+} MPI_DATA_HEADER, MPI_POINTER PTR_MPI_DATA_HEADER,
+  MpiDataHeader_t, MPI_POINTER pMpiDataHeader_t;
+
+#define MPI_DATA_HEADER_SIGNATURE       (0x43504147)
+
+#endif
diff --git a/drivers/message/fusion/lsi/mpi_lan.h b/drivers/message/fusion/lsi/mpi_lan.h
new file mode 100644 (file)
index 0000000..86d15dc
--- /dev/null
@@ -0,0 +1,204 @@
+/*
+ *  Copyright (c) 2000-2001 LSI Logic Corporation.
+ *
+ *
+ *           Name:  MPI_LAN.H
+ *          Title:  MPI LAN messages and structures
+ *  Creation Date:  June 30, 2000
+ *
+ *    MPI Version:  01.01.02
+ *
+ *  Version History
+ *  ---------------
+ *
+ *  Date      Version   Description
+ *  --------  --------  ------------------------------------------------------
+ *  05-08-00  00.10.01  Original release for 0.10 spec dated 4/26/2000.
+ *  05-24-00  00.10.02  Added LANStatus field to _MSG_LAN_SEND_REPLY.
+ *                      Added LANStatus field to _MSG_LAN_RECEIVE_POST_REPLY.
+ *                      Moved ListCount field in _MSG_LAN_RECEIVE_POST_REPLY.
+ *  06-06-00  01.00.01  Update version number for 1.0 release.
+ *  06-12-00  01.00.02  Added MPI_ to BUCKETSTATUS_ definitions.
+ *  06-22-00  01.00.03  Major changes to match new LAN definition in 1.0 spec.
+ *  06-30-00  01.00.04  Added Context Reply definitions per revised proposal.
+ *                      Changed transaction context usage to bucket/buffer.
+ *  07-05-00  01.00.05  Removed LAN_RECEIVE_POST_BUCKET_CONTEXT_MASK definition
+ *                      to lan private header file
+ *  11-02-00  01.01.01  Original release for post 1.0 work
+ *  02-20-01  01.01.02  Started using MPI_POINTER.
+ *  --------------------------------------------------------------------------
+ */
+
+#ifndef MPI_LAN_H
+#define MPI_LAN_H
+
+
+/******************************************************************************
+*
+*               L A N    M e s s a g e s
+*
+*******************************************************************************/
+
+/* LANSend messages */
+
+typedef struct _MSG_LAN_SEND_REQUEST
+{
+    U16                     Reserved;
+    U8                      ChainOffset;
+    U8                      Function;
+    U16                     Reserved2;
+    U8                      PortNumber;
+    U8                      MsgFlags;
+    U32                     MsgContext;
+    SGE_MPI_UNION           SG_List[1];
+} MSG_LAN_SEND_REQUEST, MPI_POINTER PTR_MSG_LAN_SEND_REQUEST,
+  LANSendRequest_t, MPI_POINTER pLANSendRequest_t;
+
+
+typedef struct _MSG_LAN_SEND_REPLY
+{
+    U16                     Reserved;
+    U8                      MsgLength;
+    U8                      Function;
+    U8                      Reserved2;
+    U8                      NumberOfContexts;
+    U8                      PortNumber;
+    U8                      MsgFlags;
+    U32                     MsgContext;
+    U16                     Reserved3;
+    U16                     IOCStatus;
+    U32                     IOCLogInfo;
+    U32                     BufferContext;
+} MSG_LAN_SEND_REPLY, MPI_POINTER PTR_MSG_LAN_SEND_REPLY,
+  LANSendReply_t, MPI_POINTER pLANSendReply_t;
+
+
+/* LANReceivePost */
+
+typedef struct _MSG_LAN_RECEIVE_POST_REQUEST
+{
+    U16                     Reserved;
+    U8                      ChainOffset;
+    U8                      Function;
+    U16                     Reserved2;
+    U8                      PortNumber;
+    U8                      MsgFlags;
+    U32                     MsgContext;
+    U32                     BucketCount;
+    SGE_MPI_UNION           SG_List[1];
+} MSG_LAN_RECEIVE_POST_REQUEST, MPI_POINTER PTR_MSG_LAN_RECEIVE_POST_REQUEST,
+  LANReceivePostRequest_t, MPI_POINTER pLANReceivePostRequest_t;
+
+
+typedef struct _MSG_LAN_RECEIVE_POST_REPLY
+{
+    U16                     Reserved;
+    U8                      MsgLength;
+    U8                      Function;
+    U8                      Reserved2;
+    U8                      NumberOfContexts;
+    U8                      PortNumber;
+    U8                      MsgFlags;
+    U32                     MsgContext;
+    U16                     Reserved3;
+    U16                     IOCStatus;
+    U32                     IOCLogInfo;
+    U32                     BucketsRemaining;
+    U32                     PacketOffset;
+    U32                     PacketLength;
+    U32                     BucketContext[1];
+} MSG_LAN_RECEIVE_POST_REPLY, MPI_POINTER PTR_MSG_LAN_RECEIVE_POST_REPLY,
+  LANReceivePostReply_t, MPI_POINTER pLANReceivePostReply_t;
+
+
+/* LANReset */
+
+typedef struct _MSG_LAN_RESET_REQUEST
+{
+    U16                     Reserved;
+    U8                      ChainOffset;
+    U8                      Function;
+    U16                     Reserved2;
+    U8                      PortNumber;
+    U8                      MsgFlags;
+    U32                     MsgContext;
+} MSG_LAN_RESET_REQUEST, MPI_POINTER PTR_MSG_LAN_RESET_REQUEST,
+  LANResetRequest_t, MPI_POINTER pLANResetRequest_t;
+
+
+typedef struct _MSG_LAN_RESET_REPLY
+{
+    U16                     Reserved;
+    U8                      MsgLength;
+    U8                      Function;
+    U16                     Reserved2;
+    U8                      PortNumber;
+    U8                      MsgFlags;
+    U32                     MsgContext;
+    U16                     Reserved3;
+    U16                     IOCStatus;
+    U32                     IOCLogInfo;
+} MSG_LAN_RESET_REPLY, MPI_POINTER PTR_MSG_LAN_RESET_REPLY,
+  LANResetReply_t, MPI_POINTER pLANResetReply_t;
+
+
+/****************************************************************************/
+/* LAN Context Reply defines and macros                                     */
+/****************************************************************************/
+
+#define LAN_REPLY_PACKET_LENGTH_MASK            (0x0000FFFF)
+#define LAN_REPLY_PACKET_LENGTH_SHIFT           (0)
+#define LAN_REPLY_BUCKET_CONTEXT_MASK           (0x07FF0000)
+#define LAN_REPLY_BUCKET_CONTEXT_SHIFT          (16)
+#define LAN_REPLY_BUFFER_CONTEXT_MASK           (0x07FFFFFF)
+#define LAN_REPLY_BUFFER_CONTEXT_SHIFT          (0)
+#define LAN_REPLY_FORM_MASK                     (0x18000000)
+#define LAN_REPLY_FORM_RECEIVE_SINGLE           (0x00)
+#define LAN_REPLY_FORM_RECEIVE_MULTIPLE         (0x01)
+#define LAN_REPLY_FORM_SEND_SINGLE              (0x02)
+#define LAN_REPLY_FORM_MESSAGE_CONTEXT          (0x03)
+#define LAN_REPLY_FORM_SHIFT                    (27)
+
+#define GET_LAN_PACKET_LENGTH(x)    (((x) & LAN_REPLY_PACKET_LENGTH_MASK)   \
+                                        >> LAN_REPLY_PACKET_LENGTH_SHIFT)
+
+#define SET_LAN_PACKET_LENGTH(x, lth)                                       \
+            ((x) = ((x) & ~LAN_REPLY_PACKET_LENGTH_MASK) |                  \
+                            (((lth) << LAN_REPLY_PACKET_LENGTH_SHIFT) &     \
+                                        LAN_REPLY_PACKET_LENGTH_MASK))
+
+#define GET_LAN_BUCKET_CONTEXT(x)   (((x) & LAN_REPLY_BUCKET_CONTEXT_MASK)  \
+                                        >> LAN_REPLY_BUCKET_CONTEXT_SHIFT)
+
+#define SET_LAN_BUCKET_CONTEXT(x, ctx)                                      \
+            ((x) = ((x) & ~LAN_REPLY_BUCKET_CONTEXT_MASK) |                 \
+                            (((ctx) << LAN_REPLY_BUCKET_CONTEXT_SHIFT) &    \
+                                        LAN_REPLY_BUCKET_CONTEXT_MASK))
+
+#define GET_LAN_BUFFER_CONTEXT(x)   (((x) & LAN_REPLY_BUFFER_CONTEXT_MASK)  \
+                                        >> LAN_REPLY_BUFFER_CONTEXT_SHIFT)
+
+#define SET_LAN_BUFFER_CONTEXT(x, ctx)                                      \
+            ((x) = ((x) & ~LAN_REPLY_BUFFER_CONTEXT_MASK) |                 \
+                            (((ctx) << LAN_REPLY_BUFFER_CONTEXT_SHIFT) &    \
+                                        LAN_REPLY_BUFFER_CONTEXT_MASK))
+
+#define GET_LAN_FORM(x)             (((x) & LAN_REPLY_FORM_MASK)            \
+                                        >> LAN_REPLY_FORM_SHIFT)
+
+#define SET_LAN_FORM(x, frm)                                                \
+            ((x) = ((x) & ~LAN_REPLY_FORM_MASK) |                           \
+                            (((frm) << LAN_REPLY_FORM_SHIFT) &              \
+                                        LAN_REPLY_FORM_MASK))
+
+
+/****************************************************************************/
+/* LAN Current Device State defines                                         */
+/****************************************************************************/
+
+#define MPI_LAN_DEVICE_STATE_RESET                     (0x00)
+#define MPI_LAN_DEVICE_STATE_OPERATIONAL               (0x01)
+
+
+#endif
+
diff --git a/drivers/message/fusion/lsi/mpi_targ.h b/drivers/message/fusion/lsi/mpi_targ.h
new file mode 100644 (file)
index 0000000..8b0d74a
--- /dev/null
@@ -0,0 +1,328 @@
+/*
+ *  Copyright (c) 2000-2001 LSI Logic Corporation.
+ *
+ *
+ *           Name:  MPI_TARG.H
+ *          Title:  MPI Target mode messages and structures
+ *  Creation Date:  June 22, 2000
+ *
+ *    MPI Version:  01.01.03
+ *
+ *  Version History
+ *  ---------------
+ *
+ *  Date      Version   Description
+ *  --------  --------  ------------------------------------------------------
+ *  05-08-00  00.10.01  Original release for 0.10 spec dated 4/26/2000.
+ *  06-06-00  01.00.01  Update version number for 1.0 release.
+ *  06-22-00  01.00.02  Added _MSG_TARGET_CMD_BUFFER_POST_REPLY structure.
+ *                      Corrected DECSRIPTOR typo to DESCRIPTOR.
+ *  11-02-00  01.01.01  Original release for post 1.0 work
+ *                      Modified target mode to use IoIndex instead of
+ *                      HostIndex and IocIndex. Added Alias.
+ *  01-09-01  01.01.02  Added defines for TARGET_ASSIST_FLAGS_REPOST_CMD_BUFFER
+ *                      and TARGET_STATUS_SEND_FLAGS_REPOST_CMD_BUFFER.
+ *  02-20-01  01.01.03  Started using MPI_POINTER.
+ *                      Added structures for MPI_TARGET_SCSI_SPI_CMD_BUFFER and
+ *                      MPI_TARGET_FCP_CMD_BUFFER.
+ *  --------------------------------------------------------------------------
+ */
+
+#ifndef MPI_TARG_H
+#define MPI_TARG_H
+
+
+/******************************************************************************
+*
+*        S C S I    T a r g e t    M e s s a g e s
+*
+*******************************************************************************/
+
+typedef struct _CMD_BUFFER_DESCRIPTOR
+{
+    U16                     IoIndex;
+    U16                     Reserved;
+    union
+    {
+        U32                 PhysicalAddress32;
+        U64                 PhysicalAddress64;
+    } u;
+} CMD_BUFFER_DESCRIPTOR, MPI_POINTER PTR_CMD_BUFFER_DESCRIPTOR,
+  CmdBufferDescriptor_t, MPI_POINTER pCmdBufferDescriptor_t;
+
+
+/****************************************************************************/
+/* Target Command Buffer Post Request                                       */
+/****************************************************************************/
+
+typedef struct _MSG_TARGET_CMD_BUFFER_POST_REQUEST
+{
+    U8                      BufferPostFlags;
+    U8                      BufferCount;
+    U8                      ChainOffset;
+    U8                      Function;
+    U8                      BufferLength;
+    U8                      Reserved;
+    U8                      Reserved1;
+    U8                      MsgFlags;
+    U32                     MsgContext;
+    CMD_BUFFER_DESCRIPTOR   Buffer[1];
+} MSG_TARGET_CMD_BUFFER_POST_REQUEST, MPI_POINTER PTR_MSG_TARGET_CMD_BUFFER_POST_REQUEST,
+  TargetCmdBufferPostRequest_t, MPI_POINTER pTargetCmdBufferPostRequest_t;
+
+#define CMD_BUFFER_POST_FLAGS_PORT_MASK         (0x01)
+#define CMD_BUFFER_POST_FLAGS_ADDR_MODE_MASK    (0x80)
+#define CMD_BUFFER_POST_FLAGS_ADDR_MODE_32      (0)
+#define CMD_BUFFER_POST_FLAGS_ADDR_MODE_64      (1)
+#define CMD_BUFFER_POST_FLAGS_64_BIT_ADDR       (0x80)
+
+#define CMD_BUFFER_POST_IO_INDEX_MASK           (0x00003FFF)
+
+
+typedef struct _MSG_TARGET_CMD_BUFFER_POST_REPLY
+{
+    U8                      BufferPostFlags;
+    U8                      BufferCount;
+    U8                      MsgLength;
+    U8                      Function;
+    U8                      BufferLength;
+    U8                      Reserved;
+    U8                      Reserved1;
+    U8                      MsgFlags;
+    U32                     MsgContext;
+    U16                     Reserved2;
+    U16                     IOCStatus;
+    U32                     IOCLogInfo;
+} MSG_TARGET_CMD_BUFFER_POST_REPLY, MPI_POINTER PTR_MSG_TARGET_CMD_BUFFER_POST_REPLY,
+  TargetCmdBufferPostReply_t, MPI_POINTER pTargetCmdBufferPostReply_t;
+
+
+typedef struct _MSG_PRIORITY_CMD_RECEIVED_REPLY
+{
+    U16                     Reserved;
+    U8                      MsgLength;
+    U8                      Function;
+    U16                     Reserved1;
+    U8                      Reserved2;
+    U8                      MsgFlags;
+    U32                     MsgContext;
+    U8                      PriorityReason;
+    U8                      Reserved3;
+    U16                     IOCStatus;
+    U32                     IOCLogInfo;
+    U32                     ReplyWord;
+} MSG_PRIORITY_CMD_RECEIVED_REPLY, MPI_POINTER PTR_MSG_PRIORITY_CMD_RECEIVED_REPLY,
+  PriorityCommandReceivedReply_t, MPI_POINTER pPriorityCommandReceivedReply_t;
+
+#define PRIORITY_REASON_NO_DISCONNECT           (0x00)
+#define PRIORITY_REASON_SCSI_TASK_MANAGEMENT    (0x01)
+#define PRIORITY_REASON_UNKNOWN                 (0xFF)
+
+
+typedef struct _MSG_TARGET_CMD_BUFFER_POST_ERROR_REPLY
+{
+    U16                     Reserved;
+    U8                      MsgLength;
+    U8                      Function;
+    U16                     Reserved1;
+    U8                      Reserved2;
+    U8                      MsgFlags;
+    U32                     MsgContext;
+    U16                     Reserved3;
+    U16                     IOCStatus;
+    U32                     IOCLogInfo;
+    U32                     ReplyWord;
+} MSG_TARGET_CMD_BUFFER_POST_ERROR_REPLY,
+  MPI_POINTER PTR_MSG_TARGET_CMD_BUFFER_POST_ERROR_REPLY,
+  TargetCmdBufferPostErrorReply_t, MPI_POINTER pTargetCmdBufferPostErrorReply_t;
+
+
+typedef struct _MPI_TARGET_FCP_CMD_BUFFER
+{
+    U8      FcpLun[8];
+    U8      FcpCntl[4];
+    U8      FcpCdb[16];
+    U32     FcpDl;
+} MPI_TARGET_FCP_CMD_BUFFER, MPI_POINTER PTR_MPI_TARGET_FCP_CMD_BUFFER,
+  MpiTargetFcpCmdBuffer, MPI_POINTER pMpiTargetFcpCmdBuffer;
+
+
+typedef struct _MPI_TARGET_SCSI_SPI_CMD_BUFFER
+{
+    /* SPI L_Q information unit */
+    U8      L_QType;
+    U8      Reserved;
+    U16     Tag;
+    U8      LogicalUnitNumber[8];
+    U32     DataLength;
+    /* SPI command information unit */
+    U8      ReservedFirstByteOfCommandIU;
+    U8      TaskAttribute;
+    U8      TaskManagementFlags;
+    U8      AdditionalCDBLength;
+    U8      CDB[16];
+} MPI_TARGET_SCSI_SPI_CMD_BUFFER,
+  MPI_POINTER PTR_MPI_TARGET_SCSI_SPI_CMD_BUFFER,
+  MpiTargetScsiSpiCmdBuffer, MPI_POINTER pMpiTargetScsiSpiCmdBuffer;
+
+
+/****************************************************************************/
+/* Target Assist Request                                                    */
+/****************************************************************************/
+
+typedef struct _MSG_TARGET_ASSIST_REQUEST
+{
+    U8                      StatusCode;
+    U8                      TargetAssistFlags;
+    U8                      ChainOffset;
+    U8                      Function;
+    U16                     QueueTag;
+    U8                      Reserved;
+    U8                      MsgFlags;
+    U32                     MsgContext;
+    U32                     ReplyWord;
+    U8                      LUN[8];
+    U32                     RelativeOffset;
+    U32                     DataLength;
+    SGE_IO_UNION            SGL[1];
+} MSG_TARGET_ASSIST_REQUEST, MPI_POINTER PTR_MSG_TARGET_ASSIST_REQUEST,
+  TargetAssistRequest_t, MPI_POINTER pTargetAssistRequest_t;
+
+#define TARGET_ASSIST_FLAGS_DATA_DIRECTION          (0x01)
+#define TARGET_ASSIST_FLAGS_AUTO_STATUS             (0x02)
+#define TARGET_ASSIST_FLAGS_HIGH_PRIORITY           (0x04)
+#define TARGET_ASSIST_FLAGS_REPOST_CMD_BUFFER       (0x80)
+
+
+typedef struct _MSG_TARGET_ERROR_REPLY
+{
+    U16                     Reserved;
+    U8                      MsgLength;
+    U8                      Function;
+    U16                     Reserved1;
+    U8                      Reserved2;
+    U8                      MsgFlags;
+    U32                     MsgContext;
+    U16                     Reserved3;
+    U16                     IOCStatus;
+    U32                     IOCLogInfo;
+    U32                     ReplyWord;
+    U32                     TransferCount;
+} MSG_TARGET_ERROR_REPLY, MPI_POINTER PTR_MSG_TARGET_ERROR_REPLY,
+  TargetErrorReply_t, MPI_POINTER pTargetErrorReply_t;
+
+
+/****************************************************************************/
+/* Target Status Send Request                                               */
+/****************************************************************************/
+
+typedef struct _MSG_TARGET_STATUS_SEND_REQUEST
+{
+    U8                      StatusCode;
+    U8                      StatusFlags;
+    U8                      ChainOffset;
+    U8                      Function;
+    U16                     QueueTag;
+    U8                      Reserved;
+    U8                      MsgFlags;
+    U32                     MsgContext;
+    U32                     ReplyWord;
+    U8                      LUN[8];
+    SGE_SIMPLE_UNION        StatusDataSGE;
+} MSG_TARGET_STATUS_SEND_REQUEST, MPI_POINTER PTR_MSG_TARGET_STATUS_SEND_REQUEST,
+  TargetStatusSendRequest_t, MPI_POINTER pTargetStatusSendRequest_t;
+
+#define TARGET_STATUS_SEND_FLAGS_AUTO_GOOD_STATUS   (0x01)
+#define TARGET_STATUS_SEND_FLAGS_REPOST_CMD_BUFFER  (0x80)
+
+
+/****************************************************************************/
+/* Target Mode Abort Request                                                */
+/****************************************************************************/
+
+typedef struct _MSG_TARGET_MODE_ABORT_REQUEST
+{
+    U8                      AbortType;
+    U8                      Reserved;
+    U8                      ChainOffset;
+    U8                      Function;
+    U16                     Reserved1;
+    U8                      Reserved2;
+    U8                      MsgFlags;
+    U32                     MsgContext;
+    U32                     ReplyWord;
+    U32                     MsgContextToAbort;
+} MSG_TARGET_MODE_ABORT, MPI_POINTER PTR_MSG_TARGET_MODE_ABORT,
+  TargetModeAbort_t, MPI_POINTER pTargetModeAbort_t;
+
+#define TARGET_MODE_ABORT_TYPE_ALL_CMD_BUFFERS      (0x00)
+#define TARGET_MODE_ABORT_TYPE_ALL_IO               (0x01)
+#define TARGET_MODE_ABORT_TYPE_EXACT_IO             (0x02)
+#define TARGET_MODE_ABORT_TYPE_EXACT_IO_REQUEST     (0x03)
+
+/* Target Mode Abort Reply */
+
+typedef struct _MSG_TARGET_MODE_ABORT_REPLY
+{
+    U16                     Reserved;
+    U8                      MsgLength;
+    U8                      Function;
+    U16                     Reserved1;
+    U8                      Reserved2;
+    U8                      MsgFlags;
+    U32                     MsgContext;
+    U16                     Reserved3;
+    U16                     IOCStatus;
+    U32                     IOCLogInfo;
+    U32                     AbortCount;
+} MSG_TARGET_MODE_ABORT_REPLY, MPI_POINTER PTR_MSG_TARGET_MODE_ABORT_REPLY,
+  TargetModeAbortReply_t, MPI_POINTER pTargetModeAbortReply_t;
+
+
+/****************************************************************************/
+/* Target Mode Context Reply                                                */
+/****************************************************************************/
+
+#define TARGET_MODE_REPLY_IO_INDEX_MASK         (0x00003FFF)
+#define TARGET_MODE_REPLY_IO_INDEX_SHIFT        (0)
+#define TARGET_MODE_REPLY_INITIATOR_INDEX_MASK  (0x03FFC000)
+#define TARGET_MODE_REPLY_INITIATOR_INDEX_SHIFT (14)
+#define TARGET_MODE_REPLY_ALIAS_MASK            (0x0C000000)
+#define TARGET_MODE_REPLY_ALIAS_SHIFT           (26)
+#define TARGET_MODE_REPLY_PORT_MASK             (0x10000000)
+#define TARGET_MODE_REPLY_PORT_SHIFT            (28)
+
+
+#define GET_IO_INDEX(x)     (((x) & TARGET_MODE_REPLY_IO_INDEX_MASK)           \
+                                    >> TARGET_MODE_REPLY_IO_INDEX_SHIFT)
+
+#define SET_IO_INDEX(t, i)                                                     \
+            ((t) = ((t) & ~TARGET_MODE_REPLY_IO_INDEX_MASK) |                  \
+                              (((i) << TARGET_MODE_REPLY_IO_INDEX_SHIFT) &     \
+                                             TARGET_MODE_REPLY_IO_INDEX_MASK))
+
+#define GET_INITIATOR_INDEX(x) (((x) & TARGET_MODE_REPLY_INITIATOR_INDEX_MASK) \
+                                   >> TARGET_MODE_REPLY_INITIATOR_INDEX_SHIFT)
+
+#define SET_INITIATOR_INDEX(t, ii)                                             \
+        ((t) = ((t) & ~TARGET_MODE_REPLY_INITIATOR_INDEX_MASK) |               \
+                        (((ii) << TARGET_MODE_REPLY_INITIATOR_INDEX_SHIFT) &   \
+                                      TARGET_MODE_REPLY_INITIATOR_INDEX_MASK))
+
+#define GET_ALIAS(x) (((x) & TARGET_MODE_REPLY_ALIAS_MASK)                     \
+                                               >> TARGET_MODE_REPLY_ALIAS_SHIFT)
+
+#define SET_ALIAS(t, a)  ((t) = ((t) & ~TARGET_MODE_REPLY_ALIAS_MASK) |        \
+                                    (((a) << TARGET_MODE_REPLY_ALIAS_SHIFT) &  \
+                                                 TARGET_MODE_REPLY_ALIAS_MASK))
+
+#define GET_PORT(x) (((x) & TARGET_MODE_REPLY_PORT_MASK)                       \
+                                               >> TARGET_MODE_REPLY_PORT_SHIFT)
+
+#define SET_PORT(t, p)  ((t) = ((t) & ~TARGET_MODE_REPLY_PORT_MASK) |          \
+                                    (((p) << TARGET_MODE_REPLY_PORT_SHIFT) &   \
+                                                  TARGET_MODE_REPLY_PORT_MASK))
+
+
+#endif
+
diff --git a/drivers/message/fusion/lsi/mpi_type.h b/drivers/message/fusion/lsi/mpi_type.h
new file mode 100644 (file)
index 0000000..733dec7
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ *  Copyright (c) 2000-2001 LSI Logic Corporation.
+ *
+ *
+ *           Name:  MPI_TYPE.H
+ *          Title:  MPI Basic type definitions
+ *  Creation Date:  June 6, 2000
+ *
+ *    MPI Version:  01.01.02
+ *
+ *  Version History
+ *  ---------------
+ *
+ *  Date      Version   Description
+ *  --------  --------  ------------------------------------------------------
+ *  05-08-00  00.10.01  Original release for 0.10 spec dated 4/26/2000.
+ *  06-06-00  01.00.01  Update version number for 1.0 release.
+ *  11-02-00  01.01.01  Original release for post 1.0 work
+ *  02-20-01  01.01.02  Added define and ifdef for MPI_POINTER.
+ *  --------------------------------------------------------------------------
+ */
+
+#ifndef MPI_TYPE_H
+#define MPI_TYPE_H
+
+
+/*******************************************************************************
+ * Define MPI_POINTER if it hasn't already been defined. By default MPI_POINTER
+ * is defined to be a near pointer. MPI_POINTER can be defined as a far pointer
+ * by defining MPI_POINTER as "far *" before this header file is included.
+ */
+#ifndef MPI_POINTER
+#define MPI_POINTER     *
+#endif
+
+
+/*****************************************************************************
+*
+*               B a s i c    T y p e s
+*
+*****************************************************************************/
+
+typedef signed   char   S8;
+typedef unsigned char   U8;
+typedef signed   short  S16;
+typedef unsigned short  U16;
+
+
+#if defined(unix) || defined(__arm) || defined(ALPHA)
+
+    typedef signed   int   S32;
+    typedef unsigned int   U32;
+
+#else
+
+    typedef signed   long  S32;
+    typedef unsigned long  U32;
+
+#endif
+
+
+typedef struct _S64
+{
+    U32          Low;
+    S32          High;
+} S64;
+
+typedef struct _U64
+{
+    U32          Low;
+    U32          High;
+} U64;
+
+
+/****************************************************************************/
+/*  Pointers                                                                */
+/****************************************************************************/
+
+typedef S8      *PS8;
+typedef U8      *PU8;
+typedef S16     *PS16;
+typedef U16     *PU16;
+typedef S32     *PS32;
+typedef U32     *PU32;
+typedef S64     *PS64;
+typedef U64     *PU64;
+
+
+#endif
+
diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c
new file mode 100644 (file)
index 0000000..0ada7fe
--- /dev/null
@@ -0,0 +1,3360 @@
+/*
+ *  linux/drivers/message/fusion/mptbase.c
+ *      High performance SCSI + LAN / Fibre Channel device drivers.
+ *      This is the Fusion MPT base driver which supports multiple
+ *      (SCSI + LAN) specialized protocol drivers.
+ *      For use with PCI chip/adapter(s):
+ *          LSIFC9xx/LSI409xx Fibre Channel
+ *      running LSI Logic Fusion MPT (Message Passing Technology) firmware.
+ *
+ *  Credits:
+ *      There are lots of people not mentioned below that deserve credit
+ *      and thanks but won't get it here - sorry in advance that you
+ *      got overlooked.
+ *
+ *      This driver would not exist if not for Alan Cox's development
+ *      of the linux i2o driver.
+ *
+ *      A special thanks to Noah Romer (LSI Logic) for tons of work
+ *      and tough debugging on the LAN driver, especially early on;-)
+ *      And to Roger Hickerson (LSI Logic) for tirelessly supporting
+ *      this driver project.
+ *
+ *      All manner of help from Stephen Shirron (LSI Logic):
+ *      low-level FC analysis, debug + various fixes in FCxx firmware,
+ *      initial port to alpha platform, various driver code optimizations,
+ *      being a faithful sounding board on all sorts of issues & ideas,
+ *      etc.
+ *
+ *      A huge debt of gratitude is owed to David S. Miller (DaveM)
+ *      for fixing much of the stupid and broken stuff in the early
+ *      driver while porting to sparc64 platform.  THANK YOU!
+ *
+ *      Special thanks goes to the I2O LAN driver people at the
+ *      University of Helsinki, who, unbeknownst to them, provided
+ *      the inspiration and initial structure for this driver.
+ *
+ *      A really huge debt of gratitude is owed to Eddie C. Dost
+ *      for gobs of hard work fixing and optimizing LAN code.
+ *      THANK YOU!
+ *
+ *  Copyright (c) 1999-2001 LSI Logic Corporation
+ *  Originally By: Steven J. Ralston
+ *  (mailto:Steve.Ralston@lsil.com)
+ *
+ *  $Id: mptbase.c,v 1.47 2001/03/22 10:32:23 sralston Exp $
+ */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; version 2 of the License.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    NO WARRANTY
+    THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+    CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+    LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+    MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+    solely responsible for determining the appropriateness of using and
+    distributing the Program and assumes all risks associated with its
+    exercise of rights under this Agreement, including but not limited to
+    the risks and costs of program errors, damage to or loss of data,
+    programs or equipment, and unavailability or interruption of operations.
+
+    DISCLAIMER OF LIABILITY
+    NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+    DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
+    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+    TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+    USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+    HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kdev_t.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/proc_fs.h>
+#include <asm/io.h>
+#ifdef CONFIG_MTRR
+#include <asm/mtrr.h>
+#endif
+
+#include "mptbase.h"
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+#define my_NAME                "Fusion MPT base driver"
+#define my_VERSION     MPT_LINUX_VERSION_COMMON
+#define MYNAM          "mptbase"
+
+MODULE_AUTHOR(MODULEAUTHOR);
+MODULE_DESCRIPTION(my_NAME);
+
+/*
+ *  cmd line parameters
+ */
+MODULE_PARM(PortIo, "0-1i");
+MODULE_PARM_DESC(PortIo, "[0]=Use mmap, 1=Use port io");
+MODULE_PARM(HardReset, "0-1i");
+MODULE_PARM_DESC(HardReset, "0=Disable HardReset, [1]=Enable HardReset");
+static int PortIo = 0;
+static int HardReset = 1;
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *  Public data...
+ */
+int mpt_lan_index = 0;
+int mpt_stm_index = 0;
+
+void *mpt_v_ASCQ_TablePtr = NULL;
+const char **mpt_ScsiOpcodesPtr = NULL;
+int mpt_ASCQ_TableSz = 0;
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *  Private data...
+ */
+                                       /* Adapter lookup table */
+static MPT_ADAPTER             *mpt_adapters[MPT_MAX_ADAPTERS] = {0};
+static MPT_ADAPTER_TRACKER      MptAdapters;
+                                       /* Callback lookup table */
+static MPT_CALLBACK             MptCallbacks[MPT_MAX_PROTOCOL_DRIVERS];
+                                       /* Protocol driver class lookup table */
+static int                      MptDriverClass[MPT_MAX_PROTOCOL_DRIVERS];
+                                       /* Event handler lookup table */
+static MPT_EVHANDLER            MptEvHandlers[MPT_MAX_PROTOCOL_DRIVERS];
+
+static int     FusionInitCalled = 0;
+static int     mpt_base_index = -1;
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *  Forward protos...
+ */
+static void    mpt_interrupt(int irq, void *bus_id, struct pt_regs *r);
+static int     mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply);
+
+static int     mpt_adapter_install(struct pci_dev *pdev);
+static void    mpt_detect_929_bound_ports(MPT_ADAPTER *this, struct pci_dev *pdev);
+static void    mpt_adapter_disable(MPT_ADAPTER *ioc);
+static void    mpt_adapter_dispose(MPT_ADAPTER *ioc);
+
+static void    MptDisplayIocCapabilities(MPT_ADAPTER *ioc);
+static u32     GetIocState(MPT_ADAPTER *ioc, int cooked);
+static int     GetIocFacts(MPT_ADAPTER *ioc);
+static int     GetPortFacts(MPT_ADAPTER *ioc);
+static int     SendIocInit(MPT_ADAPTER *ioc);
+static int     SendPortEnable(MPT_ADAPTER *ioc, int portnum);
+static int     mpt_fc9x9_reset(MPT_ADAPTER *ioc);
+static int     KickStart(MPT_ADAPTER *ioc);
+static int     SendIocReset(MPT_ADAPTER *ioc, u8 reset_type);
+static int     PrimeIocFifos(MPT_ADAPTER *ioc);
+static int     HandShakeReqAndReply(MPT_ADAPTER *ioc, int reqBytes, u32 *req, int replyBytes, u16 *u16reply);
+static int     WaitForDoorbellAck(MPT_ADAPTER *ioc);
+static int     WaitForDoorbellInt(MPT_ADAPTER *ioc);
+static int     WaitForDoorbellReply(MPT_ADAPTER *ioc);
+static int     GetLanConfigPages(MPT_ADAPTER *ioc);
+static int     SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch);
+static int     SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp);
+
+static int     procmpt_create(void);
+#ifdef CONFIG_PROC_FS
+static int     procmpt_destroy(void);
+#endif
+static int     procmpt_read_summary(char *page, char **start, off_t off, int count, int *eof, void *data);
+static int     procmpt_read_dbg(char *page, char **start, off_t off, int count, int *eof, void *data);
+/*static int   procmpt_info(char *buf, char **start, off_t offset, int len);*/
+
+static int     ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *evReply, int *evHandlers);
+static void    mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info);
+static void    mpt_sp_log_info(MPT_ADAPTER *ioc, u32 log_info);
+
+static struct proc_dir_entry   *procmpt_root_dir = NULL;
+
+int            fusion_init(void);
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/* 20000207 -sralston
+ *  GRRRRR...  IOSpace (port i/o) register access (for the 909) is back!
+ * 20000517 -sralston
+ *  Let's trying going back to default mmap register access...
+ */
+
+static inline u32 CHIPREG_READ32(volatile u32 *a)
+{
+       if (PortIo)
+               return inl((unsigned long)a);
+       else
+               return readl(a);
+}
+
+static inline void CHIPREG_WRITE32(volatile u32 *a, u32 v)
+{
+       if (PortIo)
+               outl(v, (unsigned long)a);
+       else
+               writel(v, a);
+}
+
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mpt_interrupt - MPT adapter (IOC) specific interrupt handler.
+ *     @irq: irq number (not used)
+ *     @bus_id: bus identifier cookie == pointer to MPT_ADAPTER structure
+ *     @r: pt_regs pointer (not used)
+ *
+ *     This routine is registered via the request_irq() kernel API call,
+ *     and handles all interrupts generated from a specific MPT adapter
+ *     (also referred to as a IO Controller or IOC).
+ *     This routine must clear the interrupt from the adapter and does
+ *     so by reading the reply FIFO.  Multiple replies may be processed
+ *     per single call to this routine; up to MPT_MAX_REPLIES_PER_ISR
+ *     which is currently set to 32 in mptbase.h.
+ *
+ *     This routine handles register-level access of the adapter but
+ *     dispatches (calls) a protocol-specific callback routine to handle
+ *     the protocol-specific details of the MPT request completion.
+ */
+static void
+mpt_interrupt(int irq, void *bus_id, struct pt_regs *r)
+{
+       MPT_ADAPTER     *ioc;
+       MPT_FRAME_HDR   *mf;
+       MPT_FRAME_HDR   *mr;
+       u32              pa;
+       u32             *m;
+       int              req_idx;
+       int              cb_idx;
+       int              type;
+       int              freeme;
+       int              count = 0;
+
+       ioc = bus_id;
+
+       /*
+        *  Drain the reply FIFO!
+        *
+        * NOTES: I've seen up to 10 replies processed in this loop, so far...
+        * Update: I've seen up to 9182 replies processed in this loop! ??
+        * Update: Limit ourselves to processing max of N replies
+        *      (bottom of loop).
+        */
+       while (1) {
+
+               if ((pa = CHIPREG_READ32(&ioc->chip->ReplyFifo)) == 0xFFFFFFFF)
+                       return;
+
+               cb_idx = 0;
+               freeme = 0;
+
+               /*
+                *  Check for non-TURBO reply!
+                */
+               if (pa & MPI_ADDRESS_REPLY_A_BIT) {
+                       dma_addr_t reply_dma_addr;
+                       u16 ioc_stat;
+
+                       /* non-TURBO reply!  Hmmm, something may be up...
+                        *  Newest turbo reply mechanism; get address
+                        *  via left shift 1 (get rid of MPI_ADDRESS_REPLY_A_BIT)!
+                        */
+                       reply_dma_addr = (pa = (pa << 1));
+
+                       /* Map DMA address of reply header to cpu address. */
+                       m = (u32 *) ((u8 *)ioc->reply_frames +
+                                       (reply_dma_addr - ioc->reply_frames_dma));
+
+                       mr = (MPT_FRAME_HDR *) m;
+                       req_idx = le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx);
+                       cb_idx = mr->u.frame.hwhdr.msgctxu.fld.cb_idx;
+                       mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
+
+                       dprintk((KERN_INFO MYNAM ": %s: Got non-TURBO reply=%p\n",
+                                       ioc->name, mr));
+                       DBG_DUMP_REPLY_FRAME(mr)
+
+                       /* NEW!  20010301 -sralston
+                        *  Check/log IOC log info
+                        */
+                       ioc_stat = le16_to_cpu(mr->u.reply.IOCStatus);
+                       if (ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
+                               u32      log_info = le32_to_cpu(mr->u.reply.IOCLogInfo);
+                               if ((int)ioc->chip_type <= (int)FC929)
+                                       mpt_fc_log_info(ioc, log_info);
+                               else
+                                       mpt_sp_log_info(ioc, log_info);
+                       }
+               } else {
+                       /*
+                        *  Process turbo (context) reply...
+                        */
+                       dirqprintk((KERN_INFO MYNAM ": %s: Got TURBO reply(=%08x)\n", ioc->name, pa));
+                       type = (pa >> MPI_CONTEXT_REPLY_TYPE_SHIFT);
+                       if (type == MPI_CONTEXT_REPLY_TYPE_SCSI_TARGET) {
+                               cb_idx = mpt_stm_index;
+                               mf = NULL;
+                               mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
+                       } else if (type == MPI_CONTEXT_REPLY_TYPE_LAN) {
+                               cb_idx = mpt_lan_index;
+                               /*
+                                * BUG FIX!  20001218 -sralston
+                                *  Blind set of mf to NULL here was fatal
+                                *  after lan_reply says "freeme"
+                                *  Fix sort of combined with an optimization here;
+                                *  added explicit check for case where lan_reply
+                                *  was just returning 1 and doing nothing else.
+                                *  For this case skip the callback, but set up
+                                *  proper mf value first here:-)
+                                */
+                               if ((pa & 0x58000000) == 0x58000000) {
+                                       req_idx = pa & 0x0000FFFF;
+                                       mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
+                                       freeme = 1;
+                                       /*
+                                        *  IMPORTANT!  Invalidate the callback!
+                                        */
+                                       cb_idx = 0;
+                               } else {
+                                       mf = NULL;
+                               }
+                               mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
+                       } else {
+                               req_idx = pa & 0x0000FFFF;
+                               cb_idx = (pa & 0x00FF0000) >> 16;
+                               mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
+                               mr = NULL;
+                       }
+                       pa = 0;                                 /* No reply flush! */
+               }
+
+               /*  Check for (valid) IO callback!  */
+               if (cb_idx) {
+                       /*  Do the callback!  */
+                       freeme = (*(MptCallbacks[cb_idx]))(ioc, mf, mr);
+               }
+
+               if (pa) {
+                       /*  Flush (non-TURBO) reply with a WRITE!  */
+                       CHIPREG_WRITE32(&ioc->chip->ReplyFifo, pa);
+               }
+
+               if (freeme) {
+                       unsigned long flags;
+
+                       /*  Put Request back on FreeQ!  */
+                       spin_lock_irqsave(&ioc->FreeQlock, flags);
+                       Q_ADD_TAIL(&ioc->FreeQ, &mf->u.frame.linkage, MPT_FRAME_HDR);
+                       spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+               }
+
+               count++;
+               dirqprintk((KERN_INFO MYNAM ": %s: ISR processed frame #%d\n", ioc->name, count));
+               mb();
+
+               if (count >= MPT_MAX_REPLIES_PER_ISR) {
+                       dirqprintk((KERN_INFO MYNAM ": %s: ISR processed %d replies.",
+                                       ioc->name, count));
+                       dirqprintk((" Giving this ISR a break!\n"));
+                       return;
+               }
+
+       }       /* drain reply FIFO */
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     mpt_base_reply - MPT base driver's callback routine; all base driver
+ *     "internal" request/reply processing is routed here.
+ *     Currently used for EventNotification and EventAck handling.
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @mf: Pointer to original MPT request frame
+ *     @reply: Pointer to MPT reply frame (NULL if TurboReply)
+ *
+ *     Returns 1 indicating original alloc'd request frame ptr
+ *     should be freed, or 0 if it shouldn't.
+ */
+static int
+mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply)
+{
+       int freereq = 1;
+       u8 func;
+
+       dprintk((KERN_INFO MYNAM ": %s: mpt_base_reply() called\n", ioc->name));
+
+       if ((mf == NULL) ||
+           (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) {
+               printk(KERN_ERR MYNAM ": %s: ERROR - NULL or BAD request frame ptr! (=%p)\n",
+                               ioc->name, mf);
+               return 1;
+       }
+
+       if (reply == NULL) {
+               dprintk((KERN_ERR MYNAM ": %s: ERROR - Unexpected NULL Event (turbo?) reply!\n",
+                               ioc->name));
+               return 1;
+       }
+
+       if (!(reply->u.hdr.MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)) {
+               dmfprintk((KERN_INFO MYNAM ": Original request frame (@%p) header\n", mf));
+               DBG_DUMP_REQUEST_FRAME_HDR(mf)
+       }
+
+       func = reply->u.hdr.Function;
+       dprintk((KERN_INFO MYNAM ": %s: mpt_base_reply, Function=%02Xh\n",
+                       ioc->name, func));
+
+       if (func == MPI_FUNCTION_EVENT_NOTIFICATION) {
+               EventNotificationReply_t *pEvReply = (EventNotificationReply_t *) reply;
+               int evHandlers = 0;
+               int results;
+
+               results = ProcessEventNotification(ioc, pEvReply, &evHandlers);
+               if (results != evHandlers) {
+                       /* CHECKME! Any special handling needed here? */
+                       dprintk((KERN_WARNING MYNAM ": %s: Hmmm... Called %d event handlers, sum results = %d\n",
+                                       ioc->name, evHandlers, results));
+               }
+
+               /*
+                *  Hmmm...  It seems that EventNotificationReply is an exception
+                *  to the rule of one reply per request.
+                */
+               if (pEvReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)
+                       freereq = 0;
+#ifdef CONFIG_PROC_FS
+//             LogEvent(ioc, pEvReply);
+#endif
+       } else if (func == MPI_FUNCTION_EVENT_ACK) {
+               dprintk((KERN_INFO MYNAM ": %s: mpt_base_reply, EventAck reply received\n",
+                               ioc->name));
+       } else {
+               printk(KERN_ERR MYNAM ": %s: ERROR - Unexpected msg function (=%02Xh) reply received!\n",
+                               ioc->name, func);
+       }
+
+       /*
+        *  Conditionally tell caller to free the original
+        *  EventNotification/EventAck/unexpected request frame!
+        */
+       return freereq;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mpt_register - Register protocol-specific main callback handler.
+ *     @cbfunc: callback function pointer
+ *     @dclass: Protocol driver's class (%MPT_DRIVER_CLASS enum value)
+ *
+ *     This routine is called by a protocol-specific driver (SCSI host,
+ *     LAN, SCSI target) to register it's reply callback routine.  Each
+ *     protocol-specific driver must do this before it will be able to
+ *     use any IOC resources, such as obtaining request frames.
+ *
+ *     NOTES: The SCSI protocol driver currently calls this routine twice
+ *     in order to register separate callbacks; one for "normal" SCSI IO
+ *     and another for MptScsiTaskMgmt requests.
+ *
+ *     Returns a positive integer valued "handle" in the
+ *     range (and S.O.D. order) {7,6,...,1} if successful.
+ *     Any non-positive return value (including zero!) should be considered
+ *     an error by the caller.
+ */
+int
+mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass)
+{
+       int r = -1;
+       int i;
+
+#ifndef MODULE
+       /*
+        *  Handle possibility of the mptscsih_detect() routine getting
+        *  called *before* fusion_init!
+        */
+       if (!FusionInitCalled) {
+               dprintk((KERN_INFO MYNAM ": Hmmm, calling fusion_init from mpt_register!\n"));
+               /*
+                *  NOTE! We'll get recursion here, as fusion_init()
+                *  calls mpt_register()!
+                */
+               fusion_init();
+               FusionInitCalled++;
+       }
+#endif
+
+       /*
+        *  Search for empty callback slot in this order: {7,6,...,1}
+        *  (slot/handle 0 is reserved!)
+        */
+       for (i = MPT_MAX_PROTOCOL_DRIVERS-1; i; i--) {
+               if (MptCallbacks[i] == NULL) {
+                       MptCallbacks[i] = cbfunc;
+                       MptDriverClass[i] = dclass;
+                       MptEvHandlers[i] = NULL;
+                       r = i;
+                       if (cbfunc != mpt_base_reply) {
+                               MOD_INC_USE_COUNT;
+                       }
+                       break;
+               }
+       }
+
+       return r;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mpt_deregister - Deregister a protocol drivers resources.
+ *     @cb_idx: previously registered callback handle
+ *
+ *     Each protocol-specific driver should call this routine when it's
+ *     module is unloaded.
+ */
+void
+mpt_deregister(int cb_idx)
+{
+       if (cb_idx && (cb_idx < MPT_MAX_PROTOCOL_DRIVERS)) {
+               MptCallbacks[cb_idx] = NULL;
+               MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
+               MptEvHandlers[cb_idx] = NULL;
+               if (cb_idx != mpt_base_index) {
+                       MOD_DEC_USE_COUNT;
+               }
+       }
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mpt_event_register - Register protocol-specific event callback
+ *     handler.
+ *     @cb_idx: previously registered (via mpt_register) callback handle
+ *     @ev_cbfunc: callback function
+ *
+ *     This routine can be called by one or more protocol-specific drivers
+ *     if/when they choose to be notified of MPT events.
+ *
+ *     Returns 0 for success.
+ */
+int
+mpt_event_register(int cb_idx, MPT_EVHANDLER ev_cbfunc)
+{
+       if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
+               return -1;
+
+       MptEvHandlers[cb_idx] = ev_cbfunc;
+       return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mpt_event_deregister - Deregister protocol-specific event callback
+ *     handler.
+ *     @cb_idx: previously registered callback handle
+ *
+ *     Each protocol-specific driver should call this routine
+ *     when it does not (or can no longer) handle events,
+ *     or when it's module is unloaded.
+ */
+void
+mpt_event_deregister(int cb_idx)
+{
+       if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
+               return;
+
+       MptEvHandlers[cb_idx] = NULL;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mpt_get_msg_frame - Obtain a MPT request frame from the pool (of 1024)
+ *     allocated per MPT adapter.
+ *     @handle: Handle of registered MPT protocol driver
+ *     @iocid: IOC unique identifier (integer)
+ *
+ *     Returns pointer to a MPT request frame or %NULL if none are available.
+ */
+MPT_FRAME_HDR*
+mpt_get_msg_frame(int handle, int iocid)
+{
+       MPT_FRAME_HDR *mf = NULL;
+       MPT_ADAPTER *iocp;
+       unsigned long flags;
+
+       /* validate handle and ioc identifier */
+       iocp = mpt_adapters[iocid];
+       spin_lock_irqsave(&iocp->FreeQlock, flags);
+       if (! Q_IS_EMPTY(&iocp->FreeQ)) {
+               int req_offset;
+
+               mf = iocp->FreeQ.head;
+               Q_DEL_ITEM(&mf->u.frame.linkage);
+               mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle;  /* byte */
+               req_offset = (u8 *)mf - (u8 *)iocp->req_frames;
+                                                               /* u16! */
+               mf->u.frame.hwhdr.msgctxu.fld.req_idx =
+                               cpu_to_le16(req_offset / iocp->req_sz);
+               mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
+       }
+       spin_unlock_irqrestore(&iocp->FreeQlock, flags);
+       dmfprintk((KERN_INFO MYNAM ": %s: mpt_get_msg_frame(%d,%d), got mf=%p\n",
+                       iocp->name, handle, iocid, mf));
+       return mf;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mpt_put_msg_frame - Send a protocol specific MPT request frame
+ *     to a IOC.
+ *     @handle: Handle of registered MPT protocol driver
+ *     @iocid: IOC unique identifier (integer)
+ *     @mf: Pointer to MPT request frame
+ *
+ *     This routine posts a MPT request frame to the request post FIFO of a
+ *     specific MPT adapter.
+ */
+void
+mpt_put_msg_frame(int handle, int iocid, MPT_FRAME_HDR *mf)
+{
+       MPT_ADAPTER *iocp;
+
+       iocp = mpt_adapters[iocid];
+       if (iocp != NULL) {
+               dma_addr_t mf_dma_addr;
+               int req_offset;
+
+               /* ensure values are reset properly! */
+               mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle;          /* byte */
+               req_offset = (u8 *)mf - (u8 *)iocp->req_frames;
+                                                                       /* u16! */
+               mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_offset / iocp->req_sz);
+               mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
+
+#ifdef MPT_DEBUG_MSG_FRAME
+               {
+                       u32     *m = mf->u.frame.hwhdr.__hdr;
+                       int      i, n;
+
+                       printk(KERN_INFO MYNAM ": %s: About to Put msg frame @ %p:\n" KERN_INFO " ",
+                                       iocp->name, m);
+                       n = iocp->req_sz/4 - 1;
+                       while (m[n] == 0)
+                               n--;
+                       for (i=0; i<=n; i++) {
+                               if (i && ((i%8)==0))
+                                       printk("\n" KERN_INFO " ");
+                               printk(" %08x", le32_to_cpu(m[i]));
+                       }
+                       printk("\n");
+               }
+#endif
+
+               mf_dma_addr = iocp->req_frames_dma + req_offset;
+               CHIPREG_WRITE32(&iocp->chip->RequestFifo, mf_dma_addr);
+       }
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mpt_free_msg_frame - Place MPT request frame back on FreeQ.
+ *     @handle: Handle of registered MPT protocol driver
+ *     @iocid: IOC unique identifier (integer)
+ *     @mf: Pointer to MPT request frame
+ *
+ *     This routine places a MPT request frame back on the MPT adapter's
+ *     FreeQ.
+ */
+void
+mpt_free_msg_frame(int handle, int iocid, MPT_FRAME_HDR *mf)
+{
+       MPT_ADAPTER *iocp;
+       unsigned long flags;
+
+       iocp = mpt_adapters[iocid];
+       if (iocp != NULL) {
+               /*  Put Request back on FreeQ!  */
+               spin_lock_irqsave(&iocp->FreeQlock, flags);
+               Q_ADD_TAIL(&iocp->FreeQ, &mf->u.frame.linkage, MPT_FRAME_HDR);
+               spin_unlock_irqrestore(&iocp->FreeQlock, flags);
+       }
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mpt_send_handshake_request - Send MPT request via doorbell
+ *     handshake method.
+ *     @handle: Handle of registered MPT protocol driver
+ *     @iocid: IOC unique identifier (integer)
+ *     @reqBytes: Size of the request in bytes
+ *     @req: Pointer to MPT request frame
+ *
+ *     This routine is used exclusively by mptscsih to send MptScsiTaskMgmt
+ *     requests since they are required to be sent via doorbell handshake.
+ *
+ *     NOTE: It is the callers responsibility to byte-swap fields in the
+ *     request which are greater than 1 byte in size.
+ *
+ *     Returns 0 for success, non-zero for failure.
+ */
+int
+mpt_send_handshake_request(int handle, int iocid, int reqBytes, u32 *req)
+{
+       MPT_ADAPTER     *iocp;
+       int              r = 0;
+
+       iocp = mpt_adapters[iocid];
+       if (iocp != NULL) {
+               u8 *req_as_bytes;
+               int i;
+
+               /*
+                *  Emulate what mpt_put_msg_frame() does /wrt to sanity
+                *  setting cb_idx/req_idx.  But ONLY if this request
+                *  is in proper (pre-alloc'd) request buffer range...
+                */
+               i = MFPTR_2_MPT_INDEX(iocp,(MPT_FRAME_HDR*)req);
+               if (reqBytes >= 12 && i >= 0 && i < iocp->req_depth) {
+                       MPT_FRAME_HDR *mf = (MPT_FRAME_HDR*)req;
+                       mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(i);
+                       mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle;
+               }
+
+               /*  Make sure there are no doorbells  */
+               CHIPREG_WRITE32(&iocp->chip->IntStatus, 0);
+
+               CHIPREG_WRITE32(&iocp->chip->Doorbell,
+                               ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
+                                ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
+
+               /*  Wait for IOC doorbell int  */
+               if ((i = WaitForDoorbellInt(iocp)) < 0) {
+                       /* FIXME! Recovery action(s)? */
+                       /*i = unresponsive_ioc(i);*/
+                       return i;
+               }
+
+               dhsprintk((KERN_INFO MYNAM ": %s: mpt_send_handshake_request start, WaitCnt=%d\n",
+                               iocp->name, i));
+
+               CHIPREG_WRITE32(&iocp->chip->IntStatus, 0);
+
+               if ((r = WaitForDoorbellAck(iocp)) < 0)
+                       return -2;
+
+               /*  Send request via doorbell handshake  */
+               req_as_bytes = (u8 *) req;
+               for (i = 0; i < reqBytes/4; i++) {
+                       u32 word;
+
+                       word = ((req_as_bytes[(i*4) + 0] <<  0) |
+                               (req_as_bytes[(i*4) + 1] <<  8) |
+                               (req_as_bytes[(i*4) + 2] << 16) |
+                               (req_as_bytes[(i*4) + 3] << 24));
+                       CHIPREG_WRITE32(&iocp->chip->Doorbell, word);
+                       if ((r = WaitForDoorbellAck(iocp)) < 0) {
+                               r = -3;
+                               break;
+                       }
+               }
+
+               /*  Make sure there are no doorbells  */
+               CHIPREG_WRITE32(&iocp->chip->IntStatus, 0);
+
+       }
+
+       return r;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mpt_adapter_find_first - Find first MPT adapter pointer.
+ *
+ *     Returns first MPT adapter pointer or %NULL if no MPT adapters
+ *     are present.
+ */
+MPT_ADAPTER *
+mpt_adapter_find_first(void)
+{
+       MPT_ADAPTER *this = NULL;
+
+       if (! Q_IS_EMPTY(&MptAdapters))
+               this = MptAdapters.head;
+
+       return this;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mpt_adapter_find_next - Find next MPT adapter pointer.
+ *     @prev: Pointer to previous MPT adapter
+ *
+ *     Returns next MPT adapter pointer or %NULL if there are no more.
+ */
+MPT_ADAPTER *
+mpt_adapter_find_next(MPT_ADAPTER *prev)
+{
+       MPT_ADAPTER *next = NULL;
+
+       if (prev && (prev->forw != (MPT_ADAPTER*)&MptAdapters.head))
+               next = prev->forw;
+
+       return next;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mpt_pci_scan - Scan PCI devices for MPT adapters.
+ *
+ *     Returns count of MPT adapters found, keying off of PCI vendor and
+ *     device_id's.
+ */
+int __init
+mpt_pci_scan(void)
+{
+       struct pci_dev *pdev;
+       struct pci_dev *pdev2;
+       int found = 0;
+       int count = 0;
+       int r;
+
+       dprintk((KERN_INFO MYNAM ": Checking for MPT adapters...\n"));
+
+       /*
+        *  NOTE: The 929 (I believe) will appear as 2 separate PCI devices,
+        *  one for each channel.
+        */
+       pci_for_each_dev(pdev) {
+               pdev2 = NULL;
+               if (pdev->vendor != 0x1000)
+                       continue;
+
+               if ((pdev->device != MPI_MANUFACTPAGE_DEVICEID_FC909) &&
+                   (pdev->device != MPI_MANUFACTPAGE_DEVICEID_FC929) &&
+#if 0
+                   /* FIXME! FC919 */
+                   (pdev->device != MPI_MANUFACTPAGE_DEVICEID_FC919) &&
+                   /* FIXME! C103x family */
+                   (pdev->device != MPI_MANUFACTPAGE_DEVID_53C1030) &&
+                   (pdev->device != MPI_MANUFACTPAGE_DEVID_53C1030_ZC) &&
+                   (pdev->device != MPI_MANUFACTPAGE_DEVID_53C1035) &&
+#endif
+                   1) {
+                       dprintk((KERN_INFO MYNAM ": Skipping LSI device=%04xh\n", pdev->device));
+                       continue;
+               }
+
+               /* GRRRRR
+                * 929 dual function devices may be presented in Func 1,0 order,
+                * but we'd really really rather have them in Func 0,1 order.
+                * Do some kind of look ahead here...
+                */
+               if (pdev->devfn & 1) {
+                       pdev2 = pci_peek_next_dev(pdev);
+                       if (pdev2 && (pdev2->vendor == 0x1000) &&
+                           (PCI_SLOT(pdev2->devfn) == PCI_SLOT(pdev->devfn)) &&
+                           (pdev2->device == MPI_MANUFACTPAGE_DEVICEID_FC929) &&
+                           (pdev2->bus->number == pdev->bus->number) &&
+                           !(pdev2->devfn & 1)) {
+                               dprintk((KERN_INFO MYNAM ": MPT adapter found: PCI bus/dfn=%02x/%02xh, class=%08x, id=%xh\n",
+                                       pdev2->bus->number, pdev2->devfn, pdev2->class, pdev2->device));
+                               found++;
+                               if ((r = mpt_adapter_install(pdev2)) == 0)
+                                       count++;
+                       } else {
+                               pdev2 = NULL;
+                       }
+               }
+
+               dprintk((KERN_INFO MYNAM ": MPT adapter found: PCI bus/dfn=%02x/%02xh, class=%08x, id=%xh\n",
+                        pdev->bus->number, pdev->devfn, pdev->class, pdev->device));
+               found++;
+               if ((r = mpt_adapter_install(pdev)) == 0)
+                       count++;
+
+               if (pdev2)
+                       pdev = pdev2;
+       }
+
+       printk(KERN_INFO MYNAM ": %d MPT adapter%s found, %d installed.\n",
+                found, (found==1) ? "" : "s", count);
+
+       if (count == 0)
+               return -ENODEV;
+
+#ifdef CONFIG_PROC_FS
+       if (procmpt_create() != 0)
+               printk(KERN_WARNING MYNAM ": WARNING! - %s creation failed!\n",
+                               MPT_PROCFS_MPTBASEDIR);
+#endif
+
+       return count;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mpt_verify_adapter - Given a unique IOC identifier, set pointer to
+ *     the associated MPT adapter structure.
+ *     @iocid: IOC unique identifier (integer)
+ *     @iocpp: Pointer to pointer to IOC adapter
+ *
+ *     Returns iocid and sets iocpp.
+ */
+int
+mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp)
+{
+       MPT_ADAPTER *p;
+
+       *iocpp = NULL;
+       if (iocid >= MPT_MAX_ADAPTERS)
+               return -1;
+
+       p = mpt_adapters[iocid];
+       if (p == NULL)
+               return -1;
+
+       *iocpp = p;
+       return iocid;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mpt_adapter_install - Install a PCI intelligent MPT adapter.
+ *     @pdev: Pointer to pci_dev structure
+ *
+ *     This routine performs all the steps necessary to bring the IOC of
+ *     a MPT adapter to a OPERATIONAL state.  This includes registering
+ *     memory regions, registering the interrupt, and allocating request
+ *     and reply memory pools.
+ *
+ *     This routine also pre-fetches the LAN MAC address of a Fibre Channel
+ *     MPT adapter.
+ *
+ *     Returns 0 for success, non-zero for failure.
+ *
+ *     TODO: Add support for polled controllers
+ */
+static int __init
+mpt_adapter_install(struct pci_dev *pdev)
+{
+       MPT_ADAPTER     *ioc;
+       char            *myname;
+       u8              *mem;
+       unsigned long    mem_phys;
+       unsigned long    port;
+       u32              msize;
+       u32              psize;
+       u32              ioc_state;
+       int              i;
+       int              r = -ENODEV;
+       int              cntdn;
+       int              len;
+       int              statefault = 0;
+
+       ioc = kmalloc(sizeof(MPT_ADAPTER), GFP_KERNEL);
+       if (ioc == NULL) {
+               printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n");
+               return -ENOMEM;
+       }
+       memset(ioc, 0, sizeof(*ioc));
+       ioc->req_sz = MPT_REQ_SIZE;                     /* avoid div by zero! */
+       ioc->alloc_total = sizeof(MPT_ADAPTER);
+
+       ioc->pcidev = pdev;
+
+       /*  Find lookup slot.  GRRRR...  */
+       for (i=0; i < MPT_MAX_ADAPTERS; i++) {
+               if (mpt_adapters[i] == NULL) {
+                       ioc->id = i;            /* Assign adapter unique id (lookup) */
+                       break;
+               }
+       }
+       if (i == MPT_MAX_ADAPTERS) {
+               printk(KERN_ERR MYNAM ": ERROR - mpt_adapters[%d] table overflow!\n", i);
+               kfree(ioc);
+               return -ENFILE;
+       }
+
+       mem_phys = msize = 0;
+       port = psize = 0;
+       for (i=0; i < DEVICE_COUNT_RESOURCE; i++) {
+               if (pdev->PCI_BASEADDR_FLAGS(i) & PCI_BASE_ADDRESS_SPACE_IO) {
+                       /*  Get I/O space!  */
+                       port = pdev->PCI_BASEADDR_START(i);
+                       psize = PCI_BASEADDR_SIZE(pdev,i);
+               } else {
+                       /*  Get memmap  */
+                       mem_phys = pdev->PCI_BASEADDR_START(i);
+                       msize = PCI_BASEADDR_SIZE(pdev,i);
+                       break;
+               }
+       }
+       ioc->mem_size = msize;
+
+       if (i == DEVICE_COUNT_RESOURCE) {
+               printk(KERN_ERR MYNAM ": ERROR - MPT adapter has no memory regions defined!\n");
+               kfree(ioc);
+               return -EINVAL;
+       }
+
+       dprintk((KERN_INFO MYNAM ": MPT adapter @ %lx, msize=%dd bytes\n", mem_phys, msize));
+       dprintk((KERN_INFO MYNAM ": (port i/o @ %lx, psize=%dd bytes)\n", port, psize));
+       dprintk((KERN_INFO MYNAM ": Using %s register access method\n", PortIo ? "PortIo" : "MemMap"));
+
+       mem = NULL;
+       if (! PortIo) {
+               /*  Get logical ptr for PciMem0 space  */
+               /*mem = ioremap(mem_phys, msize);*/
+               mem = ioremap(mem_phys, 0x100);
+               if (mem == NULL) {
+                       printk(KERN_ERR MYNAM ": ERROR - Unable to map adapter memory!\n");
+                       kfree(ioc);
+                       return -EINVAL;
+               }
+               ioc->memmap = mem;
+       }
+       dprintk((KERN_INFO MYNAM ": mem = %p, mem_phys = %lx\n", mem, mem_phys));
+
+       if (PortIo) {
+               u8 *pmem = (u8*)port;
+               ioc->mem_phys = port;
+               ioc->chip = (SYSIF_REGS*)pmem;
+       } else {
+               ioc->mem_phys = mem_phys;
+               ioc->chip = (SYSIF_REGS*)mem;
+       }
+
+       ioc->chip_type = FCUNK;
+       if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC909) {
+               ioc->chip_type = FC909;
+               ioc->prod_name = "LSIFC909";
+       }
+       else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC929) {
+               ioc->chip_type = FC929;
+               ioc->prod_name = "LSIFC929";
+       }
+#if 0
+       else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC919) {
+               ioc->chip_type = C1030;
+               ioc->prod_name = "LSIFC919";
+       }
+       else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_53C1030) {
+               ioc->chip_type = C1030;
+               ioc->prod_name = "LSI53C1030";
+       }
+#endif
+
+       myname = "iocN";
+       len = strlen(myname);
+       memcpy(ioc->name, myname, len+1);
+       ioc->name[len-1] = '0' + ioc->id;
+
+       Q_INIT(&ioc->FreeQ, MPT_FRAME_HDR);
+       spin_lock_init(&ioc->FreeQlock);
+
+       /*  Disable all!  */
+       CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
+       CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
+       ioc->active = 0;
+
+       ioc->pci_irq = -1;
+       if (pdev->irq) {
+               r = request_irq(pdev->irq, mpt_interrupt, SA_SHIRQ, ioc->name, ioc);
+
+               if (r < 0) {
+                       printk(KERN_ERR MYNAM ": %s: ERROR - Unable to allocate interrupt %d!\n",
+                                       ioc->name, pdev->irq);
+                       iounmap(mem);
+                       kfree(ioc);
+                       return -EBUSY;
+               }
+
+               ioc->pci_irq = pdev->irq;
+
+               pci_set_master(pdev);                   /* ?? */
+
+               dprintk((KERN_INFO MYNAM ": %s installed at interrupt %d\n", ioc->name, pdev->irq));
+       }
+
+       /*  tack onto tail of our MPT adapter list  */
+       Q_ADD_TAIL(&MptAdapters, ioc, MPT_ADAPTER);
+
+       /* Set lookup ptr. */
+       mpt_adapters[ioc->id] = ioc;
+
+       /* NEW!  20010220 -sralston
+        * Check for "929 bound ports" to reduce redundant resets.
+        */
+       if (ioc->chip_type == FC929)
+               mpt_detect_929_bound_ports(ioc, pdev);
+
+       /*  Get current [raw] IOC state  */
+       ioc_state = GetIocState(ioc, 0);
+       dhsprintk((KERN_INFO MYNAM ": %s initial [raw] state=%08x\n", ioc->name, ioc_state));
+
+       /*
+        *  Check to see if IOC got left/stuck in doorbell handshake
+        *  grip of death.  If so, hard reset the IOC.
+        */
+       if (ioc_state & MPI_DOORBELL_ACTIVE) {
+               statefault = 1;
+               printk(KERN_WARNING MYNAM ": %s: Uh-oh, unexpected doorbell active!\n",
+                               ioc->name);
+       }
+
+       /*
+        *  Check to see if IOC is in FAULT state.
+        *  If so, hard reset the IOC.
+        */
+       if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
+               statefault = 2;
+               printk(KERN_WARNING MYNAM ": %s: Uh-oh, IOC is in FAULT state!!!\n",
+                               ioc->name);
+               printk(KERN_WARNING "           FAULT code = %04xh\n",
+                               ioc_state & MPI_DOORBELL_DATA_MASK);
+       }
+
+       if (HardReset || statefault) {
+               if ((r = KickStart(ioc)) != 0) {
+                       r = -ENODEV;
+                       goto ioc_up_fail;
+               }
+       }
+
+       /*
+        *  Loop here waiting for IOC to come READY.
+        */
+       i = 0;
+       cntdn = HZ * 10;
+       while ((ioc_state = GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
+               if (ioc_state == MPI_IOC_STATE_OPERATIONAL) {
+                       /*
+                        *  BIOS or previous driver load left IOC in OP state.
+                        *  Reset messaging FIFOs.
+                        */
+                       dprintk((KERN_WARNING MYNAM ": %s: Sending IOC msg unit reset!\n", ioc->name));
+                       if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET)) != 0) {
+                               printk(KERN_ERR MYNAM ": %s: ERROR - IOC msg unit reset failed!\n", ioc->name);
+                               r = -ENODEV;
+                               goto ioc_up_fail;
+                       }
+               } else if (ioc_state == MPI_IOC_STATE_RESET) {
+                       /*
+                        *  Something is wrong.  Try to get IOC back
+                        *  to a known state.
+                        */
+                       dprintk((KERN_WARNING MYNAM ": %s: Sending IO unit reset!\n", ioc->name));
+                       if ((r = SendIocReset(ioc, MPI_FUNCTION_IO_UNIT_RESET)) != 0) {
+                               printk(KERN_ERR MYNAM ": %s: ERROR - IO unit reset failed!\n", ioc->name);
+                               r = -ENODEV;
+                               goto ioc_up_fail;
+                       }
+               }
+
+               i++; cntdn--;
+               if (!cntdn) {
+                       printk(KERN_ERR MYNAM ": %s: ERROR - Wait IOC_READY state timeout(%d)!\n",
+                                       ioc->name, (i+5)/HZ);
+                       r = -ETIME;
+                       goto ioc_up_fail;
+               }
+
+               current->state = TASK_INTERRUPTIBLE;
+               schedule_timeout(1);
+       }
+
+       if (statefault) {
+               printk(KERN_WARNING MYNAM ": %s: Whew!  Recovered from %s\n",
+                               ioc->name, statefault==1 ? "stuck handshake" : "IOC FAULT");
+       }
+
+       /*  Enable! (reply interrupt)  */
+       CHIPREG_WRITE32(&ioc->chip->IntMask, ~(MPI_HIM_RIM));
+       ioc->active = 1;
+
+       /*  Get IOC facts! (first time, ioc->facts0 and ioc->pfacts0)  */
+       if ((r = GetIocFacts(ioc)) != 0)
+               goto ioc_up_fail;
+
+       /* Does IocFacts.EventState need any looking at / attention here? */
+
+       if ((r = SendIocInit(ioc)) != 0)
+               goto ioc_up_fail;
+
+       /*
+        *  Prime reply & request queues!
+        *  (mucho alloc's)
+        */
+       if ((r = PrimeIocFifos(ioc)) != 0)
+               goto ioc_up_fail;
+
+       /*  Get IOC facts again! (2nd time, ioc->factsN and ioc->pfactsN)  */
+       if ((r = GetIocFacts(ioc)) != 0)
+               goto ioc_up_fail;
+
+       /* Does IocFacts.EventState need any looking at / attention here? */
+
+       MptDisplayIocCapabilities(ioc);
+
+       if (ioc->pfacts0.ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
+               /*
+                *  Pre-fetch the ports LAN MAC address!
+                *  (LANPage1_t stuff)
+                */
+               (void) GetLanConfigPages(ioc);
+#ifdef MPT_DEBUG
+               {
+                       u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
+                       dprintk((KERN_INFO MYNAM ": %s: LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
+                                       ioc->name, a[5], a[4], a[3], a[2], a[1], a[0] ));
+               }
+#endif
+       }
+
+       /* NEW!  20010120 -sralston
+        *  Enable MPT base driver management of EventNotification
+        *  and EventAck handling.
+        */
+       (void) SendEventNotification(ioc, 1);   /* 1=Enable EventNotification */
+
+       return 0;
+
+ioc_up_fail:
+       //Q_DEL_ITEM(ioc);
+       //mpt_adapter_dispose(ioc);
+       mpt_adapter_disable(ioc);
+       return r;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     mpt_detect_929_bound_ports - Search for PCI bus/dev_function
+ *     which matches PCI bus/dev_function (+/-1) for newly discovered 929.
+ *     @ioc: Pointer to MPT adapter structure
+ *     @pdev: Pointer to (struct pci_dev) structure
+ *
+ *     If match on PCI dev_function +/-1 is found, bind the two MPT adapters
+ *     using alt_ioc pointer fields in their %MPT_ADAPTER structures.
+ */
+static void
+mpt_detect_929_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
+{
+       MPT_ADAPTER *ioc_srch = mpt_adapter_find_first();
+       unsigned int match_lo, match_hi;
+
+       match_lo = pdev->devfn-1;
+       match_hi = pdev->devfn+1;
+       dprintk((KERN_INFO MYNAM ": %s: PCI bus/devfn=%x/%x, searching for devfn match on %x or %x\n",
+                       ioc->name, pdev->bus->number, pdev->devfn, match_lo, match_hi));
+
+       while (ioc_srch != NULL) {
+               struct pci_dev *_pcidev = ioc_srch->pcidev;
+
+               if ( (_pcidev->device == MPI_MANUFACTPAGE_DEVICEID_FC929) &&
+                    (_pcidev->bus->number == pdev->bus->number) &&
+                    (_pcidev->devfn == match_lo || _pcidev->devfn == match_hi) ) {
+                       /* Paranoia checks */
+                       if (ioc->alt_ioc != NULL) {
+                               printk(KERN_WARNING MYNAM ": Oops, already bound (%s <==> %s)!\n",
+                                               ioc->name, ioc->alt_ioc->name);
+                               break;
+                       } else if (ioc_srch->alt_ioc != NULL) {
+                               printk(KERN_WARNING MYNAM ": Oops, already bound (%s <==> %s)!\n",
+                                               ioc_srch->name, ioc_srch->alt_ioc->name);
+                               break;
+                       }
+                       dprintk((KERN_INFO MYNAM ": FOUND! binding %s <==> %s\n",
+                                       ioc->name, ioc_srch->name));
+                       ioc_srch->alt_ioc = ioc;
+                       ioc->alt_ioc = ioc_srch;
+                       ioc->sod_reset = ioc->alt_ioc->sod_reset;
+                       ioc->last_kickstart = ioc->alt_ioc->last_kickstart;
+                       break;
+               }
+               ioc_srch = mpt_adapter_find_next(ioc_srch);
+       }
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     mpt_adapter_disable - Disable misbehaving MPT adapter.
+ *     @this: Pointer to MPT adapter structure
+ */
+static void
+mpt_adapter_disable(MPT_ADAPTER *this)
+{
+       if (this != NULL) {
+               int sz;
+
+               /* Disable adapter interrupts! */
+               CHIPREG_WRITE32(&this->chip->IntMask, 0xFFFFFFFF);
+               /* Clear any lingering interrupt */
+               CHIPREG_WRITE32(&this->chip->IntStatus, 0);
+               this->active = 0;
+
+               if (this->reply_alloc != NULL) {
+                       sz = (this->reply_sz * this->reply_depth) + 128;
+                       pci_free_consistent(this->pcidev, sz,
+                                       this->reply_alloc, this->reply_alloc_dma);
+                       this->reply_frames = NULL;
+                       this->reply_alloc = NULL;
+                       this->alloc_total -= sz;
+               }
+
+               if (this->req_alloc != NULL) {
+                       sz = (this->req_sz * this->req_depth) + 128;
+                       /*
+                        *  Rounding UP to nearest 4-kB boundary here...
+                        */
+                       sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
+                       pci_free_consistent(this->pcidev, sz,
+                                       this->req_alloc, this->req_alloc_dma);
+                       this->req_frames = NULL;
+                       this->req_alloc = NULL;
+                       this->alloc_total -= sz;
+               }
+
+               if (this->sense_buf_pool != NULL) {
+                       sz = (this->req_depth * 256);
+                       pci_free_consistent(this->pcidev, sz,
+                                       this->sense_buf_pool, this->sense_buf_pool_dma);
+                       this->sense_buf_pool = NULL;
+                       this->alloc_total -= sz;
+               }
+       }
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     mpt_adapter_dispose - Free all resources associated with a MPT
+ *     adapter.
+ *     @this: Pointer to MPT adapter structure
+ *
+ *     This routine unregisters h/w resources and frees all alloc'd memory
+ *     associated with a MPT adapter structure.
+ */
+static void
+mpt_adapter_dispose(MPT_ADAPTER *this)
+{
+       if (this != NULL) {
+               int sz_first, sz_last;
+
+               sz_first = this->alloc_total;
+
+               mpt_adapter_disable(this);
+
+               if (this->pci_irq != -1) {
+                       free_irq(this->pci_irq, this);
+                       this->pci_irq = -1;
+               }
+
+               if (this->memmap != NULL)
+                       iounmap((u8 *) this->memmap);
+
+#if defined(CONFIG_MTRR) && 0
+               if (this->mtrr_reg > 0) {
+                       mtrr_del(this->mtrr_reg, 0, 0);
+                       dprintk((KERN_INFO MYNAM ": %s: MTRR region de-registered\n", this->name));
+               }
+#endif
+
+               /*  Zap the adapter lookup ptr!  */
+               mpt_adapters[this->id] = NULL;
+
+               sz_last = this->alloc_total;
+               dprintk((KERN_INFO MYNAM ": %s: free'd %d of %d bytes\n",
+                               this->name, sz_first-sz_last+(int)sizeof(*this), sz_first));
+               kfree(this);
+       }
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     MptDisplayIocCapabilities - Disply IOC's capacilities.
+ *     @ioc: Pointer to MPT adapter structure
+ */
+static void
+MptDisplayIocCapabilities(MPT_ADAPTER *ioc)
+{
+       int i = 0;
+
+       printk(KERN_INFO "%s: ", ioc->name);
+       if (ioc->prod_name && strlen(ioc->prod_name) > 3)
+               printk("%s: ", ioc->prod_name+3);
+       printk("Capabilities={");
+
+       if (ioc->pfacts0.ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR) {
+               printk("Initiator");
+               i++;
+       }
+
+       if (ioc->pfacts0.ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
+               printk("%sTarget", i ? "," : "");
+               i++;
+       }
+
+       if (ioc->pfacts0.ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
+               printk("%sLAN", i ? "," : "");
+               i++;
+       }
+
+#if 0
+       /*
+        *  This would probably evoke more questions than it's worth
+        */
+       if (ioc->pfacts0.ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
+               printk("%sLogBusAddr", i ? "," : "");
+               i++;
+       }
+#endif
+
+       printk("}\n");
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     GetIocState - Get the current state of a MPT adapter.
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @cooked: Request raw or cooked IOC state
+ *
+ *     Returns all IOC Doorbell register bits if cooked==0, else just the
+ *     Doorbell bits in MPI_IOC_STATE_MASK.
+ */
+static u32
+GetIocState(MPT_ADAPTER *ioc, int cooked)
+{
+       u32 s, sc;
+
+       /*  Get!  */
+       s = CHIPREG_READ32(&ioc->chip->Doorbell);
+       dprintk((KERN_INFO MYNAM ": %s: raw state = %08x\n", ioc->name, s));
+       sc = s & MPI_IOC_STATE_MASK;
+
+       /*  Save!  */
+       ioc->last_state = sc;
+
+       return cooked ? sc : s;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     GetIocFacts - Send IOCFacts request to MPT adapter.
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *
+ *     Returns 0 for success, non-zero for failure.
+ */
+static int
+GetIocFacts(MPT_ADAPTER *ioc)
+{
+       IOCFacts_t               get_facts;
+       IOCFactsReply_t         *facts;
+       int                      r;
+       int                      req_sz;
+       int                      reply_sz;
+       u32                      status;
+
+       /*  IOC *must* NOT be in RESET state!  */
+       if (ioc->last_state == MPI_IOC_STATE_RESET) {
+               printk(KERN_ERR MYNAM ": ERROR - Can't get IOCFacts, %s NOT READY! (%08x)\n",
+                               ioc->name,
+                               ioc->last_state );
+               return -44;
+       }
+
+       facts = &ioc->facts0;
+       /*  Nth (2,3,...) time thru? (been here, done that?)  */
+       if (ioc->facts0.Function == MPI_FUNCTION_IOC_FACTS) {
+               facts = &ioc->factsN;
+       }
+
+       /*  Destination (reply area)...  */
+       reply_sz = sizeof(*facts);
+       memset(facts, 0, reply_sz);
+
+       /*  Request area (get_facts on the stack right now!)  */
+       req_sz = sizeof(get_facts);
+       memset(&get_facts, 0, req_sz);
+
+       get_facts.Function = MPI_FUNCTION_IOC_FACTS;
+       /*  Assert: All other get_facts fields are zero!  */
+
+       dprintk((KERN_INFO MYNAM ": %s: Sending IocFacts%s request\n",
+                       ioc->name, facts == &ioc->facts0 ? "0" : "N" ));
+
+       /* No non-zero fields in the get_facts request are greater than
+        * 1 byte in size, so we can just fire it off as is.
+        */
+       r = HandShakeReqAndReply(ioc,
+                       req_sz, (u32*)&get_facts,
+                       reply_sz, (u16*)facts);
+       if (r != 0)
+               return r;
+
+       /*
+        *  Now byte swap the necessary fields before any further
+        *  inspection of reply contents.
+        *
+        *  But need to do some sanity checks on MsgLength (byte) field
+        *  to make sure we don't zero IOC's req_sz!
+        */
+       /* Did we get a valid reply? */
+       if (facts->MsgLength > offsetof(IOCFactsReply_t, RequestFrameSize)/sizeof(u32)) {
+               facts->MsgVersion = le16_to_cpu(facts->MsgVersion);
+               facts->MsgContext = le32_to_cpu(facts->MsgContext);
+               facts->IOCStatus = le16_to_cpu(facts->IOCStatus);
+               facts->IOCLogInfo = le32_to_cpu(facts->IOCLogInfo);
+               status = facts->IOCStatus & MPI_IOCSTATUS_MASK;
+               /* CHECKME! IOCStatus, IOCLogInfo */
+
+               facts->ReplyQueueDepth = le16_to_cpu(facts->ReplyQueueDepth);
+               facts->RequestFrameSize = le16_to_cpu(facts->RequestFrameSize);
+               facts->FWVersion = le16_to_cpu(facts->FWVersion);
+               facts->ProductID = le16_to_cpu(facts->ProductID);
+               facts->CurrentHostMfaHighAddr =
+                               le32_to_cpu(facts->CurrentHostMfaHighAddr);
+               facts->GlobalCredits = le16_to_cpu(facts->GlobalCredits);
+               facts->CurrentSenseBufferHighAddr =
+                               le32_to_cpu(facts->CurrentSenseBufferHighAddr);
+               facts->CurReplyFrameSize =
+                               le16_to_cpu(facts->CurReplyFrameSize);
+
+               /*
+                *  Handle NEW (!) IOCFactsReply fields in MPI-1.01.xx
+                *  Older MPI-1.00.xx struct had 13 dwords, and enlarged
+                *  to 14 in MPI-1.01.0x.
+                */
+               if (facts->MsgLength >= sizeof(IOCFactsReply_t)/sizeof(u32) && facts->MsgVersion > 0x0100) {
+                       facts->FWImageSize = le32_to_cpu(facts->FWImageSize);
+                       facts->DataImageSize = le32_to_cpu(facts->DataImageSize);
+               }
+
+               if (facts->RequestFrameSize) {
+                       /*
+                        *  Set values for this IOC's REQUEST queue size & depth...
+                        */
+                       ioc->req_sz = MIN(MPT_REQ_SIZE, facts->RequestFrameSize * 4);
+
+                       /*
+                        *  Set values for this IOC's REPLY queue size & depth...
+                        *
+                        * BUG? FIX?  20000516 -nromer & sralston 
+                        *  GRRR...  The following did not translate well from MPI v0.09:
+                        *      ioc->reply_sz = MIN(MPT_REPLY_SIZE, facts->ReplySize * 4);
+                        *  to 0.10:
+                        *      ioc->reply_sz = MIN(MPT_REPLY_SIZE, facts->BlockSize * 4);
+                        *  Was trying to minimally optimize to smallest possible reply size
+                        *  (and greatly reduce kmalloc size).  But LAN may need larger reply?
+                        *
+                        *  So for now, just set reply size to request size.  FIXME?
+                        */
+                       ioc->reply_sz = ioc->req_sz;
+               } else {
+                       /*  Something is wrong!  */
+                       printk(KERN_ERR MYNAM ": %s: ERROR - IOC reported invalid 0 request size!\n",
+                                       ioc->name);
+                       ioc->req_sz = MPT_REQ_SIZE;
+                       ioc->reply_sz = MPT_REPLY_SIZE;
+                       return -55;
+               }
+               ioc->req_depth = MIN(MPT_REQ_DEPTH, facts->GlobalCredits);
+               ioc->reply_depth = MIN(MPT_REPLY_DEPTH, facts->ReplyQueueDepth);
+
+               dprintk((KERN_INFO MYNAM ": %s: reply_sz=%3d, reply_depth=%4d\n",
+                               ioc->name, ioc->reply_sz, ioc->reply_depth));
+               dprintk((KERN_INFO MYNAM ": %s: req_sz  =%3d, req_depth  =%4d\n",
+                               ioc->name, ioc->req_sz, ioc->req_depth));
+
+               /*  Get port facts!  */
+               if ( (r = GetPortFacts(ioc)) != 0 )
+                       return r;
+       } else {
+               printk(KERN_ERR MYNAM ": %s: ERROR - Invalid IOC facts reply!\n",
+                               ioc->name);
+               return -66;
+       }
+
+       return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     GetPortFacts - Send PortFacts request to MPT adapter.
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *
+ *     Returns 0 for success, non-zero for failure.
+ */
+static int
+GetPortFacts(MPT_ADAPTER *ioc)
+{
+       PortFacts_t              get_pfacts;
+       PortFactsReply_t        *pfacts;
+       int                      i;
+       int                      req_sz;
+       int                      reply_sz;
+
+       /*  IOC *must* NOT be in RESET state!  */
+       if (ioc->last_state == MPI_IOC_STATE_RESET) {
+               printk(KERN_ERR MYNAM ": ERROR - Can't get PortFacts, %s NOT READY! (%08x)\n",
+                               ioc->name,
+                               ioc->last_state );
+               return -4;
+       }
+
+       pfacts = &ioc->pfacts0;
+       /*  Nth (2,3,...) time thru? (been here, done that?)  */
+       if (ioc->pfacts0.Function == MPI_FUNCTION_PORT_FACTS) {
+               pfacts = &ioc->pfactsN;
+       }
+
+       /*  Destination (reply area)...  */
+       reply_sz = sizeof(*pfacts);
+       memset(pfacts, 0, reply_sz);
+
+       /*  Request area (get_pfacts on the stack right now!)  */
+       req_sz = sizeof(get_pfacts);
+       memset(&get_pfacts, 0, req_sz);
+
+       get_pfacts.Function = MPI_FUNCTION_PORT_FACTS;
+       /*  Assert: All other get_pfacts fields are zero!  */
+
+       dprintk((KERN_INFO MYNAM ": %s: Sending PortFacts%s request\n",
+                       ioc->name, pfacts == &ioc->pfacts0 ? "0" : "N" ));
+
+       /* No non-zero fields in the get_pfacts request are greater than
+        * 1 byte in size, so we can just fire it off as is.
+        */
+       i = HandShakeReqAndReply(ioc, req_sz, (u32*)&get_pfacts,
+                               reply_sz, (u16*)pfacts);
+       if (i != 0)
+               return i;
+
+       /* Did we get a valid reply? */
+
+       /* Now byte swap the necessary fields in the response. */
+       pfacts->MsgContext = le32_to_cpu(pfacts->MsgContext);
+       pfacts->IOCStatus = le16_to_cpu(pfacts->IOCStatus);
+       pfacts->IOCLogInfo = le32_to_cpu(pfacts->IOCLogInfo);
+       pfacts->MaxDevices = le16_to_cpu(pfacts->MaxDevices);
+       pfacts->PortSCSIID = le16_to_cpu(pfacts->PortSCSIID);
+       pfacts->ProtocolFlags = le16_to_cpu(pfacts->ProtocolFlags);
+       pfacts->MaxPostedCmdBuffers = le16_to_cpu(pfacts->MaxPostedCmdBuffers);
+       pfacts->MaxPersistentIDs = le16_to_cpu(pfacts->MaxPersistentIDs);
+       pfacts->MaxLanBuckets = le16_to_cpu(pfacts->MaxLanBuckets);
+
+       return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     SendIocInit - Send IOCInit request to MPT adapter.
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *
+ *     Send IOCInit followed by PortEnable to bring IOC to OPERATIONAL state.
+ *
+ *     Returns 0 for success, non-zero for failure.
+ */
+static int
+SendIocInit(MPT_ADAPTER *ioc)
+{
+       IOCInit_t                ioc_init;
+       MPIDefaultReply_t        init_reply;
+       u32                      state;
+       int                      r;
+       int                      count;
+       int                      cntdn;
+
+       memset(&ioc_init, 0, sizeof(ioc_init));
+       memset(&init_reply, 0, sizeof(init_reply));
+
+       ioc_init.WhoInit = MPI_WHOINIT_HOST_DRIVER;
+/*     ioc_init.ChainOffset = 0;                       */
+       ioc_init.Function = MPI_FUNCTION_IOC_INIT;
+/*     ioc_init.Flags = 0;                             */
+
+       /*ioc_init.MaxDevices = 16;*/
+       ioc_init.MaxDevices = 255;
+/*     ioc_init.MaxBuses = 16;                         */
+       ioc_init.MaxBuses = 1;
+
+/*     ioc_init.MsgFlags = 0;                          */
+/*     ioc_init.MsgContext = cpu_to_le32(0x00000000);  */
+       ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz);   /* in BYTES */
+       ioc_init.HostMfaHighAddr = cpu_to_le32(0);      /* Say we 32-bit! for now */
+
+       dprintk((KERN_INFO MYNAM ": %s: Sending IOCInit (req @ %p)\n", ioc->name, &ioc_init));
+
+       r = HandShakeReqAndReply(ioc, sizeof(IOCInit_t), (u32*)&ioc_init,
+                       sizeof(MPIDefaultReply_t), (u16*)&init_reply);
+       if (r != 0)
+               return r;
+
+       /* No need to byte swap the multibyte fields in the reply
+        * since we don't even look at it's contents.
+        */
+
+       if ((r = SendPortEnable(ioc, 0)) != 0)
+               return r;
+
+       /* YIKES!  SUPER IMPORTANT!!!
+        *  Poll IocState until _OPERATIONAL while IOC is doing
+        *  LoopInit and TargetDiscovery!
+        */
+       count = 0;
+       cntdn = HZ * 60;                                        /* chg'd from 30 to 60 seconds */
+       state = GetIocState(ioc, 1);
+       while (state != MPI_IOC_STATE_OPERATIONAL && --cntdn) {
+               current->state = TASK_INTERRUPTIBLE;
+               schedule_timeout(1);
+
+               if (!cntdn) {
+                       printk(KERN_ERR MYNAM ": %s: ERROR - Wait IOC_OP state timeout(%d)!\n",
+                                       ioc->name, (count+5)/HZ);
+                       return -9;
+               }
+
+               state = GetIocState(ioc, 1);
+               count++;
+       }
+       dhsprintk((KERN_INFO MYNAM ": %s: INFO - Wait IOC_OPERATIONAL state (cnt=%d)\n",
+                       ioc->name, count));
+
+       return r;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     SendPortEnable - Send PortEnable request to MPT adapter port.
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @portnum: Port number to enable
+ *
+ *     Send PortEnable to bring IOC to OPERATIONAL state.
+ *
+ *     Returns 0 for success, non-zero for failure.
+ */
+static int
+SendPortEnable(MPT_ADAPTER *ioc, int portnum)
+{
+       PortEnable_t             port_enable;
+       MPIDefaultReply_t        reply_buf;
+       int      i;
+       int      req_sz;
+       int      reply_sz;
+
+       /*  Destination...  */
+       reply_sz = sizeof(MPIDefaultReply_t);
+       memset(&reply_buf, 0, reply_sz);
+
+       req_sz = sizeof(PortEnable_t);
+       memset(&port_enable, 0, req_sz);
+
+       port_enable.Function = MPI_FUNCTION_PORT_ENABLE;
+       port_enable.PortNumber = portnum;
+/*     port_enable.ChainOffset = 0;            */
+/*     port_enable.MsgFlags = 0;               */
+/*     port_enable.MsgContext = 0;             */
+
+       dprintk((KERN_INFO MYNAM ": %s: Sending Port(%d)Enable (req @ %p)\n",
+                       ioc->name, portnum, &port_enable));
+
+       i = HandShakeReqAndReply(ioc, req_sz, (u32*)&port_enable,
+                       reply_sz, (u16*)&reply_buf);
+       if (i != 0)
+               return i;
+
+       /* We do not even look at the reply, so we need not
+        * swap the multi-byte fields.
+        */
+
+       return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     KickStart - Perform hard reset of MPT adapter.
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *
+ *     This routine places MPT adapter in diagnostic mode via the
+ *     WriteSequence register, and then performs a hard reset of adapter
+ *     via the Diagnostic register.
+ *
+ *     Returns 0 for success, non-zero for failure.
+ */
+static int
+KickStart(MPT_ADAPTER *ioc)
+{
+       int r;
+       u32 ioc_state;
+       int cnt = 0;
+
+       dprintk((KERN_WARNING MYNAM ": KickStarting %s!\n", ioc->name));
+
+       if (ioc->chip_type == FC909) {
+               r = mpt_fc9x9_reset(ioc);
+       } else if (ioc->chip_type == FC929) {
+               unsigned long delta;
+
+               delta = jiffies - ioc->last_kickstart;
+               dprintk((KERN_INFO MYNAM ": %s: 929 KickStart, last=%ld, delta = %ld\n",
+                               ioc->name, ioc->last_kickstart, delta));
+               if ((ioc->sod_reset == 0) || (delta >= 10*HZ))
+                       r = mpt_fc9x9_reset(ioc);
+               else {
+                       dprintk((KERN_INFO MYNAM ": %s: Skipping KickStart (delta=%ld)!\n",
+                                       ioc->name, delta));
+                       return 0;
+               }
+       /* TODO! Add FC919!
+       } else if (ioc->chip_type == FC919) {
+        */
+       /* TODO! Add C1030!
+       } else if (ioc->chip_type == C1030) {
+        */
+       } else {
+               printk(KERN_ERR MYNAM ": %s: ERROR - Bad chip_type (0x%x)\n",
+                               ioc->name, ioc->chip_type);
+               return -5;
+       }
+
+       if (r != 0)
+               return -r;
+
+       dprintk((KERN_INFO MYNAM ": %s: Diagnostic reset successful\n",
+                       ioc->name));
+
+       for (cnt=0; cnt<HZ*20; cnt++) {
+               if ((ioc_state = GetIocState(ioc, 1)) == MPI_IOC_STATE_READY) {
+                       dprintk((KERN_INFO MYNAM ": %s: KickStart successful! (cnt=%d)\n",
+                                       ioc->name, cnt));
+                       return 0;
+               }
+               /* udelay(10000) ? */
+               current->state = TASK_INTERRUPTIBLE;
+               schedule_timeout(1);
+       }
+
+       printk(KERN_ERR MYNAM ": %s: ERROR - Failed to come READY after reset!\n",
+                       ioc->name);
+       return -1;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     mpt_fc9x9_reset - Perform hard reset of FC9x9 adapter.
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *
+ *     This routine places FC9x9 adapter in diagnostic mode via the
+ *     WriteSequence register, and then performs a hard reset of adapter
+ *     via the Diagnostic register.
+ *
+ *     Returns 0 for success, non-zero for failure.
+ */
+static int
+mpt_fc9x9_reset(MPT_ADAPTER *ioc)
+{
+       u32 diagval;
+
+       /* Use "Diagnostic reset" method! (only thing available!) */
+
+       /*
+        * Extra read to handle 909 B.0 chip problem with reset
+        * logic not finishing the RAM access before hard reset hits.
+        * (? comment taken from NT SYMMPI source)
+        */
+       (void) CHIPREG_READ32(&ioc->chip->Fubar);
+
+       /*
+        * Write magic sequence to WriteSequence register.
+        * But, send 0x0F first to insure a reset to the beginning of the sequence.
+        */
+       CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_KEY_VALUE_MASK);
+
+       /* Now write magic sequence */
+       CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
+       CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
+       CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
+       CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
+       CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
+       dprintk((KERN_INFO MYNAM ": %s: Wrote magic DiagWriteEn sequence\n",
+                       ioc->name));
+
+       /* Now hit the reset bit in the Diagnostic register */
+       CHIPREG_WRITE32(&ioc->chip->Diagnostic, MPI_DIAG_RESET_ADAPTER);
+
+       udelay(100);
+
+       if ((diagval = CHIPREG_READ32(&ioc->chip->Diagnostic)) &
+                               (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_DISABLE_ARM)) {
+               printk(KERN_ERR MYNAM ": %s: ERROR - Diagnostic reset FAILED!\n",
+                               ioc->name);
+               return -9;
+       }
+
+       /* TODO!
+        * Cleanup all event stuff for this IOC;
+        * re-issue EventNotification request if needed.
+        */
+       if (ioc->factsN.Function)
+               ioc->factsN.EventState = 0;
+
+       /* NEW!  20010220 -sralston
+        * Try to avoid redundant resets of the 929.
+        */
+       ioc->sod_reset++;
+       ioc->last_kickstart = jiffies;
+       if (ioc->alt_ioc) {
+               ioc->alt_ioc->sod_reset = ioc->sod_reset;
+               ioc->alt_ioc->last_kickstart = ioc->last_kickstart;
+       }
+
+       return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     SendIocReset - Send IOCReset request to MPT adapter.
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @reset_type: reset type, expected values are
+ *     %MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET or %MPI_FUNCTION_IO_UNIT_RESET
+ *
+ *     Send IOCReset request to the MPT adapter.
+ *
+ *     Returns 0 for success, non-zero for failure.
+ */
+static int
+SendIocReset(MPT_ADAPTER *ioc, u8 reset_type)
+{
+       int r;
+
+       printk(KERN_WARNING MYNAM ": %s: Sending IOC reset(0x%02x)!\n",
+                       ioc->name, reset_type);
+       CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT);
+       if ((r = WaitForDoorbellAck(ioc)) < 0)
+               return r;
+
+       /* TODO!
+        *  Cleanup all event stuff for this IOC; re-issue EventNotification
+        *  request if needed.
+        */
+       if (ioc->factsN.Function)
+               ioc->factsN.EventState = 0;
+
+       return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     PrimeIocFifos - Initialize IOC request and reply FIFOs.
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *
+ *     This routine allocates memory for the MPT reply and request frame
+ *     pools, and primes the IOC reply FIFO with reply frames.
+ *
+ *     Returns 0 for success, non-zero for failure.
+ */
+static int
+PrimeIocFifos(MPT_ADAPTER *ioc)
+{
+       MPT_FRAME_HDR *mf;
+       unsigned long b;
+       dma_addr_t aligned_mem_dma;
+       u8 *mem, *aligned_mem;
+       int i, sz;
+
+       /*  Prime reply FIFO...  */
+
+       if (ioc->reply_frames == NULL) {
+               sz = (ioc->reply_sz * ioc->reply_depth) + 128;
+               mem = pci_alloc_consistent(ioc->pcidev, sz, &ioc->reply_alloc_dma);
+               if (mem == NULL)
+                       goto out_fail;
+
+               memset(mem, 0, sz);
+               ioc->alloc_total += sz;
+               ioc->reply_alloc = mem;
+               dprintk((KERN_INFO MYNAM ": %s.reply_alloc  @ %p[%08x], sz=%d bytes\n",
+                        ioc->name, mem, ioc->reply_alloc_dma, sz));
+
+               b = (unsigned long) mem;
+               b = (b + (0x80UL - 1UL)) & ~(0x80UL - 1UL); /* round up to 128-byte boundary */
+               aligned_mem = (u8 *) b;
+               ioc->reply_frames = (MPT_FRAME_HDR *) aligned_mem;
+               ioc->reply_frames_dma =
+                       (ioc->reply_alloc_dma + (aligned_mem - mem));
+               aligned_mem_dma = ioc->reply_frames_dma;
+               dprintk((KERN_INFO MYNAM ": %s.reply_frames @ %p[%08x]\n",
+                        ioc->name, aligned_mem, aligned_mem_dma));
+
+               for (i = 0; i < ioc->reply_depth; i++) {
+                       /*  Write each address to the IOC!  */
+                       CHIPREG_WRITE32(&ioc->chip->ReplyFifo, aligned_mem_dma);
+                       aligned_mem_dma += ioc->reply_sz;
+               }
+       }
+
+
+       /*  Request FIFO - WE manage this!  */
+
+       if (ioc->req_frames == NULL) {
+               sz = (ioc->req_sz * ioc->req_depth) + 128;
+               /*
+                *  Rounding UP to nearest 4-kB boundary here...
+                */
+               sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
+
+               mem = pci_alloc_consistent(ioc->pcidev, sz, &ioc->req_alloc_dma);
+               if (mem == NULL)
+                       goto out_fail;
+
+               memset(mem, 0, sz);
+               ioc->alloc_total += sz;
+               ioc->req_alloc = mem;
+               dprintk((KERN_INFO MYNAM ": %s.req_alloc    @ %p[%08x], sz=%d bytes\n",
+                        ioc->name, mem, ioc->req_alloc_dma, sz));
+
+               b = (unsigned long) mem;
+               b = (b + (0x80UL - 1UL)) & ~(0x80UL - 1UL); /* round up to 128-byte boundary */
+               aligned_mem = (u8 *) b;
+               ioc->req_frames = (MPT_FRAME_HDR *) aligned_mem;
+               ioc->req_frames_dma =
+                       (ioc->req_alloc_dma + (aligned_mem - mem));
+               aligned_mem_dma = ioc->req_frames_dma;
+
+               dprintk((KERN_INFO MYNAM ": %s.req_frames   @ %p[%08x]\n",
+                        ioc->name, aligned_mem, aligned_mem_dma));
+
+               for (i = 0; i < ioc->req_depth; i++) {
+                       mf = (MPT_FRAME_HDR *) aligned_mem;
+
+                       /*  Queue REQUESTs *internally*!  */
+                       Q_ADD_TAIL(&ioc->FreeQ.head, &mf->u.frame.linkage, MPT_FRAME_HDR);
+                       aligned_mem += ioc->req_sz;
+               }
+
+#if defined(CONFIG_MTRR) && 0
+               /*
+                *  Enable Write Combining MTRR for IOC's memory region.
+                *  (at least as much as we can; "size and base must be
+                *  multiples of 4 kiB"
+                */
+               ioc->mtrr_reg = mtrr_add(ioc->req_alloc_dma,
+                                        sz,
+                                        MTRR_TYPE_WRCOMB, 1);
+               dprintk((KERN_INFO MYNAM ": %s: MTRR region registered (base:size=%08x:%x)\n",
+                               ioc->name, ioc->req_alloc_dma,
+                               sz ));
+#endif
+
+       }
+
+       if (ioc->sense_buf_pool == NULL) {
+               sz = (ioc->req_depth * 256);
+               ioc->sense_buf_pool =
+                               pci_alloc_consistent(ioc->pcidev, sz, &ioc->sense_buf_pool_dma);
+               if (ioc->sense_buf_pool == NULL)
+                       goto out_fail;
+
+               ioc->alloc_total += sz;
+       }
+
+       return 0;
+
+out_fail:
+       if (ioc->reply_alloc != NULL) {
+               sz = (ioc->reply_sz * ioc->reply_depth) + 128;
+               pci_free_consistent(ioc->pcidev,
+                               sz,
+                               ioc->reply_alloc, ioc->reply_alloc_dma);
+               ioc->reply_frames = NULL;
+               ioc->reply_alloc = NULL;
+               ioc->alloc_total -= sz;
+       }
+       if (ioc->req_alloc != NULL) {
+               sz = (ioc->req_sz * ioc->req_depth) + 128;
+               /*
+                *  Rounding UP to nearest 4-kB boundary here...
+                */
+               sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
+               pci_free_consistent(ioc->pcidev,
+                               sz,
+                               ioc->req_alloc, ioc->req_alloc_dma);
+#if defined(CONFIG_MTRR) && 0
+               if (ioc->mtrr_reg > 0) {
+                       mtrr_del(ioc->mtrr_reg, 0, 0);
+                       dprintk((KERN_INFO MYNAM ": %s: MTRR region de-registered\n",
+                                       ioc->name));
+               }
+#endif
+               ioc->req_frames = NULL;
+               ioc->req_alloc = NULL;
+               ioc->alloc_total -= sz;
+       }
+       if (ioc->sense_buf_pool != NULL) {
+               sz = (ioc->req_depth * 256);
+               pci_free_consistent(ioc->pcidev,
+                               sz,
+                               ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
+               ioc->sense_buf_pool = NULL;
+       }
+       return -1;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     HandShakeReqAndReply - Send MPT request to and receive reply from
+ *     IOC via doorbell handshake method.
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @reqBytes: Size of the request in bytes
+ *     @req: Pointer to MPT request frame
+ *     @replyBytes: Expected size of the reply in bytes
+ *     @u16reply: Pointer to area where reply should be written
+ *
+ *     NOTES: It is the callers responsibility to byte-swap fields in the
+ *     request which are greater than 1 byte in size.  It is also the
+ *     callers responsibility to byte-swap response fields which are
+ *     greater than 1 byte in size.
+ *
+ *     Returns 0 for success, non-zero for failure.
+ */
+static int
+HandShakeReqAndReply(MPT_ADAPTER *ioc, int reqBytes, u32 *req, int replyBytes, u16 *u16reply)
+{
+       MPIDefaultReply_t *mptReply;
+       int failcnt = 0;
+       int t;
+
+       /*
+        * Get ready to cache a handshake reply
+        */
+       ioc->hs_reply_idx = 0;
+       mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
+       mptReply->MsgLength = 0;
+
+       /*
+        * Make sure there are no doorbells (WRITE 0 to IntStatus reg),
+        * then tell IOC that we want to handshake a request of N words.
+        * (WRITE u32val to Doorbell reg).
+        */
+       CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
+       CHIPREG_WRITE32(&ioc->chip->Doorbell,
+                       ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
+                        ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
+
+       /*
+        * Wait for IOC's doorbell handshake int
+        */
+       if ((t = WaitForDoorbellInt(ioc)) < 0)
+               failcnt++;
+
+       dhsprintk((KERN_INFO MYNAM ": %s: HandShake request start, WaitCnt=%d%s\n",
+                       ioc->name, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
+
+       /*
+        * Clear doorbell int (WRITE 0 to IntStatus reg),
+        * then wait for IOC to ACKnowledge that it's ready for
+        * our handshake request.
+        */
+       CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
+       if (!failcnt && (t = WaitForDoorbellAck(ioc)) < 0)
+               failcnt++;
+
+       if (!failcnt) {
+               int      i;
+               u8      *req_as_bytes = (u8 *) req;
+
+               /*
+                * Stuff request words via doorbell handshake,
+                * with ACK from IOC for each.
+                */
+               for (i = 0; !failcnt && i < reqBytes/4; i++) {
+                       u32 word = ((req_as_bytes[(i*4) + 0] <<  0) |
+                                   (req_as_bytes[(i*4) + 1] <<  8) |
+                                   (req_as_bytes[(i*4) + 2] << 16) |
+                                   (req_as_bytes[(i*4) + 3] << 24));
+
+                       CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
+                       if ((t = WaitForDoorbellAck(ioc)) < 0)
+                               failcnt++;
+               }
+
+               dmfprintk((KERN_INFO MYNAM ": Handshake request frame (@%p) header\n", req));
+               DBG_DUMP_REQUEST_FRAME_HDR(req)
+
+               dhsprintk((KERN_INFO MYNAM ": %s: HandShake request post done, WaitCnt=%d%s\n",
+                               ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : ""));
+
+               /*
+                * Wait for completion of doorbell handshake reply from the IOC
+                */
+               if (!failcnt && (t = WaitForDoorbellReply(ioc)) < 0)
+                       failcnt++;
+
+               /*
+                * Copy out the cached reply...
+                */
+               for(i=0; i < MIN(replyBytes/2,mptReply->MsgLength*2); i++)
+                       u16reply[i] = ioc->hs_reply[i];
+       } else {
+               return -99;
+       }
+
+       return -failcnt;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     WaitForDoorbellAck - Wait for IOC to clear the IOP_DOORBELL_STATUS bit
+ *     in it's IntStatus register.
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *
+ *     This routine waits (up to ~30 seconds max) for IOC doorbell
+ *     handshake ACKnowledge.
+ *
+ *     Returns a negative value on failure, else wait loop count.
+ */
+static int
+WaitForDoorbellAck(MPT_ADAPTER *ioc)
+{
+       int cntdn = HZ * 30;                    /* ~30 seconds */
+       int count = 0;
+       u32 intstat;
+
+       while (--cntdn) {
+               intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
+               if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
+                       break;
+               current->state = TASK_INTERRUPTIBLE;
+               schedule_timeout(1);
+               count++;
+       }
+
+       if (cntdn) {
+               dhsprintk((KERN_INFO MYNAM ": %s: WaitForDoorbell ACK (cnt=%d)\n",
+                               ioc->name, count));
+               return count;
+       }
+
+       printk(KERN_ERR MYNAM ": %s: ERROR - Doorbell ACK timeout(%d)!\n",
+                       ioc->name, (count+5)/HZ);
+       return -1;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     WaitForDoorbellInt - Wait for IOC to set the HIS_DOORBELL_INTERRUPT bit
+ *     in it's IntStatus register.
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *
+ *     This routine waits (up to ~30 seconds max) for IOC doorbell interrupt.
+ *
+ *     Returns a negative value on failure, else wait loop count.
+ */
+static int
+WaitForDoorbellInt(MPT_ADAPTER *ioc)
+{
+       int cntdn = HZ * 30;                    /* ~30 seconds */
+       int count = 0;
+       u32 intstat;
+
+       while (--cntdn) {
+               intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
+               if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
+                       break;
+               current->state = TASK_INTERRUPTIBLE;
+               schedule_timeout(1);
+               count++;
+       }
+
+       if (cntdn) {
+               dhsprintk((KERN_INFO MYNAM ": %s: WaitForDoorbell INT (cnt=%d)\n",
+                               ioc->name, count));
+               return count;
+       }
+
+       printk(KERN_ERR MYNAM ": %s: ERROR - Doorbell INT timeout(%d)!\n",
+                       ioc->name, (count+5)/HZ);
+       return -1;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     WaitForDoorbellReply - Wait for and capture a IOC handshake reply.
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *
+ *     This routine polls the IOC for a handshake reply, 16 bits at a time.
+ *     Reply is cached to IOC private area large enough to hold a maximum
+ *     of 128 bytes of reply data.
+ *
+ *     Returns a negative value on failure, else size of reply in WORDS.
+ */
+static int
+WaitForDoorbellReply(MPT_ADAPTER *ioc)
+{
+       int u16cnt = 0;
+       int failcnt = 0;
+       int t;
+       u16 *hs_reply = ioc->hs_reply;
+       volatile MPIDefaultReply_t *mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
+       u16 hword;
+
+       hs_reply[0] = hs_reply[1] = hs_reply[7] = 0;
+
+       /*
+        * Get first two u16's so we can look at IOC's intended reply MsgLength
+        */
+       for (u16cnt=0; !failcnt && u16cnt < 2; u16cnt++) {
+               if ((t = WaitForDoorbellInt(ioc)) < 0)
+                       failcnt++;
+               hs_reply[u16cnt] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
+               CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
+       }
+
+       dhsprintk((KERN_INFO MYNAM ": %s: First handshake reply word=%08x%s\n",
+                       ioc->name, le32_to_cpu(*(u32 *)hs_reply),
+                       failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
+
+       /*
+        * If no error (and IOC said MsgLength is > 0), piece together
+        * reply 16 bits at a time.
+        */
+       for (u16cnt=2; !failcnt && u16cnt < (2 * mptReply->MsgLength); u16cnt++) {
+               if ((t = WaitForDoorbellInt(ioc)) < 0)
+                       failcnt++;
+               hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
+               /* don't overflow our IOC hs_reply[] buffer! */
+               if (u16cnt < sizeof(ioc->hs_reply) / sizeof(ioc->hs_reply[0]))
+                       hs_reply[u16cnt] = hword;
+               CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
+       }
+
+       if (!failcnt && (t = WaitForDoorbellInt(ioc)) < 0)
+               failcnt++;
+       CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
+
+       if (failcnt) {
+               printk(KERN_ERR MYNAM ": %s: ERROR - Handshake reply failure!\n",
+                               ioc->name);
+               return -failcnt;
+       }
+#if 0
+       else if (u16cnt != (2 * mptReply->MsgLength)) {
+               return -101;
+       }
+       else if ((mptReply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
+               return -102;
+       }
+#endif
+
+       dmfprintk((KERN_INFO MYNAM ": %s: Got Handshake reply:\n", ioc->name));
+       DBG_DUMP_REPLY_FRAME(mptReply)
+
+       dhsprintk((KERN_INFO MYNAM ": %s: WaitForDoorbell REPLY (sz=%d)\n",
+                       ioc->name, u16cnt/2));
+       return u16cnt/2;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     GetLanConfigPages - Fetch LANConfig pages.
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *
+ *     Returns 0 for success, non-zero for failure.
+ */
+static int
+GetLanConfigPages(MPT_ADAPTER *ioc)
+{
+       Config_t                 config_req;
+       ConfigReply_t            config_reply;
+       LANPage0_t              *page0;
+       dma_addr_t               page0_dma;
+       LANPage1_t              *page1;
+       dma_addr_t               page1_dma;
+       int                      i;
+       int                      req_sz;
+       int                      reply_sz;
+       int                      data_sz;
+
+/* LANPage0 */
+       /*  Immediate destination (reply area)...  */
+       reply_sz = sizeof(config_reply);
+       memset(&config_reply, 0, reply_sz);
+
+       /*  Ultimate destination...  */
+       page0 = &ioc->lan_cnfg_page0;
+       data_sz = sizeof(*page0);
+       memset(page0, 0, data_sz);
+
+       /*  Request area (config_req on the stack right now!)  */
+       req_sz = sizeof(config_req);
+       memset(&config_req, 0, req_sz);
+       config_req.Function = MPI_FUNCTION_CONFIG;
+       config_req.Action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+       /*      config_req.Header.PageVersion = 0;      */
+       /*      config_req.Header.PageLength = 0;       */
+       config_req.Header.PageNumber = 0;
+       config_req.Header.PageType = MPI_CONFIG_PAGETYPE_LAN;
+       /*      config_req.PageAddress = 0;             */
+       config_req.PageBufferSGE.u.Simple.FlagsLength = cpu_to_le32(
+                       ((MPI_SGE_FLAGS_LAST_ELEMENT |
+                         MPI_SGE_FLAGS_END_OF_BUFFER |
+                         MPI_SGE_FLAGS_END_OF_LIST |
+                         MPI_SGE_FLAGS_SIMPLE_ELEMENT |
+                         MPI_SGE_FLAGS_SYSTEM_ADDRESS |
+                         MPI_SGE_FLAGS_32_BIT_ADDRESSING |
+                         MPI_SGE_FLAGS_32_BIT_CONTEXT) << MPI_SGE_FLAGS_SHIFT) |
+                       (u32)data_sz
+       );
+       page0_dma = pci_map_single(ioc->pcidev, page0, data_sz, PCI_DMA_FROMDEVICE);
+       config_req.PageBufferSGE.u.Simple.u.Address32 = cpu_to_le32(page0_dma);
+
+       dprintk((KERN_INFO MYNAM ": %s: Sending Config request LAN_PAGE_0\n",
+                       ioc->name));
+
+       i = HandShakeReqAndReply(ioc, req_sz, (u32*)&config_req,
+                               reply_sz, (u16*)&config_reply);
+       pci_unmap_single(ioc->pcidev, page0_dma, data_sz, PCI_DMA_FROMDEVICE);
+       if (i != 0)
+               return i;
+
+       /*  Now byte swap the necessary LANPage0 fields  */
+
+/* LANPage1 */
+       /*  Immediate destination (reply area)...  */
+       reply_sz = sizeof(config_reply);
+       memset(&config_reply, 0, reply_sz);
+
+       /*  Ultimate destination...  */
+       page1 = &ioc->lan_cnfg_page1;
+       data_sz = sizeof(*page1);
+       memset(page1, 0, data_sz);
+
+       /*  Request area (config_req on the stack right now!)  */
+       req_sz = sizeof(config_req);
+       memset(&config_req, 0, req_sz);
+       config_req.Function = MPI_FUNCTION_CONFIG;
+       config_req.Action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+       /*      config_req.Header.PageVersion = 0;      */
+       /*      config_req.Header.PageLength = 0;       */
+       config_req.Header.PageNumber = 1;
+       config_req.Header.PageType = MPI_CONFIG_PAGETYPE_LAN;
+       /*      config_req.PageAddress = 0;             */
+       config_req.PageBufferSGE.u.Simple.FlagsLength = cpu_to_le32(
+                       ((MPI_SGE_FLAGS_LAST_ELEMENT |
+                         MPI_SGE_FLAGS_END_OF_BUFFER |
+                         MPI_SGE_FLAGS_END_OF_LIST |
+                         MPI_SGE_FLAGS_SIMPLE_ELEMENT |
+                         MPI_SGE_FLAGS_SYSTEM_ADDRESS |
+                         MPI_SGE_FLAGS_32_BIT_ADDRESSING |
+                         MPI_SGE_FLAGS_32_BIT_CONTEXT) << MPI_SGE_FLAGS_SHIFT) |
+                       (u32)data_sz
+       );
+       page1_dma = pci_map_single(ioc->pcidev, page1, data_sz, PCI_DMA_FROMDEVICE);
+       config_req.PageBufferSGE.u.Simple.u.Address32 = cpu_to_le32(page1_dma);
+
+       dprintk((KERN_INFO MYNAM ": %s: Sending Config request LAN_PAGE_1\n",
+                       ioc->name));
+
+       i = HandShakeReqAndReply(ioc, req_sz, (u32*)&config_req,
+                               reply_sz, (u16*)&config_reply);
+       pci_unmap_single(ioc->pcidev, page1_dma, data_sz, PCI_DMA_FROMDEVICE);
+       if (i != 0)
+               return i;
+
+       /*  Now byte swap the necessary LANPage1 fields  */
+
+       return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     SendEventNotification - Send EventNotification (on or off) request
+ *     to MPT adapter.
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @EvSwitch: Event switch flags
+ */
+static int
+SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch)
+{
+       EventNotification_t     *evnp;
+
+       evnp = (EventNotification_t *) mpt_get_msg_frame(mpt_base_index, ioc->id);
+       if (evnp == NULL) {
+               dprintk((KERN_WARNING MYNAM ": %s: WARNING - Unable to allocate a event request frame!\n",
+                               ioc->name));
+               return 0;
+       }
+       memset(evnp, 0, sizeof(*evnp));
+
+       dprintk((KERN_INFO MYNAM ": %s: Sending EventNotification(%d)\n", ioc->name, EvSwitch));
+
+       evnp->Function = MPI_FUNCTION_EVENT_NOTIFICATION;
+       evnp->ChainOffset = 0;
+       evnp->MsgFlags = 0;
+       evnp->Switch = EvSwitch;
+
+       mpt_put_msg_frame(mpt_base_index, ioc->id, (MPT_FRAME_HDR *)evnp);
+
+       return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     SendEventAck - Send EventAck request to MPT adapter.
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @evnp: Pointer to original EventNotification request
+ */
+static int
+SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp)
+{
+       EventAck_t      *pAck;
+
+       if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc->id)) == NULL) {
+               printk(KERN_WARNING MYNAM ": %s: WARNING - Unable to allocate event ACK request frame!\n",
+                               ioc->name);
+               return -1;
+       }
+       memset(pAck, 0, sizeof(*pAck));
+
+       dprintk((KERN_INFO MYNAM ": %s: Sending EventAck\n", ioc->name));
+
+       pAck->Function     = MPI_FUNCTION_EVENT_ACK;
+       pAck->ChainOffset  = 0;
+       pAck->MsgFlags     = 0;
+       pAck->Event        = evnp->Event;
+       pAck->EventContext = evnp->EventContext;
+
+       mpt_put_msg_frame(mpt_base_index, ioc->id, (MPT_FRAME_HDR *)pAck);
+
+       return 0;
+}
+
+#ifdef CONFIG_PROC_FS          /* { */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff...
+ */
+
+#define PROC_MPT_READ_RETURN(page,start,off,count,eof,len) \
+{ \
+       len -= off;                     \
+       if (len < count) {              \
+               *eof = 1;               \
+               if (len <= 0)           \
+                       return 0;       \
+       } else                          \
+               len = count;            \
+       *start = page + off;            \
+       return len;                     \
+}
+
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries.
+ *
+ *     Returns 0 for success, non-zero for failure.
+ */
+static int
+procmpt_create(void)
+{
+       MPT_ADAPTER *ioc;
+       struct proc_dir_entry *ent;
+       int errcnt = 0;
+
+       /*
+        *      BEWARE: If/when MPT_PROCFS_MPTBASEDIR changes from "mpt"
+        *      (single level) to multi level (e.g. "driver/message/fusion")
+        *      something here needs to change.  -sralston
+        */
+       procmpt_root_dir = CREATE_PROCDIR_ENTRY(MPT_PROCFS_MPTBASEDIR, NULL);
+       if (procmpt_root_dir == NULL)
+               return -ENOTDIR;
+
+       if ((ioc = mpt_adapter_find_first()) != NULL) {
+               ent = create_proc_read_entry(MPT_PROCFS_SUMMARY_NODE, 0, NULL, procmpt_read_summary, NULL);
+               if (ent == NULL) {
+                       printk(KERN_WARNING MYNAM ": WARNING - Could not create %s entry!\n",
+                                       MPT_PROCFS_SUMMARY_PATHNAME);
+                       errcnt++;
+               }
+       }
+
+       while (ioc != NULL) {
+               char pname[32];
+               int namelen;
+               /*
+                *  Create "/proc/mpt/iocN" subdirectory entry for each MPT adapter.
+                */
+               namelen = sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name);
+               if ((ent = CREATE_PROCDIR_ENTRY(pname, NULL)) != NULL) {
+                       /*
+                        *  And populate it with: "summary" and "dbg" file entries.
+                        */
+                       (void) sprintf(pname+namelen, "/summary");
+                       ent = create_proc_read_entry(pname, 0, NULL, procmpt_read_summary, ioc);
+                       if (ent == NULL) {
+                               errcnt++;
+                               printk(KERN_WARNING MYNAM ": %s: WARNING - Could not create /proc/%s entry!\n",
+                                               ioc->name, pname);
+                       }
+//#ifdef MPT_DEBUG
+                       /* DEBUG aid! */
+                       (void) sprintf(pname+namelen, "/dbg");
+                       ent = create_proc_read_entry(pname, 0, NULL, procmpt_read_dbg, ioc);
+                       if (ent == NULL) {
+                               errcnt++;
+                               printk(KERN_WARNING MYNAM ": %s: WARNING - Could not create /proc/%s entry!\n",
+                                               ioc->name, pname);
+                       }
+//#endif
+               } else {
+                       errcnt++;
+                       printk(KERN_WARNING MYNAM ": %s: WARNING - Could not create /proc/%s entry!\n",
+                                       ioc->name, pname);
+
+               }
+
+               ioc = mpt_adapter_find_next(ioc);
+       }
+
+       if (errcnt) {
+//             remove_proc_entry("mpt", 0);
+               return -ENOTDIR;
+       }
+
+       return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     procmpt_destroy - Tear down %MPT_PROCFS_MPTBASEDIR entries.
+ *
+ *     Returns 0 for success, non-zero for failure.
+ */
+static int
+procmpt_destroy(void)
+{
+       MPT_ADAPTER *ioc;
+
+       /*
+        *      BEWARE: If/when MPT_PROCFS_MPTBASEDIR changes from "mpt"
+        *      (single level) to multi level (e.g. "driver/message/fusion")
+        *      something here needs to change.  -sralston
+        */
+
+       ioc = mpt_adapter_find_first();
+       if (ioc != NULL) {
+               remove_proc_entry(MPT_PROCFS_SUMMARY_NODE, 0);
+       }
+
+       while (ioc != NULL) {
+               char pname[32];
+               int namelen;
+               /*
+                *  Tear down each "/proc/mpt/iocN" subdirectory.
+                */
+               namelen = sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name);
+               (void) sprintf(pname+namelen, "/summary");
+               remove_proc_entry(pname, 0);
+//#ifdef MPT_DEBUG
+               (void) sprintf(pname+namelen, "/dbg");
+               remove_proc_entry(pname, 0);
+//#endif
+               (void) sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name);
+               remove_proc_entry(pname, 0);
+
+               ioc = mpt_adapter_find_next(ioc);
+       }
+
+       if (atomic_read((atomic_t *)&procmpt_root_dir->count) == 0) {
+               remove_proc_entry(MPT_PROCFS_MPTBASEDIR, 0);
+               return 0;
+       }
+
+       return -1;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     procmpt_read_summary - Handle read request from /proc/mpt/summary
+ *     or from /proc/mpt/iocN/summary.
+ *     @page: Pointer to area to write information
+ *     @start: Pointer to start pointer
+ *     @off: Offset to start writing
+ *     @count: 
+ *     @eof: Pointer to EOF integer
+ *     @data: Pointer 
+ *
+ *     Returns numbers of characters written to process performing the read.
+ */
+static int
+procmpt_read_summary(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+       MPT_ADAPTER *ioc;
+       char *out = page;
+       int len;
+
+       if (data == NULL)
+               ioc = mpt_adapter_find_first();
+       else
+               ioc = data;
+
+// Too verbose!
+//     out += sprintf(out, "Attached Fusion MPT I/O Controllers:%s\n", ioc ? "" : " none");
+
+       while (ioc) {
+               int     more = 0;
+
+// Too verbose!
+//             mpt_print_ioc_facts(ioc, out, &more, 0);
+               mpt_print_ioc_summary(ioc, out, &more, 0);
+
+               out += more;
+               if ((out-page) >= count) {
+                       break;
+               }
+
+               if (data == NULL)
+                       ioc = mpt_adapter_find_next(ioc);
+               else
+                       ioc = NULL;                             /* force exit for iocN */
+       }
+       len = out - page;
+
+       PROC_MPT_READ_RETURN(page,start,off,count,eof,len);
+}
+
+// debug aid!
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     procmpt_read_dbg - Handle read request from /proc/mpt/iocN/dbg.
+ *     @page: Pointer to area to write information
+ *     @start: Pointer to start pointer
+ *     @off: Offset to start writing
+ *     @count: 
+ *     @eof: Pointer to EOF integer
+ *     @data: Pointer 
+ *
+ *     Returns numbers of characters written to process performing the read.
+ */
+static int
+procmpt_read_dbg(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+       MPT_ADAPTER *ioc;
+       char *out = page;
+       int len;
+
+       ioc = data;
+
+       while (ioc) {
+               int     more = 0;
+
+               mpt_print_ioc_facts(ioc, out, &more, 0);
+
+               out += more;
+               if ((out-page) >= count) {
+                       break;
+               }
+               ioc = NULL;
+       }
+       len = out - page;
+
+       PROC_MPT_READ_RETURN(page,start,off,count,eof,len);
+}
+#endif         /* CONFIG_PROC_FS } */
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static void
+mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc)
+{
+       if ((ioc->facts0.FWVersion & 0xF000) == 0xE000)
+               sprintf(buf, " (Exp %02d%02d)",
+                       (ioc->facts0.FWVersion & 0x0F00) >> 8,  /* Month */
+                       ioc->facts0.FWVersion & 0x001F);        /* Day */
+       else
+               buf[0] ='\0';
+
+       /* insider hack! */
+       if (ioc->facts0.FWVersion & 0x0080) {
+               strcat(buf, " [MDBG]");
+       }
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mpt_print_ioc_summary - Write ASCII summary of IOC to a buffer.
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @buffer: Pointer to buffer where IOC summary info should be written
+ *     @size: Pointer to number of bytes we wrote (set by this routine)
+ *     @len: Offset at which to start writing in buffer
+ *
+ *     This routine writes (english readable) ASCII text, which represents
+ *     a summary of IOC information, to a buffer.
+ */
+void
+mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len)
+{
+       char expVer[32];
+       int y;
+
+
+       mpt_get_fw_exp_ver(expVer, ioc);
+
+       /*
+        *  Shorter summary of attached ioc's...
+        */
+       y = sprintf(buffer+len, "%s: %s, %s%04xh%s, Ports=%d, MaxQ=%d",
+                       ioc->name,
+                       ioc->prod_name,
+                       MPT_FW_REV_MAGIC_ID_STRING,     /* "FwRev=" or somesuch */
+                       ioc->facts0.FWVersion,
+                       expVer,
+                       ioc->facts0.NumberOfPorts,
+                       ioc->req_depth);
+
+       if (ioc->pfacts0.ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
+               u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
+               y += sprintf(buffer+len+y, ", LanAddr=%02X:%02X:%02X:%02X:%02X:%02X",
+                       a[5], a[4], a[3], a[2], a[1], a[0]);
+       }
+
+       if (!ioc->active)
+               y += sprintf(buffer+len+y, " (disabled)");
+
+       y += sprintf(buffer+len+y, "\n");
+
+       *size = y;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mpt_print_ioc_facts - Write ASCII summary of IOC facts to a buffer.
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @buffer: Pointer to buffer where IOC facts should be written
+ *     @size: Pointer to number of bytes we wrote (set by this routine)
+ *     @len: Offset at which to start writing in buffer
+ *
+ *     This routine writes (english readable) ASCII text, which represents
+ *     a summary of the IOC facts, to a buffer.
+ */
+void
+mpt_print_ioc_facts(MPT_ADAPTER *ioc, char *buffer, int *size, int len)
+{
+       char expVer[32];
+       char iocName[16];
+       int sz;
+       int y;
+
+
+       mpt_get_fw_exp_ver(expVer, ioc);
+
+       strcpy(iocName, ioc->name);
+       y = sprintf(buffer+len, "%s:\n", iocName);
+
+       y += sprintf(buffer+len+y, "  ProductID = 0x%04x\n", ioc->facts0.ProductID);
+       y += sprintf(buffer+len+y, "  PortNumber = %d (of %d)\n",
+               ioc->pfacts0.PortNumber+1,
+               ioc->facts0.NumberOfPorts);
+       if (ioc->pfacts0.ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
+               u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
+               y += sprintf(buffer+len+y, "  LanAddr = 0x%02x:%02x:%02x:%02x:%02x:%02x\n",
+                       a[5], a[4], a[3], a[2], a[1], a[0]);
+       }
+       y += sprintf(buffer+len+y, "  FWVersion = 0x%04x%s\n", ioc->facts0.FWVersion, expVer);
+       y += sprintf(buffer+len+y, "  MsgVersion = 0x%04x\n", ioc->facts0.MsgVersion);
+       y += sprintf(buffer+len+y, "  WhoInit = 0x%02x\n", ioc->facts0.WhoInit);
+       y += sprintf(buffer+len+y, "  EventState = 0x%02x\n", ioc->facts0.EventState);
+       y += sprintf(buffer+len+y, "  CurrentHostMfaHighAddr = 0x%08x\n",
+                       ioc->facts0.CurrentHostMfaHighAddr);
+       y += sprintf(buffer+len+y, "  CurrentSenseBufferHighAddr = 0x%08x\n",
+                       ioc->facts0.CurrentSenseBufferHighAddr);
+       y += sprintf(buffer+len+y, "  MaxChainDepth = 0x%02x frames\n", ioc->facts0.MaxChainDepth);
+       y += sprintf(buffer+len+y, "  MinBlockSize = 0x%02x bytes\n", 4*ioc->facts0.BlockSize);
+
+       y += sprintf(buffer+len+y, "  RequestFrames @ 0x%p (Dma @ 0x%08x)\n",
+                                       ioc->req_alloc, ioc->req_alloc_dma);
+       /*
+        *  Rounding UP to nearest 4-kB boundary here...
+        */
+       sz = (ioc->req_sz * ioc->req_depth) + 128;
+       sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
+       y += sprintf(buffer+len+y, "    {CurReqSz=%d} x {CurReqDepth=%d} = %d bytes ^= 0x%x\n",
+                                       ioc->req_sz, ioc->req_depth, ioc->req_sz*ioc->req_depth, sz);
+       y += sprintf(buffer+len+y, "    {MaxReqSz=%d}   {MaxReqDepth=%d}\n",
+                                       4*ioc->facts0.RequestFrameSize,
+                                       ioc->facts0.GlobalCredits);
+
+       y += sprintf(buffer+len+y, "  ReplyFrames   @ 0x%p (Dma @ 0x%08x)\n",
+                                       ioc->reply_alloc, ioc->reply_alloc_dma);
+       sz = (ioc->reply_sz * ioc->reply_depth) + 128;
+       y += sprintf(buffer+len+y, "    {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n",
+                                       ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz);
+       y += sprintf(buffer+len+y, "    {MaxRepSz=%d}   {MaxRepDepth=%d}\n",
+                                       ioc->factsN.CurReplyFrameSize,
+                                       ioc->facts0.ReplyQueueDepth);
+
+       *size = y;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static char *
+EventDescriptionStr(u8 event, u32 evData0)
+{
+       char *ds = NULL;
+
+       switch(event) {
+       case MPI_EVENT_NONE:
+               ds = "None";
+               break;
+       case MPI_EVENT_LOG_DATA:
+               ds = "Log Data";
+               break;
+       case MPI_EVENT_STATE_CHANGE:
+               ds = "State Change";
+               break;
+       case MPI_EVENT_UNIT_ATTENTION:
+               ds = "Unit Attention";
+               break;
+       case MPI_EVENT_IOC_BUS_RESET:
+               ds = "IOC Bus Reset";
+               break;
+       case MPI_EVENT_EXT_BUS_RESET:
+               ds = "External Bus Reset";
+               break;
+       case MPI_EVENT_RESCAN:
+               ds = "Bus Rescan Event"; 
+               /* Ok, do we need to do anything here? As far as
+                  I can tell, this is when a new device gets added
+                  to the loop. */
+               break;
+       case MPI_EVENT_LINK_STATUS_CHANGE:
+               if (evData0 == MPI_EVENT_LINK_STATUS_FAILURE)
+                       ds = "Link Status(FAILURE) Change";
+               else
+                       ds = "Link Status(ACTIVE) Change";
+               break;
+       case MPI_EVENT_LOOP_STATE_CHANGE:
+               if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP)
+                       ds = "Loop State(LIP) Change";
+               else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE)
+                       ds = "Loop State(LPE) Change";                  /* ??? */
+               else
+                       ds = "Loop State(LPB) Change";                  /* ??? */
+               break;
+       case MPI_EVENT_LOGOUT:
+               ds = "Logout";
+               break;
+       case MPI_EVENT_EVENT_CHANGE:
+               if (evData0)
+                       ds = "Events(ON) Change";
+               else
+                       ds = "Events(OFF) Change";
+               break;
+       /*
+        *  MPT base "custom" events may be added here...
+        */
+       default:
+               ds = "Unknown";
+               break;
+       }
+       return ds;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     ProcessEventNotification - Route a received EventNotificationReply to
+ *     all currently regeistered event handlers.
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @pEventReply: Pointer to EventNotification reply frame
+ *     @evHandlers: Pointer to integer, number of event handlers
+ *
+ *     Returns sum of event handlers return values.
+ */
+static int
+ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply, int *evHandlers)
+{
+       u16 evDataLen;
+       u32 evData0 = 0;
+//     u32 evCtx;
+       int i;
+       int r = 0;
+       int handlers = 0;
+       char *evStr;
+       u8 event;
+
+       /*
+        *  Do platform normalization of values
+        */
+       event = le32_to_cpu(pEventReply->Event) & 0xFF;
+//     evCtx = le32_to_cpu(pEventReply->EventContext);
+       evDataLen = le16_to_cpu(pEventReply->EventDataLength);
+       if (evDataLen) {
+               evData0 = le32_to_cpu(pEventReply->Data[0]);
+       }
+
+       evStr = EventDescriptionStr(event, evData0);
+       dprintk((KERN_INFO MYNAM ": %s: MPT event (%s=%02Xh) detected!\n",
+                       ioc->name,
+                       evStr,
+                       event));
+
+#if defined(MPT_DEBUG) || defined(MPT_DEBUG_EVENTS)
+       printk(KERN_INFO MYNAM ": Event data:\n" KERN_INFO);
+       for (i = 0; i < evDataLen; i++)
+               printk(" %08x", le32_to_cpu(pEventReply->Data[i]));
+       printk("\n");
+#endif
+
+       /*
+        *  Do general / base driver event processing
+        */
+       switch(event) {
+       case MPI_EVENT_NONE:                    /* 00 */
+       case MPI_EVENT_LOG_DATA:                /* 01 */
+       case MPI_EVENT_STATE_CHANGE:            /* 02 */
+       case MPI_EVENT_UNIT_ATTENTION:          /* 03 */
+       case MPI_EVENT_IOC_BUS_RESET:           /* 04 */
+       case MPI_EVENT_EXT_BUS_RESET:           /* 05 */
+       case MPI_EVENT_RESCAN:                  /* 06 */
+       case MPI_EVENT_LINK_STATUS_CHANGE:      /* 07 */
+       case MPI_EVENT_LOOP_STATE_CHANGE:       /* 08 */
+       case MPI_EVENT_LOGOUT:                  /* 09 */
+       default:
+               break;
+       case MPI_EVENT_EVENT_CHANGE:            /* 0A */
+               if (evDataLen) {
+                       u8 evState = evData0 & 0xFF;
+
+                       /* CHECKME! What if evState unexpectedly says OFF (0)? */
+
+                       /* Update EventState field in cached IocFacts */
+                       if (ioc->factsN.Function) {
+                               ioc->factsN.EventState = evState;
+                       }
+               }
+               break;
+       }
+
+       /*
+        *  Call each currently registered protocol event handler.
+        */
+       for (i=MPT_MAX_PROTOCOL_DRIVERS-1; i; i--) {
+               if (MptEvHandlers[i]) {
+                       dprintk((KERN_INFO MYNAM ": %s: Routing Event to event handler #%d\n",
+                                       ioc->name, i));
+                       r += (*(MptEvHandlers[i]))(ioc, pEventReply);
+                       handlers++;
+               }
+       }
+       /* FIXME?  Examine results here? */
+
+       /*
+        *  If needed, send (a single) EventAck.
+        */
+       if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) {
+               if ((i = SendEventAck(ioc, pEventReply)) != 0) {
+               }
+       }
+
+       *evHandlers = handlers;
+       return r;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     mpt_fc_log_info - Log information returned from Fibre Channel IOC.
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @log_info: U32 LogInfo reply word from the IOC
+ *
+ *     Refer to lsi/fc_log.h.
+ */
+static void
+mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info)
+{
+       static char *subcl_str[8] = {
+               "FCP Initiator", "FCP Target", "LAN", "MPI Message Layer",
+               "FC Link", "Context Manager", "Invalid Field Offset", "State Change Info"
+       };
+       char *desc = "unknown";
+       u8 subcl = (log_info >> 24) & 0x7;
+       u32 SubCl = log_info & 0x27000000;
+
+       switch(log_info) {
+/* FCP Initiator */
+       case MPI_IOCLOGINFO_FC_INIT_ERROR_OUT_OF_ORDER_FRAME:
+               desc = "Received an out of order frame - unsupported";
+               break;
+       case MPI_IOCLOGINFO_FC_INIT_ERROR_BAD_START_OF_FRAME:
+               desc = "Bad start of frame primative";
+               break;
+       case MPI_IOCLOGINFO_FC_INIT_ERROR_BAD_END_OF_FRAME:
+               desc = "Bad end of frame primative";
+               break;
+       case MPI_IOCLOGINFO_FC_INIT_ERROR_OVER_RUN:
+               desc = "Receiver hardware detected overrun";
+               break;
+       case MPI_IOCLOGINFO_FC_INIT_ERROR_RX_OTHER:
+               desc = "Other errors caught by IOC which require retries";
+               break;
+       case MPI_IOCLOGINFO_FC_INIT_ERROR_SUBPROC_DEAD:
+               desc = "Main processor could not initialize sub-processor";
+               break;
+/* FC Target */
+       case MPI_IOCLOGINFO_FC_TARGET_NO_PDISC:
+               desc = "Not sent because we are waiting for a PDISC from the initiator";
+               break;
+       case MPI_IOCLOGINFO_FC_TARGET_NO_LOGIN:
+               desc = "Not sent because we are not logged in to the remote node";
+               break;
+       case MPI_IOCLOGINFO_FC_TARGET_DOAR_KILLED_BY_LIP:
+               desc = "Data Out, Auto Response, not sent due to a LIP";
+               break;
+       case MPI_IOCLOGINFO_FC_TARGET_DIAR_KILLED_BY_LIP:
+               desc = "Data In, Auto Response, not sent due to a LIP";
+               break;
+       case MPI_IOCLOGINFO_FC_TARGET_DIAR_MISSING_DATA:
+               desc = "Data In, Auto Response, missing data frames";
+               break;
+       case MPI_IOCLOGINFO_FC_TARGET_DONR_KILLED_BY_LIP:
+               desc = "Data Out, No Response, not sent due to a LIP";
+               break;
+       case MPI_IOCLOGINFO_FC_TARGET_WRSP_KILLED_BY_LIP:
+               desc = "Auto-response after a write not sent due to a LIP";
+               break;
+       case MPI_IOCLOGINFO_FC_TARGET_DINR_KILLED_BY_LIP:
+               desc = "Data In, No Response, not completed due to a LIP";
+               break;
+       case MPI_IOCLOGINFO_FC_TARGET_DINR_MISSING_DATA:
+               desc = "Data In, No Response, missing data frames";
+               break;
+       case MPI_IOCLOGINFO_FC_TARGET_MRSP_KILLED_BY_LIP:
+               desc = "Manual Response not sent due to a LIP";
+               break;
+       case MPI_IOCLOGINFO_FC_TARGET_NO_CLASS_3:
+               desc = "Not sent because remote node does not support Class 3";
+               break;
+       case MPI_IOCLOGINFO_FC_TARGET_LOGIN_NOT_VALID:
+               desc = "Not sent because login to remote node not validated";
+               break;
+       case MPI_IOCLOGINFO_FC_TARGET_FROM_OUTBOUND:
+               desc = "Cleared from the outbound after a logout";
+               break;
+       case MPI_IOCLOGINFO_FC_TARGET_WAITING_FOR_DATA_IN:
+               desc = "Cleared waiting for data after a logout";
+               break;
+/* LAN */
+       case MPI_IOCLOGINFO_FC_LAN_TRANS_SGL_MISSING:
+               desc = "Transaction Context Sgl Missing";
+               break;
+       case MPI_IOCLOGINFO_FC_LAN_TRANS_WRONG_PLACE:
+               desc = "Transaction Context found before an EOB";
+               break;
+       case MPI_IOCLOGINFO_FC_LAN_TRANS_RES_BITS_SET:
+               desc = "Transaction Context value has reserved bits set";
+               break;
+       case MPI_IOCLOGINFO_FC_LAN_WRONG_SGL_FLAG:
+               desc = "Invalid SGL Flags";
+               break;
+/* FC Link */
+       case MPI_IOCLOGINFO_FC_LINK_LOOP_INIT_TIMEOUT:
+               desc = "Loop initialization timed out";
+               break;
+       case MPI_IOCLOGINFO_FC_LINK_ALREADY_INITIALIZED:
+               desc = "Another system controller already initialized the loop";
+               break;
+       case MPI_IOCLOGINFO_FC_LINK_LINK_NOT_ESTABLISHED:
+               desc = "Not synchronized to signal or still negotiating (possible cable problem)";
+               break;
+       }
+
+       printk(KERN_INFO MYNAM ": %s: LogInfo(0x%08x): SubCl={%s}",
+                       ioc->name, log_info, subcl_str[subcl]);
+       if (SubCl == MPI_IOCLOGINFO_FC_INVALID_FIELD_BYTE_OFFSET)
+               printk(", byte_offset=%d\n", log_info & MPI_IOCLOGINFO_FC_INVALID_FIELD_MAX_OFFSET);
+       else if (SubCl == MPI_IOCLOGINFO_FC_STATE_CHANGE)
+               printk("\n");           /* StateChg in LogInfo & 0x00FFFFFF, above */
+       else
+               printk("\n" KERN_INFO " %s\n", desc);
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     mpt_sp_log_info - Log information returned from SCSI Parallel IOC.
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @mr: Pointer to MPT reply frame
+ *     @log_info: U32 LogInfo word from the IOC
+ *
+ *     Refer to lsi/sp_log.h.
+ */
+static void
+mpt_sp_log_info(MPT_ADAPTER *ioc, u32 log_info)
+{
+       /* FIXME! */
+       printk(KERN_INFO MYNAM ": %s: LogInfo(0x%08x)\n", ioc->name, log_info);
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mpt_register_ascqops_strings - Register SCSI ASC/ASCQ and SCSI
+ *     OpCode strings from the (optional) isense module.
+ *     @ascqTable: Pointer to ASCQ_Table_t structure
+ *     @ascqtbl_sz: Number of entries in ASCQ_Table
+ *     @opsTable: Pointer to array of SCSI OpCode strings (char pointers)
+ *
+ *     Specialized driver registration routine for the isense driver.
+ */
+int
+mpt_register_ascqops_strings(/*ASCQ_Table_t*/void *ascqTable, int ascqtbl_sz, const char **opsTable)
+{
+       int r = 0;
+
+       if (ascqTable && ascqtbl_sz && opsTable) {
+               mpt_v_ASCQ_TablePtr = ascqTable;
+               mpt_ASCQ_TableSz = ascqtbl_sz;
+               mpt_ScsiOpcodesPtr = opsTable;
+               printk(KERN_INFO MYNAM ": English readable SCSI-3 strings enabled:-)\n");
+               r = 1;
+       }
+       MOD_INC_USE_COUNT;
+       return r;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mpt_deregister_ascqops_strings - Deregister SCSI ASC/ASCQ and SCSI
+ *     OpCode strings from the isense driver.
+ *
+ *     Specialized driver deregistration routine for the isense driver.
+ */
+void
+mpt_deregister_ascqops_strings(void)
+{
+       mpt_v_ASCQ_TablePtr = NULL;
+       mpt_ASCQ_TableSz = 0;
+       mpt_ScsiOpcodesPtr = NULL;
+       printk(KERN_INFO MYNAM ": English readable SCSI-3 strings disabled)-:\n");
+       MOD_DEC_USE_COUNT;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+EXPORT_SYMBOL(mpt_register);
+EXPORT_SYMBOL(mpt_deregister);
+EXPORT_SYMBOL(mpt_event_register);
+EXPORT_SYMBOL(mpt_event_deregister);
+EXPORT_SYMBOL(mpt_get_msg_frame);
+EXPORT_SYMBOL(mpt_put_msg_frame);
+EXPORT_SYMBOL(mpt_free_msg_frame);
+EXPORT_SYMBOL(mpt_send_handshake_request);
+EXPORT_SYMBOL(mpt_adapter_find_first);
+EXPORT_SYMBOL(mpt_adapter_find_next);
+EXPORT_SYMBOL(mpt_verify_adapter);
+EXPORT_SYMBOL(mpt_print_ioc_summary);
+EXPORT_SYMBOL(mpt_lan_index);
+EXPORT_SYMBOL(mpt_stm_index);
+
+EXPORT_SYMBOL(mpt_register_ascqops_strings);
+EXPORT_SYMBOL(mpt_deregister_ascqops_strings);
+EXPORT_SYMBOL(mpt_v_ASCQ_TablePtr);
+EXPORT_SYMBOL(mpt_ASCQ_TableSz);
+EXPORT_SYMBOL(mpt_ScsiOpcodesPtr);
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     fusion_init - Fusion MPT base driver initialization routine.
+ *
+ *     Returns 0 for success, non-zero for failure.
+ */
+int __init fusion_init(void)
+{
+       int i;
+
+       if (FusionInitCalled++) {
+               dprintk((KERN_INFO MYNAM ": INFO - Driver late-init entry point called\n"));
+               return 0;
+       }
+
+       show_mptmod_ver(my_NAME, my_VERSION);
+       printk(KERN_INFO COPYRIGHT "\n");
+
+       Q_INIT(&MptAdapters, MPT_ADAPTER);                      /* set to empty */
+       for (i = 0; i < MPT_MAX_PROTOCOL_DRIVERS; i++) {
+               MptCallbacks[i] = NULL;
+               MptDriverClass[i] = MPTUNKNOWN_DRIVER;
+               MptEvHandlers[i] = NULL;
+       }
+
+       /* NEW!  20010120 -sralston
+        *  Register ourselves (mptbase) in order to facilitate
+        *  EventNotification handling.
+        */
+       mpt_base_index = mpt_register(mpt_base_reply, MPTBASE_DRIVER);
+
+       if ((i = mpt_pci_scan()) < 0)
+               return i;
+
+       return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     fusion_exit - Perform driver unload cleanup.
+ *
+ *     This routine frees all resources associated with each MPT adapter
+ *     and removes all %MPT_PROCFS_MPTBASEDIR entries.
+ */
+static void fusion_exit(void)
+{
+       MPT_ADAPTER *this;
+       int i;
+
+       dprintk((KERN_INFO MYNAM ": fusion_exit() called!\n"));
+
+       /*
+        *  Paranoia; disable interrupts on all MPT adapters.
+        */
+       for (i=0; i<MPT_MAX_ADAPTERS; i++) {
+               if ((this = mpt_adapters[i]) != NULL) {
+                       /* Disable adapter interrupts! */
+                       CHIPREG_WRITE32(&this->chip->IntMask, 0xFFFFFFFF);
+                       /* Clear any lingering interrupt */
+                       CHIPREG_WRITE32(&this->chip->IntStatus, 0);
+                       this->active = 0;
+               }
+       }
+
+       /* Whups?  20010120 -sralston
+        *  Moved this *above* removal of all MptAdapters!
+        */
+#ifdef CONFIG_PROC_FS
+       procmpt_destroy();
+#endif
+
+       while (! Q_IS_EMPTY(&MptAdapters)) {
+               this = MptAdapters.head;
+               Q_DEL_ITEM(this);
+               mpt_adapter_dispose(this);
+       }
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+module_init(fusion_init);
+module_exit(fusion_exit);
diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h
new file mode 100644 (file)
index 0000000..68fc7ac
--- /dev/null
@@ -0,0 +1,581 @@
+/*
+ *  linux/drivers/message/fusion/mptbase.h
+ *      High performance SCSI + LAN / Fibre Channel device drivers.
+ *      For use with PCI chip/adapter(s):
+ *          LSIFC9xx/LSI409xx Fibre Channel
+ *      running LSI Logic Fusion MPT (Message Passing Technology) firmware.
+ *
+ *  Credits:
+ *     (see mptbase.c)
+ *
+ *  Copyright (c) 1999-2001 LSI Logic Corporation
+ *  Originally By: Steven J. Ralston
+ *  (mailto:Steve.Ralston@lsil.com)
+ *
+ *  $Id: mptbase.h,v 1.38 2001/03/22 10:54:30 sralston Exp $
+ */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; version 2 of the License.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    NO WARRANTY
+    THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+    CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+    LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+    MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+    solely responsible for determining the appropriateness of using and
+    distributing the Program and assumes all risks associated with its
+    exercise of rights under this Agreement, including but not limited to
+    the risks and costs of program errors, damage to or loss of data,
+    programs or equipment, and unavailability or interruption of operations.
+
+    DISCLAIMER OF LIABILITY
+    NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+    DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
+    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+    TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+    USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+    HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#ifndef MPTBASE_H_INCLUDED
+#define MPTBASE_H_INCLUDED
+/*{-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+#include "linux_compat.h"      /* linux-2.2.x (vs. -2.4.x) tweaks */
+
+#include "lsi/mpi_type.h"
+#include "lsi/mpi.h"           /* Fusion MPI(nterface) basic defs */
+#include "lsi/mpi_ioc.h"       /* Fusion MPT IOC(ontroller) defs */
+#include "lsi/mpi_cnfg.h"      /* IOC configuration support */
+#include "lsi/mpi_init.h"      /* SCSI Host (initiator) protocol support */
+#include "lsi/mpi_lan.h"       /* LAN over FC protocol support */
+
+//#include "lsi/mpi_fc.h"      /* Fibre Channel (lowlevel) support */
+//#include "lsi/mpi_targ.h"    /* SCSI/FCP Target protcol support */
+#include "lsi/fc_log.h"
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+#ifndef MODULEAUTHOR
+#define MODULEAUTHOR   "LSI Logic Corporation"
+#endif
+
+#ifndef COPYRIGHT
+#define COPYRIGHT      "Copyright (c) 1999-2001 " MODULEAUTHOR
+#endif
+
+#define MPT_LINUX_VERSION_COMMON       "1.00.11"
+#define MPT_LINUX_VERSION_EXP          "0.09.66-EXP"
+#define MPT_LINUX_PACKAGE_NAME         "@(#)mptlinux-1.00.11"
+#define WHAT_MAGIC_STRING              "@" "(" "#" ")"
+
+#define show_mptmod_ver(s,ver)  \
+       printk(KERN_INFO "%s %s\n", s, ver);
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *  Fusion MPT(linux) driver configurable stuff...
+ */
+#define MPT_MAX_ADAPTERS               16
+#define MPT_MAX_PROTOCOL_DRIVERS       8
+
+#define MPT_MISCDEV_BASENAME           "mptctl"
+#define MPT_MISCDEV_PATHNAME           "/dev/" MPT_MISCDEV_BASENAME
+
+#define MPT_PROCFS_MPTBASEDIR          "mpt"
+                                               /* chg it to "driver/fusion" ? */
+#define MPT_PROCFS_SUMMARY_NODE                MPT_PROCFS_MPTBASEDIR "/summary"
+#define MPT_PROCFS_SUMMARY_PATHNAME    "/proc/" MPT_PROCFS_SUMMARY_NODE
+#define MPT_FW_REV_MAGIC_ID_STRING     "FwRev="
+
+#ifdef __KERNEL__      /* { */
+#define  MPT_MAX_REQ_DEPTH             1023
+#define  MPT_REQ_DEPTH                 256
+#define  MPT_MIN_REQ_DEPTH             128
+
+#define  MPT_MAX_REPLY_DEPTH           MPT_MAX_REQ_DEPTH
+#define  MPT_REPLY_DEPTH               128
+#define  MPT_MIN_REPLY_DEPTH           8
+#define  MPT_MAX_REPLIES_PER_ISR       32
+
+#define  MPT_MAX_FRAME_SIZE            128
+#define  MPT_REQ_SIZE                  128
+#define  MPT_REPLY_SIZE                        128
+
+#define  MPT_SG_BUCKETS_PER_HUNK       1
+
+#ifdef MODULE
+#define  MPT_REQ_DEPTH_RANGE_STR       __MODULE_STRING(MPT_MIN_REQ_DEPTH) "-" __MODULE_STRING(MPT_MAX_REQ_DEPTH)
+#define  MPT_REPLY_DEPTH_RANGE_STR     __MODULE_STRING(MPT_MIN_REPLY_DEPTH) "-" __MODULE_STRING(MPT_MAX_REPLY_DEPTH)
+#define  MPT_REPLY_SIZE_RANGE_STR      __MODULE_STRING(MPT_MIN_REPLY_SIZE) "-" __MODULE_STRING(MPT_MAX_FRAME_SIZE)
+#endif
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *  MPT protocol driver defs...
+ */
+typedef enum {
+       MPTBASE_DRIVER,         /* MPT base class */
+       MPTCTL_DRIVER,          /* MPT ioctl class */
+       MPTSCSIH_DRIVER,        /* MPT SCSI host (initiator) class */
+       MPTLAN_DRIVER,          /* MPT LAN class */
+       MPTSTM_DRIVER,          /* MPT SCSI target mode class */
+       MPTUNKNOWN_DRIVER
+} MPT_DRIVER_CLASS;
+
+/*
+ *  MPT adapter / port / bus / device info structures...
+ */
+
+typedef union _MPT_FRAME_TRACKER {
+       struct {
+               struct _MPT_FRAME_HDR   *forw;
+               struct _MPT_FRAME_HDR   *back;
+               u32                      arg1;
+               void                    *argp1;
+       } linkage;
+       /*
+        * NOTE: On non-32-bit systems, where pointers are LARGE,
+        * using the linkage pointers destroys our sacred MsgContext
+        * field contents.  But we don't care anymore because these
+        * are now reset in mpt_put_msg_frame() just prior to sending
+        * a request off to the IOC.
+        */
+       struct {
+               u32 __hdr[2];
+               /*
+                * The following _MUST_ match the location of the
+                * MsgContext field in the MPT message headers.
+                */
+               union {
+                       u32              MsgContext;
+                       struct {
+                               u16      req_idx;       /* Request index */
+                               u8       cb_idx;        /* callback function index */
+                               u8       rsvd;
+                       } fld;
+               } msgctxu;
+       } hwhdr;
+} MPT_FRAME_TRACKER;
+
+/*
+ *  We might want to view/access a frame as:
+ *    1) generic request header
+ *    2) SCSIIORequest
+ *    3) SCSIIOReply
+ *    4) MPIDefaultReply
+ *    5) frame tracker
+ */
+typedef struct _MPT_FRAME_HDR {
+       union {
+               MPIHeader_t             hdr;
+               SCSIIORequest_t         scsireq;
+               SCSIIOReply_t           sreply;
+               MPIDefaultReply_t       reply;
+               MPT_FRAME_TRACKER       frame;
+       } u;
+} MPT_FRAME_HDR;
+
+typedef struct _MPT_Q_TRACKER {
+       MPT_FRAME_HDR   *head;
+       MPT_FRAME_HDR   *tail;
+} MPT_Q_TRACKER;
+
+
+typedef struct _MPT_SGL_HDR {
+       SGESimple32_t    sge[1];
+} MPT_SGL_HDR;
+
+typedef struct _MPT_SGL64_HDR {
+       SGESimple64_t    sge[1];
+} MPT_SGL64_HDR;
+
+
+typedef struct _Q_ITEM {
+       struct _Q_ITEM  *forw;
+       struct _Q_ITEM  *back;
+} Q_ITEM;
+
+typedef struct _Q_TRACKER {
+       struct _Q_ITEM  *head;
+       struct _Q_ITEM  *tail;
+} Q_TRACKER;
+
+
+/*
+ *  Chip-specific stuff...
+ */
+
+typedef enum {
+       FC909 = 0x0909,
+       FC919 = 0x0919,
+       FC929 = 0x0929,
+       C1030 = 0x1030,
+       FCUNK = 0xFBAD
+} CHIP_TYPE;
+
+/*
+ *  System interface register set
+ */
+
+typedef struct _SYSIF_REGS
+{
+       u32     Doorbell;       /* 00     System<->IOC Doorbell reg  */
+       u32     WriteSequence;  /* 04     Write Sequence register    */
+       u32     Diagnostic;     /* 08     Diagnostic register        */
+       u32     TestBase;       /* 0C     Test Base Address          */
+       u32     Reserved1[8];   /* 10-2F  reserved for future use    */
+       u32     IntStatus;      /* 30     Interrupt Status           */
+       u32     IntMask;        /* 34     Interrupt Mask             */
+       u32     Reserved2[2];   /* 38-3F  reserved for future use    */
+       u32     RequestFifo;    /* 40     Request Post/Free FIFO     */
+       u32     ReplyFifo;      /* 44     Reply   Post/Free FIFO     */
+       u32     Reserved3[2];   /* 48-4F  reserved for future use    */
+       u32     HostIndex;      /* 50     Host Index register        */
+       u32     Reserved4[15];  /* 54-8F                             */
+       u32     Fubar;          /* 90     For Fubar usage            */
+       u32     Reserved5[27];  /* 94-FF                             */
+} SYSIF_REGS;
+
+/*
+ * NOTE: Use MPI_{DOORBELL,WRITESEQ,DIAG}_xxx defs in lsi/mpi.h
+ * in conjunction with SYSIF_REGS accesses!
+ */
+
+
+typedef struct _MPT_ADAPTER
+{
+       struct _MPT_ADAPTER     *forw;
+       struct _MPT_ADAPTER     *back;
+       int                      id;            /* Unique adapter id {0,1,2,...} */
+       int                      pci_irq;
+       IOCFactsReply_t          facts0;
+       IOCFactsReply_t          factsN;
+       char                     name[32];      /* "iocN"             */
+       char                    *prod_name;     /* "LSIFC9x9"         */
+       u32                      mem_phys;      /* == f4020000 (mmap) */
+       volatile SYSIF_REGS     *chip;          /* == c8817000 (mmap) */
+       CHIP_TYPE                chip_type;
+       int                      mem_size;
+       int                      alloc_total;
+       u32                      last_state;
+       int                      active;
+       int                      sod_reset;
+       unsigned long            last_kickstart;
+       PortFactsReply_t         pfacts0;
+       PortFactsReply_t         pfactsN;
+       LANPage0_t               lan_cnfg_page0;
+       LANPage1_t               lan_cnfg_page1;
+       u8                      *reply_alloc;           /* Reply frames alloc ptr */
+       dma_addr_t               reply_alloc_dma;
+       MPT_FRAME_HDR           *reply_frames;          /* Reply frames - rounded up! */
+       dma_addr_t               reply_frames_dma;
+       int                      reply_depth;
+       int                      reply_sz;
+               /* We (host driver) get to manage our own RequestQueue! */
+       u8                      *req_alloc;             /* Request frames alloc ptr */
+       dma_addr_t               req_alloc_dma;
+       MPT_FRAME_HDR           *req_frames;            /* Request msg frames for PULL mode! */
+       dma_addr_t               req_frames_dma;
+       int                      req_depth;
+       int                      req_sz;
+       spinlock_t               FreeQlock;
+       MPT_Q_TRACKER            FreeQ;
+               /* Pool of SCSI sense buffers for commands coming from
+                * the SCSI mid-layer.  We have one 256 byte sense buffer
+                * for each REQ entry.
+                */
+       u8                      *sense_buf_pool;
+       dma_addr_t               sense_buf_pool_dma;
+       int                      hs_reply_idx;
+       u32                      hs_req[MPT_MAX_FRAME_SIZE/sizeof(u32)];
+       u16                      hs_reply[MPT_MAX_FRAME_SIZE/sizeof(u16)];
+       struct pci_dev          *pcidev;
+       struct _MPT_ADAPTER     *alt_ioc;
+/*     atomic_t                 userCnt;       */
+       u8                      *memmap;
+       int                      mtrr_reg;
+       struct Scsi_Host        *sh;
+       struct proc_dir_entry   *ioc_dentry;
+} MPT_ADAPTER;
+
+
+typedef struct _MPT_ADAPTER_TRACKER {
+       MPT_ADAPTER     *head;
+       MPT_ADAPTER     *tail;
+} MPT_ADAPTER_TRACKER;
+
+/*
+ *  New return value convention:
+ *    1 = Ok to free associated request frame
+ *    0 = not Ok ...
+ */
+typedef int (*MPT_CALLBACK)(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply);
+typedef int (*MPT_EVHANDLER)(MPT_ADAPTER *ioc, EventNotificationReply_t *evReply);
+
+/*
+ *  Fibre Channel (SCSI) target device...
+ */
+typedef struct _FC_TARGET {
+       struct _FC_TARGET       *forw;
+       struct _FC_TARGET       *back;
+       int                      bus_id;
+       int                      target_id;
+       int                      lun_exists[32];
+       u8                       inquiry_data[36];
+       u8                       last_sense[256];
+} FC_TARGET;
+
+typedef struct _FCDEV_TRACKER {
+       FC_TARGET       *head;
+       FC_TARGET       *tail;
+} FCDEV_TRACKER;
+
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *  Funky (private) macros...
+ */
+#ifdef MPT_DEBUG
+#define dprintk(x)  printk x
+#else
+#define dprintk(x)
+#endif
+
+#ifdef MPT_DEBUG_HANDSHAKE
+#define dhsprintk(x)  printk x
+#else
+#define dhsprintk(x)
+#endif
+
+#if defined(MPT_DEBUG) || defined(MPT_DEBUG_MSG_FRAME)
+#define dmfprintk(x)  printk x
+#else
+#define dmfprintk(x)
+#endif
+
+#ifdef MPT_DEBUG_IRQ
+#define dirqprintk(x)  printk x
+#else
+#define dirqprintk(x)
+#endif
+
+#ifdef MPT_DEBUG_EVENTS
+#define deventprintk(x)  printk x
+#else
+#define deventprintk(x)
+#endif
+
+#ifdef MPT_DEBUG_SPINLOCK
+#define dslprintk(x)  printk x
+#else
+#define dslprintk(x)
+#endif
+
+#ifdef MPT_DEBUG_SG
+#define dsgprintk(x)  printk x
+#else
+#define dsgprintk(x)
+#endif
+
+
+#define MPT_INDEX_2_MFPTR(ioc,idx) \
+       (MPT_FRAME_HDR*)( (u8*)(ioc)->req_frames + (ioc)->req_sz * (idx) )
+
+#define MFPTR_2_MPT_INDEX(ioc,mf) \
+       (int)( ((u8*)mf - (u8*)(ioc)->req_frames) / (ioc)->req_sz )
+
+#define Q_INIT(q,type)  (q)->head = (q)->tail = (type*)(q)
+#define Q_IS_EMPTY(q)   ((Q_ITEM*)(q)->head == (Q_ITEM*)(q))
+
+#define Q_ADD_TAIL(qt,i,type) { \
+       Q_TRACKER       *_qt = (Q_TRACKER*)(qt); \
+       Q_ITEM          *oldTail = _qt->tail; \
+       (i)->forw = (type*)_qt; \
+       (i)->back = (type*)oldTail; \
+       oldTail->forw = (Q_ITEM*)(i); \
+       _qt->tail = (Q_ITEM*)(i); \
+}
+
+#define Q_ADD_HEAD(qt,i,type) { \
+       Q_TRACKER       *_qt = (Q_TRACKER*)(qt); \
+       Q_ITEM          *oldHead = _qt->head; \
+       (i)->forw = (type*)oldHead; \
+       (i)->back = (type*)_qt; \
+       oldHead->back = (Q_ITEM*)(i); \
+       _qt->head = (Q_ITEM*)(i); \
+}
+
+#define Q_DEL_ITEM(i) { \
+       Q_ITEM  *_forw = (Q_ITEM*)(i)->forw; \
+       Q_ITEM  *_back = (Q_ITEM*)(i)->back; \
+       _back->forw = _forw; \
+       _forw->back = _back; \
+}
+
+
+#define SWAB4(value) \
+       (u32)(   (((value) & 0x000000ff) << 24) \
+              | (((value) & 0x0000ff00) << 8)  \
+              | (((value) & 0x00ff0000) >> 8)  \
+              | (((value) & 0xff000000) >> 24) )
+
+
+#if defined(MPT_DEBUG) || defined(MPT_DEBUG_MSG_FRAME)
+#define DBG_DUMP_REPLY_FRAME(mfp) \
+       {       u32 *m = (u32 *)(mfp);                                  \
+               int  i, n = (le32_to_cpu(m[0]) & 0x00FF0000) >> 16;     \
+               printk(KERN_INFO " ");                                  \
+               for (i=0; i<n; i++)                                     \
+                       printk(" %08x", le32_to_cpu(m[i]));             \
+               printk("\n");                                           \
+       }
+#define DBG_DUMP_REQUEST_FRAME_HDR(mfp) \
+       {       int  i, n = 3;                                          \
+               u32 *m = (u32 *)(mfp);                                  \
+               printk(KERN_INFO " ");                                  \
+               for (i=0; i<n; i++)                                     \
+                       printk(" %08x", le32_to_cpu(m[i]));             \
+               printk("\n");                                           \
+       }
+#else
+#define DBG_DUMP_REPLY_FRAME(mfp)
+#define DBG_DUMP_REQUEST_FRAME_HDR(mfp)
+#endif
+
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+#endif         /* } __KERNEL__ */
+
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+/*
+ *  MPT Control IOCTLs and structures
+ */
+#define MPT_MAGIC_NUMBER       'm'
+#define MPTRWPERF              _IOWR(MPT_MAGIC_NUMBER,0,struct mpt_raw_r_w)
+#define MPTRWPERF_CHK          _IOR(MPT_MAGIC_NUMBER,13,struct mpt_raw_r_w)
+#define MPTRWPERF_RESET                _IOR(MPT_MAGIC_NUMBER,14,struct mpt_raw_r_w)
+#define MPTFWDOWNLOAD          _IOWR(MPT_MAGIC_NUMBER,15,struct mpt_fw_xfer)
+#define MPTSCSICMD             _IOWR(MPT_MAGIC_NUMBER,16,struct mpt_scsi_cmd)
+
+/*
+ *  Define something *vague* enough that caller doesn't
+ *  really need to know anything about device parameters
+ *  (blk_size, capacity, etc.)
+ */
+struct mpt_raw_r_w {
+       unsigned int     iocnum;        /* IOC unit number */
+       unsigned int     port;          /* IOC port number */
+       unsigned int     target;        /* SCSI Target */
+       unsigned int     lun;           /* SCSI LUN */
+       unsigned int     iters;         /* N iterations */
+       unsigned short   nblks;         /* number of blocks per IO */
+       unsigned short   qdepth;        /* max Q depth on this device */
+       unsigned char    range;         /* 0-100% of FULL disk capacity, 0=use (nblks X iters) */
+       unsigned char    skip;          /* % of disk to skip */
+       unsigned char    rdwr;          /* 0-100%, 0=pure ReaDs, 100=pure WRites */
+       unsigned char    seqran;        /* 0-100%, 0=pure SEQential, 100=pure RANdom */
+       unsigned int     cache_sz;      /* In Kb!  Optimize hits to N Kb cache size */
+};
+
+struct mpt_fw_xfer {
+       unsigned int     iocnum;        /* IOC unit number */
+/*     u8               flags;*/       /* Message flags - bit field */
+       unsigned int     fwlen;
+       void            *bufp;          /* Pointer to firmware buffer */
+};
+
+struct mpt_scsi_cmd {
+       unsigned int     iocnum;        /* IOC unit number */
+       unsigned int     port;          /* IOC port number */
+       unsigned int     target;        /* SCSI Target */
+       unsigned int     lun;           /* SCSI LUN */
+       SCSIIORequest_t  scsi_req;
+       SCSIIOReply_t    scsi_reply;
+};
+
+struct mpt_ioctl_sanity {
+       unsigned int     iocnum;
+};
+
+#ifdef __KERNEL__      /* { */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+/*
+ *  Public entry points...
+ */
+extern int      mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass);
+extern void     mpt_deregister(int cb_idx);
+extern int      mpt_event_register(int cb_idx, MPT_EVHANDLER ev_cbfunc);
+extern void     mpt_event_deregister(int cb_idx);
+extern int      mpt_register_ascqops_strings(/*ASCQ_Table_t*/void *ascqTable, int ascqtbl_sz, const char **opsTable);
+extern void     mpt_deregister_ascqops_strings(void);
+extern MPT_FRAME_HDR   *mpt_get_msg_frame(int handle, int iocid);
+extern void     mpt_free_msg_frame(int handle, int iocid, MPT_FRAME_HDR *mf);
+extern void     mpt_put_msg_frame(int handle, int iocid, MPT_FRAME_HDR *mf);
+extern int      mpt_send_handshake_request(int handle, int iocid, int reqBytes, u32 *req);
+extern int      mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp);
+extern MPT_ADAPTER     *mpt_adapter_find_first(void);
+extern MPT_ADAPTER     *mpt_adapter_find_next(MPT_ADAPTER *prev);
+extern void     mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buf, int *size, int len);
+extern void     mpt_print_ioc_facts(MPT_ADAPTER *ioc, char *buf, int *size, int len);
+
+/*
+ *  Public data decl's...
+ */
+extern int               mpt_lan_index;        /* needed by mptlan.c */
+extern int               mpt_stm_index;        /* needed by mptstm.c */
+
+extern void             *mpt_v_ASCQ_TablePtr;
+extern const char      **mpt_ScsiOpcodesPtr;
+extern int               mpt_ASCQ_TableSz;
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+#endif         /* } __KERNEL__ */
+
+/*
+ *  More (public) macros...
+ */
+#ifndef MIN
+#define MIN(a, b)   (((a) < (b)) ? (a) : (b))
+#endif
+#ifndef MAX
+#define MAX(a, b)   (((a) > (b)) ? (a) : (b))
+#endif
+
+#ifndef offsetof
+#define offsetof(t, m) ((size_t) (&((t *)0)->m))
+#endif
+
+#if defined(__alpha__) || defined(__sparc_v9__)
+#define CAST_U32_TO_PTR(x)     ((void *)(u64)x)
+#define CAST_PTR_TO_U32(x)     ((u32)(u64)x)
+#else
+#define CAST_U32_TO_PTR(x)     ((void *)x)
+#define CAST_PTR_TO_U32(x)     ((u32)x)
+#endif
+
+#define MPT_PROTOCOL_FLAGS_c_c_c_c(pflags) \
+       ((pflags) & MPI_PORTFACTS_PROTOCOL_INITIATOR)   ? 'I' : 'i',    \
+       ((pflags) & MPI_PORTFACTS_PROTOCOL_TARGET)      ? 'T' : 't',    \
+       ((pflags) & MPI_PORTFACTS_PROTOCOL_LAN)         ? 'L' : 'l',    \
+       ((pflags) & MPI_PORTFACTS_PROTOCOL_LOGBUSADDR)  ? 'B' : 'b'
+
+/*}-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+#endif
+
diff --git a/drivers/message/fusion/mptctl.c b/drivers/message/fusion/mptctl.c
new file mode 100644 (file)
index 0000000..7bcb375
--- /dev/null
@@ -0,0 +1,1296 @@
+/*
+ *  linux/drivers/message/fusion/mptctl.c
+ *      Fusion MPT misc device (ioctl) driver.
+ *      For use with PCI chip/adapter(s):
+ *          LSIFC9xx/LSI409xx Fibre Channel
+ *      running LSI Logic Fusion MPT (Message Passing Technology) firmware.
+ *
+ *  Credits:
+ *      This driver would not exist if not for Alan Cox's development
+ *      of the linux i2o driver.
+ *
+ *      A huge debt of gratitude is owed to David S. Miller (DaveM)
+ *      for fixing much of the stupid and broken stuff in the early
+ *      driver while porting to sparc64 platform.  THANK YOU!
+ *
+ *      A big THANKS to Eddie C. Dost for fixing the ioctl path
+ *      and most importantly f/w download on sparc64 platform!
+ *      (plus Eddie's other helpful hints and insights)
+ *
+ *      Thanks to Arnaldo Carvalho de Melo for finding and patching
+ *      a potential memory leak in mpt_ioctl_do_fw_download(),
+ *      and for some kmalloc insight:-)
+ *
+ *      (see also mptbase.c)
+ *
+ *  Copyright (c) 1999-2001 LSI Logic Corporation
+ *  Originally By: Steven J. Ralston, Noah Romer
+ *  (mailto:Steve.Ralston@lsil.com)
+ *
+ *  $Id: mptctl.c,v 1.23 2001/03/21 19:42:31 sralston Exp $
+ */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; version 2 of the License.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    NO WARRANTY
+    THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+    CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+    LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+    MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+    solely responsible for determining the appropriateness of using and
+    distributing the Program and assumes all risks associated with its
+    exercise of rights under this Agreement, including but not limited to
+    the risks and costs of program errors, damage to or loss of data,
+    programs or equipment, and unavailability or interruption of operations.
+
+    DISCLAIMER OF LIABILITY
+    NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+    DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
+    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+    TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+    USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+    HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/miscdevice.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+#include <linux/proc_fs.h>
+
+#define COPYRIGHT      "Copyright (c) 1999-2001 LSI Logic Corporation"
+#define MODULEAUTHOR   "Steven J. Ralston, Noah Romer"
+#include "mptbase.h"
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+#define my_NAME                "Fusion MPT misc device (ioctl) driver"
+#define my_VERSION     MPT_LINUX_VERSION_COMMON
+#define MYNAM          "mptctl"
+
+EXPORT_NO_SYMBOLS;
+MODULE_AUTHOR(MODULEAUTHOR);
+MODULE_DESCRIPTION(my_NAME);
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+static int mptctl_id = -1;
+static int rwperf_reset = 0;
+static struct semaphore mptctl_syscall_sem_ioc[MPT_MAX_ADAPTERS];
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+static int mpt_ioctl_rwperf(unsigned long arg);
+static int mpt_ioctl_rwperf_status(unsigned long arg);
+static int mpt_ioctl_rwperf_reset(unsigned long arg);
+static int mpt_ioctl_fw_download(unsigned long arg);
+static int mpt_ioctl_do_fw_download(int ioc, char *ufwbuf, size_t fwlen);
+static int mpt_ioctl_scsi_cmd(unsigned long arg);
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * Scatter gather list (SGL) sizes and limits...
+ */
+//#define MAX_SCSI_FRAGS       9
+#define MAX_FRAGS_SPILL1       9
+#define MAX_FRAGS_SPILL2       15
+#define FRAGS_PER_BUCKET       (MAX_FRAGS_SPILL2 + 1)
+
+//#define MAX_CHAIN_FRAGS      64
+//#define MAX_CHAIN_FRAGS      (15+15+15+16)
+#define MAX_CHAIN_FRAGS                (4 * MAX_FRAGS_SPILL2 + 1)
+
+//  Define max sg LIST bytes ( == (#frags + #chains) * 8 bytes each)
+//  Works out to: 592d bytes!     (9+1)*8 + 4*(15+1)*8
+//                  ^----------------- 80 + 512
+#define MAX_SGL_BYTES          ((MAX_FRAGS_SPILL1 + 1 + (4 * FRAGS_PER_BUCKET)) * 8)
+
+/* linux only seems to ever give 128kB MAX contiguous (GFP_USER) mem bytes */
+#define MAX_KMALLOC_SZ         (128*1024)
+
+struct buflist {
+       u8      *kptr;
+       int      len;
+};
+
+#define myMAX_TARGETS  (1<<4)
+#define myMAX_LUNS     (1<<3)
+#define myMAX_T_MASK   (myMAX_TARGETS-1)
+#define myMAX_L_MASK   (myMAX_LUNS-1)
+static u8  DevInUse[myMAX_TARGETS][myMAX_LUNS] = {{0,0}};
+static u32 DevIosCount[myMAX_TARGETS][myMAX_LUNS] = {{0,0}};
+
+static u32 fwReplyBuffer[16];
+static pMPIDefaultReply_t ReplyMsg = NULL;
+
+/* some private forw protos */
+static SGESimple32_t *kbuf_alloc_2_sgl( int bytes, u32 dir, int *frags,
+               struct buflist **blp, dma_addr_t *sglbuf_dma, MPT_ADAPTER *ioc);
+static void kfree_sgl( SGESimple32_t *sgl, dma_addr_t sgl_dma,
+               struct buflist *buflist, MPT_ADAPTER *ioc);
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mptctl_syscall_down - Down the MPT adapter syscall semaphore.
+ *     @ioc: Pointer to MPT adapter
+ *     @nonblock: boolean, non-zero if O_NONBLOCK is set
+ *
+ *     All of the mptctl commands can potentially sleep, which is illegal
+ *     with a spinlock held, thus we perform mutual exclusion here.
+ *
+ *     Returns negative errno on error, or zero for success.
+ */
+static inline int
+mptctl_syscall_down(MPT_ADAPTER *ioc, int nonblock)
+{
+       dprintk((KERN_INFO MYNAM "::mpt_syscall_down(%p,%d) called\n", ioc, nonblock));
+
+       if (nonblock) {
+               if (down_trylock(&mptctl_syscall_sem_ioc[ioc->id]))
+                       return -EAGAIN;
+       } else {
+               if (down_interruptible(&mptctl_syscall_sem_ioc[ioc->id]))
+                       return -ERESTARTSYS;
+       }
+       return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *  This is the callback for any message we have posted. The message itself
+ *  will be returned to the message pool when we return from the IRQ
+ *
+ *  This runs in irq context so be short and sweet.
+ */
+static int
+mptctl_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply)
+{
+       u8 targ;
+
+       //dprintk((KERN_DEBUG MYNAM ": Got mptctl_reply()!\n"));
+
+       if (req && req->u.hdr.Function == MPI_FUNCTION_SCSI_IO_REQUEST) {
+               targ = req->u.scsireq.TargetID & myMAX_T_MASK;
+               DevIosCount[targ][0]--;
+       } else if (reply && req && req->u.hdr.Function == MPI_FUNCTION_FW_DOWNLOAD) {
+               // NOTE: Expects/requires non-Turbo reply!
+               dprintk((KERN_INFO MYNAM ": Caching MPI_FUNCTION_FW_DOWNLOAD reply!\n"));
+               memcpy(fwReplyBuffer, reply, MIN(sizeof(fwReplyBuffer), 4*reply->u.reply.MsgLength));
+               ReplyMsg = (pMPIDefaultReply_t) fwReplyBuffer;
+       }
+
+       return 1;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static loff_t
+mptctl_llseek(struct file *file, loff_t offset, int origin)
+{
+       return -ESPIPE;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static ssize_t
+mptctl_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
+{
+       printk(KERN_ERR MYNAM ": ioctl WRITE not yet supported\n");
+       return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static ssize_t
+mptctl_read(struct file *file, char *buf, size_t count, loff_t *ptr)
+{
+       return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *  MPT ioctl handler
+ */
+static int
+mpt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+       struct mpt_ioctl_sanity *usanity = (struct mpt_ioctl_sanity *) arg;
+       struct mpt_ioctl_sanity  ksanity;
+       int iocnum;
+       unsigned iocnumX;
+       int nonblock = (file->f_flags & O_NONBLOCK);
+       int ret;
+       MPT_ADAPTER *iocp = NULL;
+
+       dprintk((KERN_INFO MYNAM "::mpt_ioctl() called\n"));
+
+       if (copy_from_user(&ksanity, usanity, sizeof(ksanity))) {
+               printk(KERN_ERR "%s::mpt_ioctl() @%d - "
+                               "Unable to copy mpt_ioctl_sanity data @ %p\n",
+                               __FILE__, __LINE__, (void*)usanity);
+               return -EFAULT;
+       }
+       ret = -ENXIO;                           /* (-6) No such device or address */
+
+       /* Verify intended MPT adapter */
+       iocnumX = ksanity.iocnum & 0xFF;
+       if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) ||
+           (iocp == NULL)) {
+               printk(KERN_ERR "%s::mpt_ioctl() @%d - ioc%d not found!\n",
+                               __FILE__, __LINE__, iocnumX);
+               return -ENODEV;
+       }
+
+       if ((ret = mptctl_syscall_down(iocp, nonblock)) != 0)
+               return ret;
+
+       dprintk((KERN_INFO MYNAM "::mpt_ioctl() - Using %s\n", iocp->name));
+
+       switch(cmd) {
+       case MPTRWPERF:
+               ret = mpt_ioctl_rwperf(arg);
+               break;
+       case MPTRWPERF_CHK:
+               ret = mpt_ioctl_rwperf_status(arg);
+               break;
+       case MPTRWPERF_RESET:
+               ret = mpt_ioctl_rwperf_reset(arg);
+               break;
+       case MPTFWDOWNLOAD:
+               ret = mpt_ioctl_fw_download(arg);
+               break;
+       case MPTSCSICMD:
+               ret = mpt_ioctl_scsi_cmd(arg);
+               break;
+       default:
+               ret = -EINVAL;
+       }
+
+       up(&mptctl_syscall_sem_ioc[iocp->id]);
+
+       return ret;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int mptctl_open(struct inode *inode, struct file *file)
+{
+       /*
+        * Should support multiple management users
+        */
+       return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int mptctl_release(struct inode *inode, struct file *file)
+{
+       return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+mpt_ioctl_fw_download(unsigned long arg)
+{
+       struct mpt_fw_xfer      *ufwdl = (struct mpt_fw_xfer *) arg;
+       struct mpt_fw_xfer       kfwdl;
+
+       dprintk((KERN_INFO "mpt_ioctl_fwdl called. mptctl_id = %xh\n", mptctl_id)); //tc
+       if (copy_from_user(&kfwdl, ufwdl, sizeof(struct mpt_fw_xfer))) {
+               printk(KERN_ERR "%s@%d::_ioctl_fwdl - "
+                               "Unable to copy mpt_fw_xfer struct @ %p\n",
+                               __FILE__, __LINE__, (void*)ufwdl);
+               return -EFAULT;
+       }
+
+       return mpt_ioctl_do_fw_download(kfwdl.iocnum, kfwdl.bufp, kfwdl.fwlen);
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * MPT FW Download
+ */
+static int
+mpt_ioctl_do_fw_download(int ioc, char *ufwbuf, size_t fwlen)
+{
+       FWDownload_t            *dlmsg;
+       MPT_FRAME_HDR           *mf;
+       MPT_ADAPTER             *iocp;
+//     char                    *fwbuf;
+//     dma_addr_t               fwbuf_dma;
+       FWDownloadTCSGE_t       *fwVoodoo;
+//     SGEAllUnion_t           *fwSgl;
+       int                      ret;
+
+       SGESimple32_t   *sgl;
+       SGESimple32_t   *sgOut, *sgIn;
+       dma_addr_t       sgl_dma;
+       struct buflist  *buflist;
+       struct buflist  *bl;
+       int              numfrags = 0;
+       int              maxfrags;
+       int              n = 0;
+       u32              sgdir;
+       u32              nib;
+       int              fw_bytes_copied = 0;
+       u16              iocstat;
+       int              i;
+
+       dprintk((KERN_INFO "mpt_ioctl_do_fwdl called. mptctl_id = %xh.\n", mptctl_id));
+
+       dprintk((KERN_INFO "DbG: kfwdl.bufp  = %p\n", ufwbuf));
+       dprintk((KERN_INFO "DbG: kfwdl.fwlen = %d\n", (int)fwlen));
+       dprintk((KERN_INFO "DbG: kfwdl.ioc   = %04xh\n", ioc));
+
+       if ((ioc = mpt_verify_adapter(ioc, &iocp)) < 0) {
+               printk("%s@%d::_ioctl_fwdl - ioc%d not found!\n",
+                               __FILE__, __LINE__, ioc);
+               return -ENXIO; /* (-6) No such device or address */
+       }
+
+       if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL)
+               return -EAGAIN;
+       dlmsg = (FWDownload_t*) mf;
+       fwVoodoo = (FWDownloadTCSGE_t *) &dlmsg->SGL;
+       sgOut = (SGESimple32_t *) (fwVoodoo + 1);
+
+       /*
+        * Construct f/w download request
+        */
+       dlmsg->ImageType = MPI_FW_DOWNLOAD_ITYPE_FW;
+       dlmsg->Reserved = 0;
+       dlmsg->ChainOffset = 0;
+       dlmsg->Function = MPI_FUNCTION_FW_DOWNLOAD;
+       dlmsg->Reserved1[0] = dlmsg->Reserved1[1] = dlmsg->Reserved1[2] = 0;
+       dlmsg->MsgFlags = 0;
+
+       fwVoodoo->Reserved = 0;
+       fwVoodoo->ContextSize = 0;
+       fwVoodoo->DetailsLength = 12;
+       fwVoodoo->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
+       fwVoodoo->Reserved1 = 0;
+       fwVoodoo->ImageOffset = 0;
+       fwVoodoo->ImageSize = cpu_to_le32(fwlen);
+
+       /*
+        * Need to kmalloc area(s) for holding firmware image bytes.
+        * But we need to do it piece meal, using a proper
+        * scatter gather list (with 128kB MAX hunks).
+        * 
+        * A practical limit here might be # of sg hunks that fit into
+        * a single IOC request frame; 12 or 8 (see below), so:
+        * For FC9xx: 12 x 128kB == 1.5 mB (max)
+        * For C1030:  8 x 128kB == 1   mB (max)
+        * We could support chaining, but things get ugly(ier:)
+        */
+       sgdir = 0x04000000;             /* IOC will READ from sys mem */
+       if ((sgl = kbuf_alloc_2_sgl(fwlen, sgdir, &numfrags, &buflist, &sgl_dma, iocp)) == NULL)
+               return -ENOMEM;
+
+       /*
+        * We should only need SGL with 2 simple_32bit entries (up to 256 kB)
+        * for FC9xx f/w image, but calculate max number of sge hunks
+        * we can fit into a request frame, and limit ourselves to that.
+        * (currently no chain support)
+        * For FC9xx: (128-12-16)/8 = 12.5 = 12
+        * For C1030:  (96-12-16)/8 =  8.5 =  8
+        */
+       maxfrags = (iocp->req_sz - sizeof(MPIHeader_t) - sizeof(FWDownloadTCSGE_t)) / sizeof(SGESimple32_t);
+       if (numfrags > maxfrags) {
+               ret = -EMLINK;
+               goto fwdl_out;
+       }
+
+       dprintk((KERN_INFO "DbG: sgl buffer  = %p, sgfrags = %d\n", sgl, numfrags));
+
+       /*
+        * Parse SG list, copying sgl itself,
+        * plus f/w image hunks from user space as we go...
+        */
+       ret = -EFAULT;
+       sgIn = sgl;
+       bl = buflist;
+       for (i=0; i < numfrags; i++) {
+               nib = (sgIn->FlagsLength & 0xF0000000) >> 28;
+               /* skip ignore/chain. */
+               if (nib == 0 || nib == 3) {
+                       ;
+               } else if (sgIn->Address) {
+                       *sgOut = *sgIn;
+                       n++;
+                       if (copy_from_user(bl->kptr, ufwbuf+fw_bytes_copied, bl->len)) {
+                               printk(KERN_ERR "%s@%d::_ioctl_fwdl - "
+                                               "Unable to copy f/w buffer hunk#%d @ %p\n",
+                                               __FILE__, __LINE__, n, (void*)ufwbuf);
+                               goto fwdl_out;
+                       }
+                       fw_bytes_copied += bl->len;
+               }
+               sgIn++;
+               bl++;
+               sgOut++;
+       }
+
+#ifdef MPT_DEBUG
+       {
+               u32 *m = (u32 *)mf;
+               printk(KERN_INFO MYNAM ": F/W download request:\n" KERN_INFO " ");
+               for (i=0; i < 7+numfrags*2; i++)
+                       printk(" %08x", le32_to_cpu(m[i]));
+               printk("\n");
+       }
+#endif
+
+       /*
+        * Finally, perform firmware download.
+        */
+       ReplyMsg = NULL;
+       mpt_put_msg_frame(mptctl_id, ioc, mf);
+
+       /*
+        *  Wait until the reply has been received
+        */
+       {
+               int      foo = 0;
+
+               while (ReplyMsg == NULL) {
+                       if (!(foo%1000000)) {
+                               dprintk((KERN_INFO "DbG::_do_fwdl: "
+                                          "In ReplyMsg loop - iteration %d\n",
+                                          foo)); //tc
+                       }
+                       ret = -ETIME;
+                       if (++foo > 60000000)
+                               goto fwdl_out;
+                       mb();
+                       schedule();
+                       barrier();
+               }
+       }
+
+       if (sgl)
+               kfree_sgl(sgl, sgl_dma, buflist, iocp);
+
+       iocstat = le16_to_cpu(ReplyMsg->IOCStatus) & MPI_IOCSTATUS_MASK;
+       if (iocstat == MPI_IOCSTATUS_SUCCESS) {
+               printk(KERN_INFO MYNAM ": F/W update successfully sent to %s!\n", iocp->name);
+               return 0;
+       } else if (iocstat == MPI_IOCSTATUS_INVALID_FUNCTION) {
+               printk(KERN_WARNING MYNAM ": ?Hmmm...  %s says it doesn't support F/W download!?!\n",
+                               iocp->name);
+               printk(KERN_WARNING MYNAM ": (time to go bang on somebodies door)\n");
+               return -EBADRQC;
+       } else if (iocstat == MPI_IOCSTATUS_BUSY) {
+               printk(KERN_WARNING MYNAM ": Warning!  %s says: IOC_BUSY!\n", iocp->name);
+               printk(KERN_WARNING MYNAM ": (try again later?)\n");
+               return -EBUSY;
+       } else {
+               printk(KERN_WARNING MYNAM "::ioctl_fwdl() ERROR!  %s returned [bad] status = %04xh\n",
+                                   iocp->name, iocstat);
+               printk(KERN_WARNING MYNAM ": (bad VooDoo)\n");
+               return -ENOMSG;
+       }
+       return 0;
+
+fwdl_out:
+        kfree_sgl(sgl, sgl_dma, buflist, iocp);
+       return ret;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *  NEW rwperf (read/write performance) stuff starts here...
+ */
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static SGESimple32_t *
+kbuf_alloc_2_sgl(int bytes, u32 sgdir, int *frags,
+                struct buflist **blp, dma_addr_t *sglbuf_dma, MPT_ADAPTER *ioc)
+{
+       SGESimple32_t   *sglbuf = NULL;
+       struct buflist  *buflist = NULL;
+       int              numfrags = 0;
+       int              fragcnt = 0;
+       int              alloc_sz = MIN(bytes,MAX_KMALLOC_SZ);  // avoid kernel warning msg!
+       int              bytes_allocd = 0;
+       int              this_alloc;
+       SGESimple32_t   *sgl;
+       u32              pa;                                    // phys addr
+       SGEChain32_t    *last_chain = NULL;
+       SGEChain32_t    *old_chain = NULL;
+       int              chaincnt = 0;
+       int              i, buflist_ent;
+       int              sg_spill = MAX_FRAGS_SPILL1;
+       int              dir;
+
+       *frags = 0;
+       *blp = NULL;
+       i = MAX_SGL_BYTES / 8;
+       buflist = kmalloc(i, GFP_USER);
+       if (buflist == NULL)
+               return NULL;
+       memset(buflist, 0, i);
+       buflist_ent = 0;
+
+       sglbuf = pci_alloc_consistent(ioc->pcidev, MAX_SGL_BYTES, sglbuf_dma);
+       if (sglbuf == NULL)
+               goto free_and_fail;
+
+       if (sgdir & 0x04000000)
+               dir = PCI_DMA_TODEVICE;
+       else
+               dir = PCI_DMA_FROMDEVICE;
+
+       sgl = sglbuf;
+       while (bytes_allocd < bytes) {
+               this_alloc = MIN(alloc_sz, bytes-bytes_allocd);
+               buflist[buflist_ent].len = this_alloc;
+               buflist[buflist_ent].kptr = pci_alloc_consistent(ioc->pcidev,
+                                                                this_alloc,
+                                                                &pa);
+               if (buflist[buflist_ent].kptr == NULL) {
+                       alloc_sz = alloc_sz / 2;
+                       if (alloc_sz == 0) {
+                               printk(KERN_WARNING MYNAM "-SG: No can do - "
+                                                   "not enough memory!   :-(\n");
+                               printk(KERN_WARNING MYNAM "-SG: (freeing %d frags)\n",
+                                                   numfrags);
+                               goto free_and_fail;
+                       }
+                       continue;
+               } else {
+                       dma_addr_t dma_addr;
+
+                       bytes_allocd += this_alloc;
+
+                       /* Write one SIMPLE sge */
+                       sgl->FlagsLength = cpu_to_le32(0x10000000|sgdir|this_alloc);
+                       dma_addr = pci_map_single(ioc->pcidev, buflist[buflist_ent].kptr, this_alloc, dir);
+                       sgl->Address = cpu_to_le32(dma_addr);
+
+                       fragcnt++;
+                       numfrags++;
+                       sgl++;
+                       buflist_ent++;
+               }
+
+               if (bytes_allocd >= bytes)
+                       break;
+
+               /* Need to chain? */
+               if (fragcnt == sg_spill) {
+                       dma_addr_t chain_link;
+
+                       if (last_chain != NULL)
+                               last_chain->NextChainOffset = 0x1E;
+
+                       fragcnt = 0;
+                       sg_spill = MAX_FRAGS_SPILL2;
+
+                       /* fixup previous SIMPLE sge */
+                       sgl[-1].FlagsLength |= cpu_to_le32(0x80000000);
+
+                       chain_link = (*sglbuf_dma) +
+                               ((u8 *)(sgl+1) - (u8 *)sglbuf);
+
+                       /* Write one CHAIN sge */
+                       sgl->FlagsLength = cpu_to_le32(0x30000080);
+                       sgl->Address = cpu_to_le32(chain_link);
+
+                       old_chain = last_chain;
+                       last_chain = (SGEChain32_t*)sgl;
+                       chaincnt++;
+                       numfrags++;
+                       sgl++;
+               }
+
+               /* overflow check... */
+               if (numfrags*8 > MAX_SGL_BYTES) {
+                       /* GRRRRR... */
+                       printk(KERN_WARNING MYNAM "-SG: No can do - "
+                                           "too many SG frags!   :-(\n");
+                       printk(KERN_WARNING MYNAM "-SG: (freeing %d frags)\n",
+                                           numfrags);
+                       goto free_and_fail;
+               }
+       }
+
+       /* Last sge fixup: set LE+eol+eob bits */
+       sgl[-1].FlagsLength |= cpu_to_le32(0xC1000000);
+
+       /* Chain fixup needed? */
+       if (last_chain != NULL && fragcnt < 16)
+               last_chain->Length = cpu_to_le16(fragcnt * 8);
+
+       *frags = numfrags;
+       *blp = buflist;
+
+       dprintk((KERN_INFO MYNAM "-SG: kbuf_alloc_2_sgl() - "
+                          "%d SG frags generated!  (%d CHAIN%s)\n",
+                          numfrags, chaincnt, chaincnt>1?"s":""));
+
+       dprintk((KERN_INFO MYNAM "-SG: kbuf_alloc_2_sgl() - "
+                          "last (big) alloc_sz=%d\n",
+                          alloc_sz));
+
+       return sglbuf;
+
+free_and_fail:
+       if (sglbuf != NULL) {
+               int i;
+
+               for (i = 0; i < numfrags; i++) {
+                       dma_addr_t dma_addr;
+                       u8 *kptr;
+                       int len;
+
+                       if ((sglbuf[i].FlagsLength >> 24) == 0x30)
+                               continue;
+
+                       dma_addr = le32_to_cpu(sglbuf[i].Address);
+                       kptr = buflist[i].kptr;
+                       len = buflist[i].len;
+
+                       pci_free_consistent(ioc->pcidev, len, kptr, dma_addr);
+               }
+               pci_free_consistent(ioc->pcidev, MAX_SGL_BYTES, sglbuf, *sglbuf_dma);
+       }
+       kfree(buflist);
+       return NULL;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static void
+kfree_sgl(SGESimple32_t *sgl, dma_addr_t sgl_dma, struct buflist *buflist, MPT_ADAPTER *ioc)
+{
+       SGESimple32_t   *sg = sgl;
+       struct buflist  *bl = buflist;
+       u32              nib;
+       int              dir;
+       int              n = 0;
+
+       if (sg->FlagsLength & 0x04000000)
+               dir = PCI_DMA_TODEVICE;
+       else
+               dir = PCI_DMA_FROMDEVICE;
+
+       nib = (sg->FlagsLength & 0xF0000000) >> 28;
+       while (! (nib & 0x4)) { /* eob */
+               /* skip ignore/chain. */
+               if (nib == 0 || nib == 3) {
+                       ;
+               } else if (sg->Address) {
+                       dma_addr_t dma_addr;
+                       void *kptr;
+                       int len;
+
+                       dma_addr = le32_to_cpu(sg->Address);
+                       kptr = bl->kptr;
+                       len = bl->len;
+                       pci_unmap_single(ioc->pcidev, dma_addr, len, dir);
+                       pci_free_consistent(ioc->pcidev, len, kptr, dma_addr);
+                       n++;
+               }
+               sg++;
+               bl++;
+               nib = (sg->FlagsLength & 0xF0000000) >> 28;
+       }
+
+       /* we're at eob! */
+       if (sg->Address) {
+               dma_addr_t dma_addr;
+               void *kptr;
+               int len;
+
+               dma_addr = le32_to_cpu(sg->Address);
+               kptr = bl->kptr;
+               len = bl->len;
+               pci_unmap_single(ioc->pcidev, dma_addr, len, dir);
+               pci_free_consistent(ioc->pcidev, len, kptr, dma_addr);
+               n++;
+       }
+
+       pci_free_consistent(ioc->pcidev, MAX_SGL_BYTES, sgl, sgl_dma);
+       kfree(buflist);
+       dprintk((KERN_INFO MYNAM "-SG: Free'd 1 SGL buf + %d kbufs!\n", n));
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+mpt_ioctl_rwperf_init(struct mpt_raw_r_w *dest, unsigned long src,
+                     char *caller, MPT_ADAPTER **iocpp)
+{
+       char    *myname = "_rwperf_init()";
+       int      ioc;
+
+       /* get copy of structure passed from user space */
+       if (copy_from_user(dest, (void*)src, sizeof(*dest))) {
+               printk(KERN_ERR MYNAM "::%s() @%d - Can't copy mpt_raw_r_w data @ %p\n",
+                               myname, __LINE__, (void*)src);
+               return -EFAULT;                         /* (-14) Bad address */
+       } else {
+               dprintk((KERN_INFO MYNAM "-perf: PerfInfo.{ioc,targ,qd,iters,nblks}"
+                                  ": %d %d %d %d %d\n",
+                                  dest->iocnum, dest->target,
+                                  (int)dest->qdepth, dest->iters, dest->nblks ));
+               dprintk((KERN_INFO MYNAM "-perf: PerfInfo.{cache,skip,range,rdwr,seqran}"
+                                  ": %d %d %d %d %d\n",
+                                  dest->cache_sz, dest->skip, dest->range,
+                                  dest->rdwr, dest->seqran ));
+
+               /* Get the MPT adapter id. */
+               if ((ioc = mpt_verify_adapter(dest->iocnum, iocpp)) < 0) {
+                       printk(KERN_ERR MYNAM "::%s() @%d - ioc%d not found!\n",
+                                       myname, __LINE__, dest->iocnum);
+                       return -ENXIO;                  /* (-6) No such device or address */
+               } else {
+                       dprintk((MYNAM "-perf: %s using mpt/ioc%x, target %02xh\n",
+                                       caller, dest->iocnum, dest->target));
+               }
+       }
+
+       return ioc;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+/*  Treat first N blocks of disk as sacred!  */
+#define SACRED_BLOCKS  100
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+mpt_ioctl_rwperf(unsigned long arg)
+{
+       struct mpt_raw_r_w       kPerfInfo;
+                               /* NOTE: local copy, on stack==KERNEL_SPACE! */
+       u8               target, targetM;
+       u8               lun, lunM;
+       u8               scsiop;
+       int              qdepth;
+       int              iters;
+       int              cache_sz;
+       u32              xferbytes;
+       u32              scsidir;
+       u32              qtag;
+       u32              scsictl;
+       u32              sgdir;
+       u32              blkno;
+       u32              sbphys;
+       SGESimple32_t   *sgl;
+       dma_addr_t       sgl_dma;
+       struct buflist  *buflist;
+       SGESimple32_t   *sgOut, *sgIn;
+       int              numfrags;
+       u32             *msg;
+       int              i;
+       int              ioc;
+       MPT_FRAME_HDR   *mf;
+       MPT_ADAPTER     *iocp;
+       int              sgfragcpycnt;
+       int              blklo, blkhi;
+       u8               nextchainoffset;
+       u8              *SenseBuf;
+       dma_addr_t       SenseBufDMA;
+       char            *myname = "_rwperf()";
+
+    dprintk((KERN_INFO "%s - starting...\n", myname));
+
+    /* Validate target device */
+    if ((ioc = mpt_ioctl_rwperf_init(&kPerfInfo, arg, myname, &iocp)) < 0)
+        return ioc;
+
+    /* Allocate DMA'able memory for the sense buffer. */
+    SenseBuf = pci_alloc_consistent(iocp->pcidev, 256, &SenseBufDMA);
+
+    /* set perf parameters from input */
+    target = kPerfInfo.target & 0x0FF;
+    targetM = target & myMAX_T_MASK;
+    lun = kPerfInfo.lun & 0x1F;                        // LUN=31 max
+    lunM = lun & myMAX_L_MASK;
+    qdepth = kPerfInfo.qdepth;
+    iters = kPerfInfo.iters;
+    xferbytes = ((u32)kPerfInfo.nblks)<<9;
+
+    DevInUse[targetM][lunM] = 1;
+    DevIosCount[targetM][lunM] = 0;
+
+    cache_sz = kPerfInfo.cache_sz * 1024;      // CacheSz in kB!
+
+    /* ToDo: */
+    /* get capacity (?) */
+
+
+    // pre-build, one time, everything we can for speed in the loops below...
+
+    scsiop = 0x28;                             // default to SCSI READ!
+    scsidir = MPI_SCSIIO_CONTROL_READ;         // DATA IN  (host<--ioc<--dev)
+                                               // 02000000
+    qtag = MPI_SCSIIO_CONTROL_SIMPLEQ;         // 00000000
+
+    if (xferbytes == 0) {
+        // Do 0-byte READ!!!
+        //  IMPORTANT!  Need to set no SCSI DIR for this!
+        scsidir = MPI_SCSIIO_CONTROL_NODATATRANSFER;
+    }
+
+    scsictl = scsidir | qtag;
+
+    /*
+     *  Set sgdir for DMA transfer.
+     */
+//    sgdir   = 0x04000000;            // SCSI WRITE
+    sgdir = 0x00000000;                        // SCSI READ
+
+    if ((sgl = kbuf_alloc_2_sgl(MAX(512,xferbytes), sgdir, &numfrags, &buflist, &sgl_dma, iocp)) == NULL)
+        return -ENOMEM;
+
+    sgfragcpycnt = MIN(10,numfrags);
+    nextchainoffset = 0;
+    if (numfrags > 10)
+        nextchainoffset = 0x1E;
+
+    sbphys = SenseBufDMA;
+
+    rwperf_reset = 0;
+
+//    do {     // target-loop
+
+        blkno = SACRED_BLOCKS;         // Treat first N blocks as sacred!
+                                       // FIXME!  Skip option
+        blklo = blkno;
+        blkhi = blkno;
+
+        do {    // inner-loop
+
+            while ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL) {
+                mb();
+                schedule();
+                barrier();
+            }
+            msg = (u32*)mf;
+
+            /* Start piecing the SCSIIORequest together */
+            msg[0] = 0x00000000 | nextchainoffset<<16 | target;
+            msg[1] = 0x0000FF0A;                               // 255 sense bytes, 10-byte CDB!
+            msg[3] = lun << 8;
+            msg[4] = 0;
+            msg[5] = scsictl;
+
+            // 16 bytes of CDB @ msg[6,7,8,9] are below...
+
+            msg[6] = (   ((blkno & 0xFF000000) >> 8)
+                       | ((blkno & 0x00FF0000) << 8)
+                       | scsiop );
+            msg[7] = (   (((u32)kPerfInfo.nblks & 0x0000FF00) << 16)
+                       | ((blkno & 0x000000FF) << 8)
+                       | ((blkno & 0x0000FF00) >> 8) );
+            msg[8] = (kPerfInfo.nblks & 0x00FF);
+            msg[9] = 0;
+
+            msg[10] = xferbytes;
+
+//            msg[11] = 0xD0000100;
+//            msg[12] = sbphys;
+//            msg[13] = 0;
+            msg[11] = sbphys;
+
+            // Copy the SGL...
+            if (xferbytes) {
+                sgOut = (SGESimple32_t*)&msg[12];
+                sgIn  = sgl;
+                for (i=0; i < sgfragcpycnt; i++)
+                    *sgOut++ = *sgIn++;
+            }
+
+            // fubar!  QueueDepth issue!!!
+            while (    !rwperf_reset
+                    && (DevIosCount[targetM][lunM] >= MIN(qdepth,64)) )
+            {
+                mb();
+                schedule();
+                barrier();
+            }
+
+//            blkno += kPerfInfo.nblks;
+// EXP Stuff!
+// Try optimizing to certain cache size for the target!
+// by keeping blkno within cache range if at all possible
+#if 0
+            if (    cache_sz
+                 && ((2 * kPerfInfo.nblks) <= (cache_sz>>9))
+                 && ((blkno + kPerfInfo.nblks) > ((cache_sz>>9) + SACRED_BLOCKS)) )
+                blkno = SACRED_BLOCKS;
+            else
+                blkno += kPerfInfo.nblks;
+#endif
+// Ok, cheat!
+            if (cache_sz && ((blkno + kPerfInfo.nblks) > ((cache_sz>>9) + SACRED_BLOCKS)) )
+                   blkno = SACRED_BLOCKS;
+            else
+                blkno += kPerfInfo.nblks;
+
+            if (blkno > blkhi)
+                blkhi = blkno;
+
+            DevIosCount[targetM][lunM]++;
+
+            /*
+             *  Finally, post the request
+             */
+            mpt_put_msg_frame(mptctl_id, ioc, mf);
+
+
+            /* let linux breath! */
+            mb();
+            schedule();
+            barrier();
+
+            //dprintk((KERN_DEBUG MYNAM "-perf: inner-loop, cnt=%d\n", iters));
+
+        } while ((--iters > 0) && !rwperf_reset);
+
+        dprintk((KERN_INFO MYNAM "-perf: DbG: blklo=%d, blkhi=%d\n", blklo, blkhi));
+        dprintk((KERN_INFO MYNAM "-perf: target-loop, thisTarget=%d\n", target));
+
+//        //  TEMPORARY!
+//        target = 0;
+
+//    } while (target);
+
+
+    if (DevIosCount[targetM][lunM]) {
+        dprintk((KERN_INFO "  DbG: DevIosCount[%d][%d]=%d\n",
+                targetM, lunM, DevIosCount[targetM][lunM]));
+    }
+
+    while (DevIosCount[targetM][lunM]) {
+        //dprintk((KERN_DEBUG "  DbG: Waiting... DevIosCount[%d][%d]=%d\n",
+        //        targetM, lunM, DevIosCount[targetM][lunM]));
+        mb();
+        schedule();
+        barrier();
+    }
+    DevInUse[targetM][lunM] = 0;
+
+    pci_free_consistent(iocp->pcidev, 256, SenseBuf, SenseBufDMA);
+
+    if (sgl)
+        kfree_sgl(sgl, sgl_dma, buflist, iocp);
+
+    dprintk((KERN_INFO "  *** done ***\n"));
+
+    return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+mpt_ioctl_rwperf_status(unsigned long arg)
+{
+       struct mpt_raw_r_w       kPerfInfo;
+                               /* NOTE: local copy, on stack==KERNEL_SPACE! */
+       MPT_ADAPTER     *iocp;
+       int              ioc;
+//     u8               targ;
+//     u8               lun;
+       int              T, L;
+       char            *myname = "_rwperf_status()";
+
+
+       dprintk((KERN_INFO "%s - starting...\n", myname));
+
+       /* Get a pointer to the MPT adapter. */
+       if ((ioc = mpt_ioctl_rwperf_init(&kPerfInfo, arg, myname, &iocp)) < 0)
+               return ioc;
+
+       /* set perf parameters from input */
+//     targ = kPerfInfo.target & 0xFF;
+//     lun = kPerfInfo.lun & 0x1F;
+
+       for (T=0; T < myMAX_TARGETS; T++)
+               for (L=0; L < myMAX_LUNS; L++)
+                       if (DevIosCount[T][L]) {
+                               printk(KERN_INFO "%s: ioc%d->00:%02x:%02x"
+                                                ", IosCnt=%d\n",
+                                                myname, ioc, T, L, DevIosCount[T][L] );
+                       }
+
+       return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+mpt_ioctl_rwperf_reset(unsigned long arg)
+{
+       struct mpt_raw_r_w       kPerfInfo;
+                               /* NOTE: local copy, on stack==KERNEL_SPACE! */
+       MPT_ADAPTER     *iocp;
+       int              ioc;
+//     u8               targ;
+//     u8               lun;
+       int              T, L;
+       int              i;
+       char            *myname = "_rwperf_reset()";
+
+       dprintk((KERN_INFO "%s - starting...\n", myname));
+
+       /* Get MPT adapter id. */
+       if ((ioc = mpt_ioctl_rwperf_init(&kPerfInfo, arg, myname, &iocp)) < 0)
+               return ioc;
+
+       /* set perf parameters from input */
+//     targ = kPerfInfo.target & 0xFF;
+//     lun = kPerfInfo.lun & 0x1F;
+
+       rwperf_reset = 1;
+       for (i=0; i < 1000000; i++) {
+               mb();
+               schedule();
+               barrier();
+       }
+       rwperf_reset = 0;
+
+       for (T=0; T < myMAX_TARGETS; T++)
+               for (L=0; L < myMAX_LUNS; L++)
+                       if (DevIosCount[T][L]) {
+                               printk(KERN_INFO "%s: ioc%d->00:%02x:%02x, "
+                                                "IosCnt RESET! (from %d to 0)\n",
+                                                myname, ioc, T, L, DevIosCount[T][L] );
+                               DevIosCount[T][L] = 0;
+                               DevInUse[T][L] = 0;
+                       }
+
+       return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+mpt_ioctl_scsi_cmd(unsigned long arg)
+{
+       return -ENOSYS;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+static struct file_operations mptctl_fops = {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,51)
+       owner:          THIS_MODULE,
+#endif
+       llseek:         mptctl_llseek,
+       read:           mptctl_read,
+       write:          mptctl_write,
+       ioctl:          mpt_ioctl,
+       open:           mptctl_open,
+       release:        mptctl_release,
+};
+
+static struct miscdevice mptctl_miscdev = {
+       MPT_MINOR,
+       MYNAM,
+       &mptctl_fops
+};
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+#if defined(__sparc__) && defined(__sparc_v9__)                /*{*/
+
+/* The dynamic ioctl32 compat. registry only exists in >2.3.x sparc64 kernels */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)                /*{*/
+extern int register_ioctl32_conversion(unsigned int cmd,
+                                      int (*handler)(unsigned int,
+                                                     unsigned int,
+                                                     unsigned long,
+                                                     struct file *));
+int unregister_ioctl32_conversion(unsigned int cmd);
+
+struct mpt_fw_xfer32 {
+       unsigned int iocnum;
+       unsigned int fwlen;
+       u32 bufp;
+};
+
+#define MPTFWDOWNLOAD32     _IOWR(MPT_MAGIC_NUMBER,15,struct mpt_fw_xfer32)
+
+extern asmlinkage int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg);
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+sparc32_mptfwxfer_ioctl(unsigned int fd, unsigned int cmd,
+                       unsigned long arg, struct file *filp)
+{
+       struct mpt_fw_xfer32 kfw32;
+       struct mpt_fw_xfer kfw;
+       MPT_ADAPTER *iocp = NULL;
+       int iocnum, iocnumX;
+       int nonblock = (filp->f_flags & O_NONBLOCK);
+       int ret;
+
+       dprintk((KERN_INFO MYNAM "::sparc32_mptfwxfer_ioctl() called\n"));
+
+       if (copy_from_user(&kfw32, (char *)arg, sizeof(kfw32)))
+               return -EFAULT;
+
+       /* Verify intended MPT adapter */
+       iocnumX = kfw32.iocnum & 0xFF;
+       if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) ||
+           (iocp == NULL)) {
+               printk(KERN_ERR MYNAM "::sparc32_mptfwxfer_ioctl @%d - ioc%d not found!\n",
+                               __LINE__, iocnumX);
+               return -ENODEV;
+       }
+
+       if ((ret = mptctl_syscall_down(iocp, nonblock)) != 0)
+               return ret;
+
+       kfw.iocnum = iocnum;
+       kfw.fwlen = kfw32.fwlen;
+       kfw.bufp = (void *)(unsigned long)kfw32.bufp;
+
+       ret = mpt_ioctl_do_fw_download(kfw.iocnum, kfw.bufp, kfw.fwlen);
+
+       up(&mptctl_syscall_sem_ioc[iocp->id]);
+
+       return ret;
+}
+
+#if 0          /* { */
+static int
+sparc32_mptfwxfer_ioctl(unsigned int fd, unsigned int cmd,
+                       unsigned long arg, struct file *filp)
+{
+       struct mpt_fw_xfer32 kfw32;
+       struct mpt_fw_xfer kfw;
+       mm_segment_t old_fs;
+       int ret;
+
+       dprintk((KERN_INFO MYNAM "::sparc32_mptfwxfer_ioctl() called\n"));
+
+       if (copy_from_user(&kfw32, (char *)arg, sizeof(kfw32)))
+               return -EFAULT;
+
+       /* Verify intended MPT adapter */
+       iocnumX = kfw32.iocnum & 0xFF;
+       if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) ||
+           (iocp == NULL)) {
+               printk(KERN_ERR MYNAM "::sparc32_mptfwxfer_ioctl @%d - ioc%d not found!\n",
+                               __LINE__, iocnumX);
+               return -ENODEV;
+       }
+
+       if ((ret = mptctl_syscall_down(iocp, nonblock)) != 0)
+               return ret;
+
+       kfw.iocnum = iocnum;
+       kfw.fwlen = kfw32.fwlen;
+       kfw.bufp = (void *)(unsigned long)kfw32.bufp;
+
+       old_fs = get_fs();
+       set_fs(KERNEL_DS);
+       ret = sys_ioctl(fd, MPTFWDOWNLOAD, (unsigned long)&kfw);
+       set_fs(old_fs);
+
+       up(&mptctl_syscall_sem_ioc[iocp->id]);
+
+       return ret;
+}
+#endif         /* #if 0 } */
+
+#endif         /*} linux >= 2.3.x */
+#endif         /*} sparc */
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+int __init mptctl_init(void)
+{
+       int err;
+       int i;
+       int where = 1;
+
+       show_mptmod_ver(my_NAME, my_VERSION);
+
+       for (i=0; i<MPT_MAX_ADAPTERS; i++) {
+               sema_init(&mptctl_syscall_sem_ioc[i], 1);
+       }
+
+#if defined(__sparc__) && defined(__sparc_v9__)                /*{*/
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)                /*{*/
+       err = register_ioctl32_conversion(MPTRWPERF, NULL);
+       if (++where && err) goto out_fail;
+       err = register_ioctl32_conversion(MPTRWPERF_CHK, NULL);
+       if (++where && err) goto out_fail;
+       err = register_ioctl32_conversion(MPTRWPERF_RESET, NULL);
+       if (++where && err) goto out_fail;
+       err = register_ioctl32_conversion(MPTFWDOWNLOAD32,
+                                         sparc32_mptfwxfer_ioctl);
+       if (++where && err) goto out_fail;
+#endif         /*} linux >= 2.3.x */
+#endif         /*} sparc */
+
+       if (misc_register(&mptctl_miscdev) == -1) {
+               printk(KERN_ERR MYNAM ": Can't register misc device [minor=%d].\n", MPT_MINOR);
+               err = -EBUSY;
+               goto out_fail;
+       }
+       printk(KERN_INFO MYNAM ": Registered with Fusion MPT base driver\n");
+       printk(KERN_INFO MYNAM ": /dev/%s @ (major,minor=%d,%d)\n",
+                        mptctl_miscdev.name, MISC_MAJOR, mptctl_miscdev.minor);
+
+       /*
+        *  Install our handler
+        */
+       ++where;
+       if ((mptctl_id = mpt_register(mptctl_reply, MPTCTL_DRIVER)) < 0) {
+               printk(KERN_ERR MYNAM ": ERROR: Failed to register with Fusion MPT base driver\n");
+               misc_deregister(&mptctl_miscdev);
+               err = -EBUSY;
+               goto out_fail;
+       }
+
+       return 0;
+
+out_fail:
+
+#if defined(__sparc__) && defined(__sparc_v9__)                /*{*/
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)                /*{*/
+       printk(KERN_ERR MYNAM ": ERROR: Failed to register ioctl32_conversion!"
+                       " (%d:err=%d)\n", where, err);
+       unregister_ioctl32_conversion(MPTRWPERF);
+       unregister_ioctl32_conversion(MPTRWPERF_CHK);
+       unregister_ioctl32_conversion(MPTRWPERF_RESET);
+       unregister_ioctl32_conversion(MPTFWDOWNLOAD32);
+#endif         /*} linux >= 2.3.x */
+#endif         /*} sparc */
+
+       return err;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+void mptctl_exit(void)
+{
+       misc_deregister(&mptctl_miscdev);
+       printk(KERN_INFO MYNAM ": /dev/%s @ (major,minor=%d,%d)\n",
+                        mptctl_miscdev.name, MISC_MAJOR, mptctl_miscdev.minor);
+       printk(KERN_INFO MYNAM ": Deregistered from Fusion MPT base driver\n");
+
+       mpt_deregister(mptctl_id);
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+module_init(mptctl_init);
+module_exit(mptctl_exit);
diff --git a/drivers/message/fusion/mptlan.c b/drivers/message/fusion/mptlan.c
new file mode 100644 (file)
index 0000000..f619f2f
--- /dev/null
@@ -0,0 +1,1462 @@
+/*
+ *  linux/drivers/message/fusion/mptlan.c
+ *      IP Over Fibre Channel device driver.
+ *      For use with PCI chip/adapter(s):
+ *          LSIFC9xx/LSI409xx Fibre Channel
+ *      running LSI Logic Fusion MPT (Message Passing Technology) firmware.
+ *
+ *  Credits:
+ *      This driver would not exist if not for Alan Cox's development
+ *      of the linux i2o driver.
+ *
+ *      Special thanks goes to the I2O LAN driver people at the
+ *      University of Helsinki, who, unbeknownst to them, provided
+ *      the inspiration and initial structure for this driver.
+ *
+ *      A huge debt of gratitude is owed to David S. Miller (DaveM)
+ *      for fixing much of the stupid and broken stuff in the early
+ *      driver while porting to sparc64 platform.  THANK YOU!
+ *
+ *      A really huge debt of gratitude is owed to Eddie C. Dost
+ *      for gobs of hard work fixing and optimizing LAN code.
+ *      THANK YOU!
+ *
+ *      (see also mptbase.c)
+ *
+ *  Copyright (c) 2000-2001 LSI Logic Corporation
+ *  Originally By: Noah Romer
+ *
+ *  $Id: mptlan.c,v 1.25 2001/03/02 22:12:04 sralston Exp $
+ */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; version 2 of the License.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    NO WARRANTY
+    THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+    CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+    LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+    MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+    solely responsible for determining the appropriateness of using and
+    distributing the Program and assumes all risks associated with its
+    exercise of rights under this Agreement, including but not limited to
+    the risks and costs of program errors, damage to or loss of data,
+    programs or equipment, and unavailability or interruption of operations.
+
+    DISCLAIMER OF LIABILITY
+    NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+    DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
+    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+    TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+    USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+    HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * Define statements used for debugging
+ */
+//#define MPT_LAN_IO_DEBUG
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+#include "mptlan.h"
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+
+#define MYNAM          "mptlan"
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * MPT LAN message sizes without variable part.
+ */
+#define MPT_LAN_RECEIVE_POST_REQUEST_SIZE \
+       (sizeof(LANReceivePostRequest_t) - sizeof(SGE_MPI_UNION))
+
+#define MPT_LAN_TRANSACTION32_SIZE \
+       (sizeof(SGETransaction32_t) - sizeof(u32))
+
+/*
+ *  Fusion MPT LAN private structures
+ */
+
+struct BufferControl {
+       struct sk_buff  *skb;
+       dma_addr_t      dma;
+       unsigned int    len;
+};
+
+struct mpt_lan_priv {
+       MPT_ADAPTER *mpt_dev;
+       u8 pnum; /* Port number in the IOC. This is not a Unix network port! */
+
+       atomic_t buckets_out;           /* number of unused buckets on IOC */
+       int bucketthresh;               /* Send more when this many used */
+
+       int *mpt_txfidx; /* Free Tx Context list */
+       int mpt_txfidx_tail;
+       spinlock_t txfidx_lock;
+
+       int *mpt_rxfidx; /* Free Rx Context list */
+       int mpt_rxfidx_tail;
+       spinlock_t rxfidx_lock;
+
+       struct BufferControl *RcvCtl;   /* Receive BufferControl structs */
+       struct BufferControl *SendCtl;  /* Send BufferControl structs */
+
+       int max_buckets_out;            /* Max buckets to send to IOC */
+       int tx_max_out;                 /* IOC's Tx queue len */
+
+       u32 total_posted;
+       u32 total_received;
+       struct net_device_stats stats;  /* Per device statistics */
+
+       struct tq_struct post_buckets_task;
+       unsigned long post_buckets_active;
+};
+
+struct mpt_lan_ohdr {
+       u16     dtype;
+       u8      daddr[FC_ALEN];
+       u16     stype;
+       u8      saddr[FC_ALEN];
+};
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+/*
+ *  Forward protos...
+ */
+static int  lan_reply (MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf,
+                      MPT_FRAME_HDR *reply);
+static int  mpt_lan_open(struct net_device *dev);
+static int  mpt_lan_reset(struct net_device *dev);
+static int  mpt_lan_close(struct net_device *dev);
+static void mpt_lan_post_receive_buckets(void *dev_id);
+static void mpt_lan_wake_post_buckets_task(struct net_device *dev);
+static int  mpt_lan_receive_post_turbo(struct net_device *dev, u32 tmsg);
+static int  mpt_lan_receive_post_reply(struct net_device *dev,
+                                      LANReceivePostReply_t *pRecvRep);
+static int  mpt_lan_send_turbo(struct net_device *dev, u32 tmsg);
+static int  mpt_lan_send_reply(struct net_device *dev,
+                              LANSendReply_t *pSendRep);
+static int  mpt_lan_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply);
+static unsigned short mpt_lan_type_trans(struct sk_buff *skb,
+                                        struct net_device *dev);
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *  Fusion MPT LAN private data
+ */
+static int LanCtx = -1;
+
+static u32 max_buckets_out = 127;
+static u32 tx_max_out_p = 127 - 16;
+
+static struct net_device *mpt_landev[MPT_MAX_ADAPTERS+1];
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * Fusion MPT LAN external data
+ */
+extern int mpt_lan_index;
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     lan_reply - Handle all data sent from the hardware.
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @mf: Pointer to original MPT request frame (NULL if TurboReply)
+ *     @reply: Pointer to MPT reply frame
+ *
+ *     Returns 1 indicating original alloc'd request frame ptr
+ *     should be freed, or 0 if it shouldn't.
+ */
+static int
+lan_reply (MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply)
+{
+       struct net_device *dev = mpt_landev[ioc->id];
+       int FreeReqFrame = 0;
+
+       dioprintk((KERN_INFO MYNAM ": %s/%s: Got reply.\n",
+                 IOC_AND_NETDEV_NAMES_s_s(dev)));
+
+//     dioprintk((KERN_INFO MYNAM "@lan_reply: mf = %p, reply = %p\n",
+//                     mf, reply));
+
+       if (mf == NULL) {
+               u32 tmsg = CAST_PTR_TO_U32(reply);
+
+               dioprintk((KERN_INFO MYNAM ": %s/%s: @lan_reply, tmsg %08x\n",
+                               IOC_AND_NETDEV_NAMES_s_s(dev),
+                               tmsg));
+
+               switch (GET_LAN_FORM(tmsg)) {
+
+               // NOTE!  (Optimization) First case here is now caught in
+               //  mptbase.c::mpt_interrupt() routine and callcack here
+               //  is now skipped for this case!  20001218 -sralston
+#if 0
+               case LAN_REPLY_FORM_MESSAGE_CONTEXT:
+//                     dioprintk((KERN_INFO MYNAM "/lan_reply: "
+//                               "MessageContext turbo reply received\n"));
+                       FreeReqFrame = 1;
+                       break;
+#endif
+
+               case LAN_REPLY_FORM_SEND_SINGLE:
+//                     dioprintk((MYNAM "/lan_reply: "
+//                               "calling mpt_lan_send_reply (turbo)\n"));
+  
+                       // Potential BUG here?  -sralston
+                       //      FreeReqFrame = mpt_lan_send_turbo(dev, tmsg);
+                       //  If/when mpt_lan_send_turbo would return 1 here,
+                       //  calling routine (mptbase.c|mpt_interrupt)
+                       //  would Oops because mf has already been set
+                       //  to NULL.  So after return from this func,
+                       //  mpt_interrupt() will attempt to put (NULL) mf ptr
+                       //  item back onto it's adapter FreeQ - Oops!:-(
+                       //  It's Ok, since mpt_lan_send_turbo() *currently*
+                       //  always returns 0, but..., just in case:
+
+                       (void) mpt_lan_send_turbo(dev, tmsg);
+                       FreeReqFrame = 0;
+
+                       break;
+
+               case LAN_REPLY_FORM_RECEIVE_SINGLE:
+//                     dioprintk((KERN_INFO MYNAM "@lan_reply: "
+//                               "rcv-Turbo = %08x\n", tmsg));
+                       mpt_lan_receive_post_turbo(dev, tmsg);
+                       break;
+
+               default:
+                       printk (KERN_ERR MYNAM "/lan_reply: Got a turbo reply "
+                               "that I don't know what to do with\n");
+
+                       /* CHECKME!  Hmmm...  FreeReqFrame is 0 here; is that right? */
+
+                       break;
+               }
+
+               return FreeReqFrame;
+       }
+
+//     msg = (u32 *) reply;
+//     dioprintk((KERN_INFO MYNAM "@lan_reply: msg = %08x %08x %08x %08x\n",
+//               le32_to_cpu(msg[0]), le32_to_cpu(msg[1]),
+//               le32_to_cpu(msg[2]), le32_to_cpu(msg[3])));
+//     dioprintk((KERN_INFO MYNAM "@lan_reply: Function = %02xh\n",
+//               reply->u.hdr.Function));
+
+       switch (reply->u.hdr.Function) {
+
+       case MPI_FUNCTION_LAN_SEND:
+       {
+               LANSendReply_t *pSendRep;
+
+               pSendRep = (LANSendReply_t *) reply;
+               FreeReqFrame = mpt_lan_send_reply(dev, pSendRep);
+               break;
+       }
+
+       case MPI_FUNCTION_LAN_RECEIVE:
+       {
+               LANReceivePostReply_t *pRecvRep;
+
+               pRecvRep = (LANReceivePostReply_t *) reply;
+               if (pRecvRep->NumberOfContexts) {
+                       mpt_lan_receive_post_reply(dev, pRecvRep);
+                       if (!(pRecvRep->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY))
+                               FreeReqFrame = 1;
+               } else
+                       dioprintk((KERN_INFO MYNAM "@lan_reply: zero context "
+                                 "ReceivePostReply received.\n"));
+               break;
+       }
+
+       case MPI_FUNCTION_LAN_RESET:
+               /* Just a default reply. Might want to check it to
+                * make sure that everything went ok.
+                */
+               FreeReqFrame = 1;
+               break;
+
+       case MPI_FUNCTION_EVENT_NOTIFICATION:
+       case MPI_FUNCTION_EVENT_ACK:
+               /* UPDATE!  20010120 -sralston
+                *  _EVENT_NOTIFICATION should NOT come down this path any more.
+                *  Should be routed to mpt_lan_event_process(), but just in case...
+                */
+               FreeReqFrame = 1;
+               break;
+
+       default:
+               printk (KERN_ERR MYNAM "/lan_reply: Got a non-turbo "
+                       "reply that I don't know what to do with\n");
+
+               /* CHECKME!  Hmmm...  FreeReqFrame is 0 here; is that right? */
+               FreeReqFrame = 1;
+
+               break;
+       }
+
+       return FreeReqFrame;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+mpt_lan_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
+{
+       dprintk((KERN_INFO MYNAM ": MPT event routed to LAN driver!\n"));
+
+       switch (le32_to_cpu(pEvReply->Event)) {
+       case MPI_EVENT_NONE:                            /* 00 */
+       case MPI_EVENT_LOG_DATA:                        /* 01 */
+       case MPI_EVENT_STATE_CHANGE:                    /* 02 */
+       case MPI_EVENT_UNIT_ATTENTION:                  /* 03 */
+       case MPI_EVENT_IOC_BUS_RESET:                   /* 04 */
+       case MPI_EVENT_EXT_BUS_RESET:                   /* 05 */
+       case MPI_EVENT_RESCAN:                          /* 06 */
+               /* Ok, do we need to do anything here? As far as
+                  I can tell, this is when a new device gets added
+                  to the loop. */
+       case MPI_EVENT_LINK_STATUS_CHANGE:              /* 07 */
+       case MPI_EVENT_LOOP_STATE_CHANGE:               /* 08 */
+       case MPI_EVENT_LOGOUT:                          /* 09 */
+       case MPI_EVENT_EVENT_CHANGE:                    /* 0A */
+       default:
+               break;
+       }
+
+       /*
+        *  NOTE: pEvent->AckRequired handling now done in mptbase.c;
+        *  Do NOT do it here now!
+        */
+
+       return 1;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+mpt_lan_open(struct net_device *dev)
+{
+       struct mpt_lan_priv *priv = (struct mpt_lan_priv *) dev->priv;
+       int i;
+
+       mpt_lan_reset(dev);
+
+       priv->mpt_txfidx = kmalloc(priv->tx_max_out * sizeof(int), GFP_KERNEL);
+       if (priv->mpt_txfidx == NULL)
+               goto out;
+       priv->mpt_txfidx_tail = -1;
+
+       priv->SendCtl = kmalloc(priv->tx_max_out * sizeof(struct BufferControl),
+                               GFP_KERNEL);
+       if (priv->SendCtl == NULL)
+               goto out_mpt_txfidx;
+       for (i = 0; i < priv->tx_max_out; i++) {
+               memset(&priv->SendCtl[i], 0, sizeof(struct BufferControl));
+               priv->mpt_txfidx[++priv->mpt_txfidx_tail] = i;
+       }
+
+       dprintk((KERN_INFO MYNAM "@lo: Finished initializing SendCtl\n"));
+
+       priv->mpt_rxfidx = kmalloc(priv->max_buckets_out * sizeof(int),
+                                  GFP_KERNEL);
+       if (priv->mpt_rxfidx == NULL)
+               goto out_SendCtl;
+       priv->mpt_rxfidx_tail = -1;
+
+       priv->RcvCtl = kmalloc(priv->max_buckets_out *
+                                               sizeof(struct BufferControl),
+                              GFP_KERNEL);
+       if (priv->RcvCtl == NULL)
+               goto out_mpt_rxfidx;
+       for (i = 0; i < priv->max_buckets_out; i++) {
+               memset(&priv->RcvCtl[i], 0, sizeof(struct BufferControl));
+               priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = i;
+       }
+
+/**/   dprintk((KERN_INFO MYNAM "/lo: txfidx contains - "));
+/**/   for (i = 0; i < priv->tx_max_out; i++)
+/**/           dprintk((" %xh", priv->mpt_txfidx[i]));
+/**/   dprintk(("\n"));
+
+       dprintk((KERN_INFO MYNAM "/lo: Finished initializing RcvCtl\n"));
+
+       mpt_lan_post_receive_buckets(dev);
+       printk(KERN_INFO MYNAM ": %s/%s: interface up & active\n",
+                       IOC_AND_NETDEV_NAMES_s_s(dev));
+
+       if (mpt_event_register(LanCtx, mpt_lan_event_process) != 0) {
+               /* FIXME! */
+       }
+
+       netif_start_queue(dev);
+       dprintk((KERN_INFO MYNAM "/lo: Done.\n"));
+
+       return 0;
+out_mpt_rxfidx:
+       kfree(priv->mpt_rxfidx);
+       priv->mpt_rxfidx = NULL;
+out_SendCtl:
+       kfree(priv->SendCtl);
+       priv->SendCtl = NULL;
+out_mpt_txfidx:
+       kfree(priv->mpt_txfidx);
+       priv->mpt_txfidx = NULL;
+out:   return -ENOMEM;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+mpt_lan_reset(struct net_device *dev)
+{
+       MPT_FRAME_HDR *mf;
+       LANResetRequest_t *pResetReq;
+       struct mpt_lan_priv *priv = (struct mpt_lan_priv *)dev->priv;
+
+       mf = mpt_get_msg_frame(LanCtx, priv->mpt_dev->id);
+
+       if (mf == NULL) {
+/*             dprintk((KERN_ERR MYNAM "/reset: Evil funkiness abounds! "
+               "Unable to allocate a request frame.\n"));
+*/
+               return -1;
+       }
+
+       pResetReq = (LANResetRequest_t *) mf;
+
+       pResetReq->Function     = MPI_FUNCTION_LAN_RESET;
+       pResetReq->ChainOffset  = 0;
+       pResetReq->Reserved     = 0;
+       pResetReq->PortNumber   = priv->pnum;
+       pResetReq->MsgFlags     = 0;
+       pResetReq->Reserved2    = 0;
+
+       mpt_put_msg_frame(LanCtx, priv->mpt_dev->id, mf);
+
+       return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+mpt_lan_close(struct net_device *dev)
+{
+       struct mpt_lan_priv *priv = (struct mpt_lan_priv *) dev->priv;
+       MPT_ADAPTER *mpt_dev = priv->mpt_dev;
+       unsigned int timeout;
+       int i;
+
+       dprintk((KERN_INFO MYNAM ": mpt_lan_close called\n"));
+
+       mpt_event_deregister(LanCtx);
+
+       dprintk((KERN_INFO MYNAM ":lan_close: Posted %d buckets "
+                 "since driver was loaded, %d still out\n",
+                 priv->total_posted,atomic_read(&priv->buckets_out)));
+
+       netif_stop_queue(dev);
+
+       mpt_lan_reset(dev);
+
+       timeout = 2 * HZ;
+       while (atomic_read(&priv->buckets_out) && --timeout) {
+               current->state = TASK_INTERRUPTIBLE;
+               schedule_timeout(1);
+       }
+
+       for (i = 0; i < priv->max_buckets_out; i++) {
+               if (priv->RcvCtl[i].skb != NULL) {
+/**/                   dprintk((KERN_INFO MYNAM "/lan_close: bucket %05x "
+/**/                             "is still out\n", i));
+                       pci_unmap_single(mpt_dev->pcidev, priv->RcvCtl[i].dma,
+                                        priv->RcvCtl[i].len,
+                                        PCI_DMA_FROMDEVICE);
+                       dev_kfree_skb(priv->RcvCtl[i].skb);
+               }
+       }
+
+       kfree (priv->RcvCtl);
+       kfree (priv->mpt_rxfidx);
+
+       for (i = 0; i < priv->tx_max_out; i++) {
+               if (priv->SendCtl[i].skb != NULL) {
+                       pci_unmap_single(mpt_dev->pcidev, priv->SendCtl[i].dma,
+                                        priv->SendCtl[i].len,
+                                        PCI_DMA_TODEVICE);
+                       dev_kfree_skb(priv->SendCtl[i].skb);
+               }
+       }
+
+       kfree(priv->SendCtl);
+       kfree(priv->mpt_txfidx);
+
+       atomic_set(&priv->buckets_out, 0);
+
+       printk(KERN_INFO MYNAM ": %s/%s: interface down & inactive\n",
+                       IOC_AND_NETDEV_NAMES_s_s(dev));
+
+       return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static struct net_device_stats *
+mpt_lan_get_stats(struct net_device *dev)
+{
+       struct mpt_lan_priv *priv = (struct mpt_lan_priv *)dev->priv;
+
+       return (struct net_device_stats *) &priv->stats;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+mpt_lan_change_mtu(struct net_device *dev, int new_mtu)
+{
+       if ((new_mtu < MPT_LAN_MIN_MTU) || (new_mtu > MPT_LAN_MAX_MTU))
+               return -EINVAL;
+       dev->mtu = new_mtu;
+       return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/* Tx timeout handler. */
+static void
+mpt_lan_tx_timeout(struct net_device *dev)
+{
+       netif_wake_queue(dev);  
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+//static inline int
+static int
+mpt_lan_send_turbo(struct net_device *dev, u32 tmsg)
+{
+       struct mpt_lan_priv *priv = (struct mpt_lan_priv *) dev->priv;
+       MPT_ADAPTER *mpt_dev = priv->mpt_dev;
+       struct sk_buff *sent;
+       unsigned long flags;
+       u32 ctx;
+
+       ctx = GET_LAN_BUFFER_CONTEXT(tmsg);
+       sent = priv->SendCtl[ctx].skb;
+
+       priv->stats.tx_packets++;
+       priv->stats.tx_bytes += sent->len;
+
+       dioprintk((KERN_INFO MYNAM ": %s/%s: @%s, skb %p sent.\n",
+                       IOC_AND_NETDEV_NAMES_s_s(dev),
+                       __FUNCTION__, sent));
+
+       priv->SendCtl[ctx].skb = NULL;
+       pci_unmap_single(mpt_dev->pcidev, priv->SendCtl[ctx].dma,
+                        priv->SendCtl[ctx].len, PCI_DMA_TODEVICE);
+       dev_kfree_skb_irq(sent);
+
+       spin_lock_irqsave(&priv->txfidx_lock, flags);
+       priv->mpt_txfidx[++priv->mpt_txfidx_tail] = ctx;
+       spin_unlock_irqrestore(&priv->txfidx_lock, flags);
+
+       netif_wake_queue(dev);
+       return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+mpt_lan_send_reply(struct net_device *dev, LANSendReply_t *pSendRep)
+{
+       struct mpt_lan_priv *priv = (struct mpt_lan_priv *) dev->priv;
+       MPT_ADAPTER *mpt_dev = priv->mpt_dev;
+       struct sk_buff *sent;
+       unsigned long flags;
+       int FreeReqFrame = 0;
+       u32 *pContext;
+       u32 ctx;
+       u8 count;
+
+       count = pSendRep->NumberOfContexts;
+
+       dioprintk((KERN_INFO MYNAM ": send_reply: IOCStatus: %04x\n",
+                le16_to_cpu(pSendRep->IOCStatus)));
+
+       /* Add check for Loginfo Flag in IOCStatus */
+
+       switch (le16_to_cpu(pSendRep->IOCStatus)) {
+       case MPI_IOCSTATUS_SUCCESS:
+               priv->stats.tx_packets += count;
+               break;
+
+       case MPI_IOCSTATUS_LAN_CANCELED:
+       case MPI_IOCSTATUS_LAN_TRANSMIT_ABORTED:
+               break;
+
+       case MPI_IOCSTATUS_INVALID_SGL:
+               priv->stats.tx_errors += count;
+               printk (KERN_ERR MYNAM ": %s/%s: ERROR - Invalid SGL sent to IOC!\n",
+                               IOC_AND_NETDEV_NAMES_s_s(dev));
+               goto out;
+
+       default:
+               priv->stats.tx_errors += count;
+               break;
+       }
+
+       pContext = &pSendRep->BufferContext;
+
+       spin_lock_irqsave(&priv->txfidx_lock, flags);
+       while (count > 0) {
+               ctx = GET_LAN_BUFFER_CONTEXT(le32_to_cpu(*pContext));
+
+               sent = priv->SendCtl[ctx].skb;
+               priv->stats.tx_bytes += sent->len;
+
+               dioprintk((KERN_INFO MYNAM ": %s/%s: @%s, skb %p sent.\n",
+                               IOC_AND_NETDEV_NAMES_s_s(dev),
+                               __FUNCTION__, sent));
+
+               priv->SendCtl[ctx].skb = NULL;
+               pci_unmap_single(mpt_dev->pcidev, priv->SendCtl[ctx].dma,
+                                priv->SendCtl[ctx].len, PCI_DMA_TODEVICE);
+               dev_kfree_skb_irq(sent);
+
+               priv->mpt_txfidx[++priv->mpt_txfidx_tail] = ctx;
+
+               pContext++;
+               count--;
+       }
+       spin_unlock_irqrestore(&priv->txfidx_lock, flags);
+
+out:
+       if (!(pSendRep->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY))
+               FreeReqFrame = 1;
+
+       netif_wake_queue(dev);
+       return FreeReqFrame;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+mpt_lan_sdu_send (struct sk_buff *skb, struct net_device *dev)
+{
+       struct mpt_lan_priv *priv = (struct mpt_lan_priv *) dev->priv;
+       MPT_ADAPTER *mpt_dev = priv->mpt_dev;
+       MPT_FRAME_HDR *mf;
+       LANSendRequest_t *pSendReq;
+       SGETransaction32_t *pTrans;
+       SGESimple64_t *pSimple;
+       dma_addr_t dma;
+       unsigned long flags;
+       int ctx;
+
+       dioprintk((KERN_INFO MYNAM ": %s called, skb_addr = %p\n",
+                       __FUNCTION__, skb));
+
+       spin_lock_irqsave(&priv->txfidx_lock, flags);
+       if (priv->mpt_txfidx_tail < 0) {
+               netif_stop_queue(dev);
+               spin_unlock_irqrestore(&priv->txfidx_lock, flags);
+
+               printk (KERN_ERR "%s: no tx context available: %u\n",
+                       __FUNCTION__, priv->mpt_txfidx_tail);
+               return 1;
+       }
+
+       mf = mpt_get_msg_frame(LanCtx, mpt_dev->id);
+       if (mf == NULL) {
+               netif_stop_queue(dev);
+               dev_kfree_skb(skb);
+               spin_unlock_irqrestore(&priv->txfidx_lock, flags);
+
+               printk (KERN_ERR "%s: Unable to alloc request frame\n",
+                       __FUNCTION__);
+               return 1;
+       }
+
+       ctx = priv->mpt_txfidx[priv->mpt_txfidx_tail--];
+       spin_unlock_irqrestore(&priv->txfidx_lock, flags);
+
+//     dioprintk((KERN_INFO MYNAM ": %s/%s: Creating new msg frame (send).\n",
+//                     IOC_AND_NETDEV_NAMES_s_s(dev)));
+
+       pSendReq = (LANSendRequest_t *) mf;
+
+       /* Set the mac.raw pointer, since this apparently isn't getting
+        * done before we get the skb. Pull the data pointer past the mac data.
+        */
+       skb->mac.raw = skb->data;
+       skb_pull(skb, 12);
+
+        dma = pci_map_single(mpt_dev->pcidev, skb->data, skb->len,
+                            PCI_DMA_TODEVICE);
+
+       priv->SendCtl[ctx].skb = skb;
+       priv->SendCtl[ctx].dma = dma;
+       priv->SendCtl[ctx].len = skb->len;
+
+       /* Message Header */
+       pSendReq->Function    = MPI_FUNCTION_LAN_SEND;
+       pSendReq->ChainOffset = 0;
+       pSendReq->MsgFlags    = 0;
+       pSendReq->PortNumber  = priv->pnum;
+
+       /* Transaction Context Element */
+       pTrans = (SGETransaction32_t *) pSendReq->SG_List;
+
+       /* No Flags, 8 bytes of Details, 32bit Context (bloody turbo replies) */
+       pTrans->ContextSize   = sizeof(u32);
+       pTrans->DetailsLength = 2 * sizeof(u32);
+       pTrans->Flags         = 0;
+       pTrans->TransactionContext[0] = cpu_to_le32(ctx);
+
+//     dioprintk((KERN_INFO MYNAM ": %s/%s: BC = %08x, skb = %p, buff = %p\n",
+//                     IOC_AND_NETDEV_NAMES_s_s(dev),
+//                     ctx, skb, skb->data));
+
+       pTrans->TransactionDetails[0] = cpu_to_le32((0x1000          << 16) |
+                                                   (skb->mac.raw[0] <<  8) |
+                                                   (skb->mac.raw[1] <<  0));
+       pTrans->TransactionDetails[1] = cpu_to_le32((skb->mac.raw[2] << 24) |
+                                                   (skb->mac.raw[3] << 16) |
+                                                   (skb->mac.raw[4] <<  8) |
+                                                   (skb->mac.raw[5] <<  0));
+
+       pSimple = (SGESimple64_t *) &pTrans->TransactionDetails[2];
+
+       pSimple->FlagsLength = cpu_to_le32(
+                       ((MPI_SGE_FLAGS_END_OF_BUFFER |
+                         MPI_SGE_FLAGS_SIMPLE_ELEMENT |
+                         MPI_SGE_FLAGS_64_BIT_ADDRESSING |
+                         MPI_SGE_FLAGS_END_OF_LIST) << MPI_SGE_FLAGS_SHIFT) |
+                       skb->len);
+       pSimple->Address.Low = cpu_to_le32((u32) dma);
+       if (sizeof(dma_addr_t) > sizeof(u32))
+               pSimple->Address.High = cpu_to_le32((u32) ((u64) dma >> 32));
+       else
+               pSimple->Address.High = 0;
+
+       mpt_put_msg_frame (LanCtx, mpt_dev->id, mf);
+       dev->trans_start = jiffies;
+
+       dioprintk((KERN_INFO MYNAM ": %s/%s: Sending packet. FlagsLength = %08x.\n",
+                       IOC_AND_NETDEV_NAMES_s_s(dev),
+                       le32_to_cpu(pSimple->FlagsLength)));
+
+       return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static inline void
+mpt_lan_wake_post_buckets_task(struct net_device *dev)
+{
+       struct mpt_lan_priv *priv = dev->priv;
+
+       if (test_and_set_bit(0, &priv->post_buckets_active) == 0) {
+               queue_task(&priv->post_buckets_task, &tq_immediate);
+               mark_bh(IMMEDIATE_BH);
+               dioprintk((KERN_INFO MYNAM ": %s/%s: Queued post_buckets task.\n",
+                               IOC_AND_NETDEV_NAMES_s_s(dev) ));
+       }
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static inline int
+mpt_lan_receive_skb(struct net_device *dev, struct sk_buff *skb)
+{
+       struct mpt_lan_priv *priv = dev->priv;
+
+       skb->protocol = mpt_lan_type_trans(skb, dev);
+
+       dioprintk((KERN_INFO MYNAM ": %s/%s: Incoming packet (%d bytes) " 
+                "delivered to upper level.\n",
+                       IOC_AND_NETDEV_NAMES_s_s(dev), skb->len));
+
+       priv->stats.rx_bytes += skb->len;
+       priv->stats.rx_packets++;
+
+       skb->dev = dev;
+       netif_rx(skb);
+
+       dioprintk((MYNAM "/receive_skb: %d buckets remaining\n",
+                atomic_read(&priv->buckets_out)));
+
+       if (atomic_read(&priv->buckets_out) < priv->bucketthresh)
+               mpt_lan_wake_post_buckets_task(dev);
+
+       dioprintk((KERN_INFO MYNAM "/receive_post_reply: %d buckets "
+                 "remaining, %d received back since sod\n",
+                 atomic_read(&priv->buckets_out), priv->total_received));
+
+       return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+//static inline int
+static int
+mpt_lan_receive_post_turbo(struct net_device *dev, u32 tmsg)
+{
+       struct mpt_lan_priv *priv = dev->priv;
+       MPT_ADAPTER *mpt_dev = priv->mpt_dev;
+       struct sk_buff *skb, *old_skb;
+       unsigned long flags;
+       u32 ctx, len;
+
+       ctx = GET_LAN_BUCKET_CONTEXT(tmsg);
+       skb = priv->RcvCtl[ctx].skb;
+
+       len = GET_LAN_PACKET_LENGTH(tmsg);
+
+       if (len < MPT_LAN_RX_COPYBREAK) {
+               old_skb = skb;
+
+               skb = (struct sk_buff *)dev_alloc_skb(len);
+               if (!skb) {
+                       printk (KERN_ERR MYNAM ": %s/%s: ERROR - Can't allocate skb! (%s@%d)\n",
+                                       IOC_AND_NETDEV_NAMES_s_s(dev),
+                                       __FILE__, __LINE__);
+                       return -ENOMEM;
+               }
+
+               pci_dma_sync_single(mpt_dev->pcidev, priv->RcvCtl[ctx].dma,
+                                   priv->RcvCtl[ctx].len, PCI_DMA_FROMDEVICE);
+
+               memcpy(skb_put(skb, len), old_skb->data, len);
+
+               goto out;
+       }
+
+       skb_put(skb, len);
+
+       priv->RcvCtl[ctx].skb = NULL;
+
+       pci_unmap_single(mpt_dev->pcidev, priv->RcvCtl[ctx].dma,
+                        priv->RcvCtl[ctx].len, PCI_DMA_FROMDEVICE);
+
+out:
+       spin_lock_irqsave(&priv->rxfidx_lock, flags);
+       priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = ctx;
+       spin_unlock_irqrestore(&priv->rxfidx_lock, flags);
+
+       atomic_dec(&priv->buckets_out);
+       priv->total_received++;
+
+       return mpt_lan_receive_skb(dev, skb);
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+mpt_lan_receive_post_free(struct net_device *dev,
+                         LANReceivePostReply_t *pRecvRep)
+{
+       struct mpt_lan_priv *priv = dev->priv;
+       MPT_ADAPTER *mpt_dev = priv->mpt_dev;
+       unsigned long flags;
+       struct sk_buff *skb;
+       u32 ctx;
+       u8 count;
+       int i;
+
+       count = pRecvRep->NumberOfContexts;
+
+/**/   dprintk((KERN_INFO MYNAM "/receive_post_reply: "
+                 "IOC returned %d buckets, freeing them...\n", count));
+
+       spin_lock_irqsave(&priv->rxfidx_lock, flags);
+       for (i = 0; i < count; i++) {
+               ctx = le32_to_cpu(pRecvRep->BucketContext[i]);
+
+               skb = priv->RcvCtl[ctx].skb;
+
+//             dprintk((KERN_INFO MYNAM ": %s: dev_name = %s\n",
+//                             IOC_AND_NETDEV_NAMES_s_s(dev)));
+//             dprintk((KERN_INFO MYNAM "@rpr[2], priv = %p, buckets_out addr = %p",
+//                             priv, &(priv->buckets_out)));
+//             dprintk((KERN_INFO MYNAM "@rpr[2] TC + 3\n"));
+
+               priv->RcvCtl[ctx].skb = NULL;
+               pci_unmap_single(mpt_dev->pcidev, priv->RcvCtl[ctx].dma,
+                                priv->RcvCtl[ctx].len, PCI_DMA_FROMDEVICE);
+               dev_kfree_skb_any(skb);
+
+               priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = ctx;
+       }
+       spin_unlock_irqrestore(&priv->rxfidx_lock, flags);
+
+       atomic_sub(count, &priv->buckets_out);
+
+//     for (i = 0; i < priv->max_buckets_out; i++)
+//             if (priv->RcvCtl[i].skb != NULL)
+//                     dprintk((KERN_INFO MYNAM "@rpr: bucket %03x "
+//                               "is still out\n", i));
+
+/*     dprintk((KERN_INFO MYNAM "/receive_post_reply: freed %d buckets\n",
+                 count));
+*/
+/**/   dprintk((KERN_INFO MYNAM "@receive_post_reply: %d buckets "
+/**/             "remaining, %d received back since sod.\n",
+/**/             atomic_read(&priv->buckets_out), priv->total_received));
+       return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+mpt_lan_receive_post_reply(struct net_device *dev,
+                          LANReceivePostReply_t *pRecvRep)
+{
+       struct mpt_lan_priv *priv = dev->priv;
+       MPT_ADAPTER *mpt_dev = priv->mpt_dev;
+       struct sk_buff *skb, *old_skb;
+       unsigned long flags;
+       u32 len, ctx;
+       u32 offset;
+       u8 count;
+       int i, l;
+
+       dioprintk((KERN_INFO MYNAM ": mpt_lan_receive_post_reply called\n"));
+       dioprintk((KERN_INFO MYNAM ": receive_post_reply: IOCStatus: %04x\n",
+                le16_to_cpu(pRecvRep->IOCStatus)));
+
+       if (le16_to_cpu(pRecvRep->IOCStatus) & MPI_IOCSTATUS_LAN_CANCELED)
+               return mpt_lan_receive_post_free(dev, pRecvRep);
+
+       len = le32_to_cpu(pRecvRep->PacketLength);
+       if (len == 0) {
+               printk (KERN_ERR MYNAM ": %s/%s: ERROR - Got a non-TURBO "
+                       "ReceivePostReply w/ PacketLength zero!\n",
+                               IOC_AND_NETDEV_NAMES_s_s(dev));
+               printk (KERN_ERR MYNAM ": MsgFlags = %02x, IOCStatus = %04x\n",
+                               pRecvRep->MsgFlags, le16_to_cpu(pRecvRep->IOCStatus));
+               return -1;
+       }
+
+       ctx    = le32_to_cpu(pRecvRep->BucketContext[0]);
+       count  = pRecvRep->NumberOfContexts;
+       skb    = priv->RcvCtl[ctx].skb;
+
+       offset = le32_to_cpu(pRecvRep->PacketOffset);
+//     if (offset != 0) {
+//             printk (KERN_INFO MYNAM ": %s/%s: Got a ReceivePostReply "
+//                     "w/ PacketOffset %u\n",
+//                             IOC_AND_NETDEV_NAMES_s_s(dev),
+//                             offset);
+//     }
+
+       dioprintk((KERN_INFO MYNAM ": %s/%s: @rpr, offset = %d, len = %d\n",
+                       IOC_AND_NETDEV_NAMES_s_s(dev),
+                       offset, len));
+
+       if (count > 1) {
+               int szrem = len;
+
+//             dioprintk((KERN_INFO MYNAM ": %s/%s: Multiple buckets returned "
+//                     "for single packet, concatenating...\n",
+//                             IOC_AND_NETDEV_NAMES_s_s(dev)));
+
+               skb = (struct sk_buff *)dev_alloc_skb(len);
+               if (!skb) {
+                       printk (KERN_ERR MYNAM ": %s/%s: ERROR - Can't allocate skb! (%s@%d)\n",
+                                       IOC_AND_NETDEV_NAMES_s_s(dev),
+                                       __FILE__, __LINE__);
+                       return -ENOMEM;
+               }
+
+               spin_lock_irqsave(&priv->rxfidx_lock, flags);
+               for (i = 0; i < count; i++) {
+
+                       ctx = le32_to_cpu(pRecvRep->BucketContext[i]);
+                       old_skb = priv->RcvCtl[ctx].skb;
+
+                       l = priv->RcvCtl[ctx].len;
+                       if (szrem < l)
+                               l = szrem;
+
+//                     dioprintk((KERN_INFO MYNAM ": %s/%s: Buckets = %d, len = %u\n",
+//                                     IOC_AND_NETDEV_NAMES_s_s(dev),
+//                                     i, l));
+
+                       pci_dma_sync_single(mpt_dev->pcidev,
+                                           priv->RcvCtl[ctx].dma,
+                                           priv->RcvCtl[ctx].len,
+                                           PCI_DMA_FROMDEVICE);
+                       memcpy(skb_put(skb, l), old_skb->data, l);
+
+                       priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = ctx;
+                       szrem -= l;
+               }
+               spin_unlock_irqrestore(&priv->rxfidx_lock, flags);
+
+       } else if (len < MPT_LAN_RX_COPYBREAK) {
+
+               old_skb = skb;
+
+               skb = (struct sk_buff *)dev_alloc_skb(len);
+               if (!skb) {
+                       printk (KERN_ERR MYNAM ": %s/%s: ERROR - Can't allocate skb! (%s@%d)\n",
+                                       IOC_AND_NETDEV_NAMES_s_s(dev),
+                                       __FILE__, __LINE__);
+                       return -ENOMEM;
+               }
+
+               pci_dma_sync_single(mpt_dev->pcidev, priv->RcvCtl[ctx].dma,
+                                   priv->RcvCtl[ctx].len, PCI_DMA_FROMDEVICE);
+
+               memcpy(skb_put(skb, len), old_skb->data, len);
+
+               spin_lock_irqsave(&priv->rxfidx_lock, flags);
+               priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = ctx;
+               spin_unlock_irqrestore(&priv->rxfidx_lock, flags);
+
+       } else {
+               spin_lock_irqsave(&priv->rxfidx_lock, flags);
+
+               priv->RcvCtl[ctx].skb = NULL;
+
+               pci_unmap_single(mpt_dev->pcidev, priv->RcvCtl[ctx].dma,
+                                priv->RcvCtl[ctx].len, PCI_DMA_FROMDEVICE);
+               priv->RcvCtl[ctx].dma = 0;
+
+               priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = ctx;
+               spin_unlock_irqrestore(&priv->rxfidx_lock, flags);
+
+               skb_put(skb,len);
+       }
+
+       atomic_sub(count, &priv->buckets_out);
+       priv->total_received += count;
+
+       if (priv->mpt_rxfidx_tail >= MPT_LAN_MAX_BUCKETS_OUT) {
+               printk (KERN_ERR MYNAM ": %s/%s: Yoohoo! mpt_rxfidx_tail = %d, "
+                       "MPT_LAN_MAX_BUCKETS_OUT = %d\n",
+                               IOC_AND_NETDEV_NAMES_s_s(dev),
+                               priv->mpt_rxfidx_tail,
+                               MPT_LAN_MAX_BUCKETS_OUT);
+
+               panic("Damn it Jim! I'm a doctor, not a programmer! "
+                               "Oh, wait a sec, I am a programmer. "
+                               "And, who's Jim?!?!\n"
+                               "Arrgghh! We've done it again!\n");
+       }
+
+#if 0
+       {
+               u32 remaining = le32_to_cpu(pRecvRep->BucketsRemaining);
+               if (remaining < priv->bucketthresh)
+                       mpt_lan_wake_post_buckets_task(dev);
+
+               if (remaining == 0)
+                       printk (KERN_WARNING MYNAM ": %s/%s: WARNING - IOC out of buckets! "
+                               "(priv->buckets_out = %d)\n",
+                                       IOC_AND_NETDEV_NAMES_s_s(dev),
+                                       atomic_read(&priv->buckets_out));
+               else
+                       printk (KERN_INFO MYNAM ": %s/%s: IOC says %d buckets left. "
+                               "(priv->buckets_out = %d)\n",
+                                       IOC_AND_NETDEV_NAMES_s_s(dev),
+                                       remaining, atomic_read(&priv->buckets_out));
+       }
+#endif
+
+       return mpt_lan_receive_skb(dev, skb);
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/* Simple SGE's only at the moment */
+
+static void
+mpt_lan_post_receive_buckets(void *dev_id)
+{
+       struct net_device *dev = dev_id;
+       struct mpt_lan_priv *priv = dev->priv;
+       MPT_ADAPTER *mpt_dev = priv->mpt_dev;
+       MPT_FRAME_HDR *mf;
+       LANReceivePostRequest_t *pRecvReq;
+       SGETransaction32_t *pTrans;
+       SGESimple64_t *pSimple;
+       struct sk_buff *skb;
+       dma_addr_t dma;
+       u32 curr, buckets, count, max;
+       u32 len = (dev->mtu + dev->hard_header_len + 4);
+       unsigned long flags;
+       int i;
+
+       curr = atomic_read(&priv->buckets_out);
+       buckets = (priv->max_buckets_out - curr);
+
+       dioprintk((KERN_INFO MYNAM ": %s/%s: @%s, Start_buckets = %u, buckets_out = %u\n",
+                       IOC_AND_NETDEV_NAMES_s_s(dev),
+                       __FUNCTION__, buckets, curr));
+
+       max = (mpt_dev->req_sz - MPT_LAN_RECEIVE_POST_REQUEST_SIZE) /
+                       (MPT_LAN_TRANSACTION32_SIZE + sizeof(SGESimple64_t));
+
+       while (buckets) {
+               mf = mpt_get_msg_frame(LanCtx, mpt_dev->id);
+               if (mf == NULL) {
+                       printk (KERN_ERR "%s: Unable to alloc request frame\n",
+                               __FUNCTION__);
+                       dioprintk((KERN_ERR "%s: %u buckets remaining\n",
+                                __FUNCTION__, buckets));
+                       goto out;
+               }
+               pRecvReq = (LANReceivePostRequest_t *) mf;
+
+               count = buckets;
+               if (count > max)
+                       count = max;
+
+               pRecvReq->Function    = MPI_FUNCTION_LAN_RECEIVE;
+               pRecvReq->ChainOffset = 0;
+               pRecvReq->MsgFlags    = 0;
+               pRecvReq->PortNumber  = priv->pnum;
+
+               pTrans = (SGETransaction32_t *) pRecvReq->SG_List;
+               pSimple = NULL;
+
+               for (i = 0; i < count; i++) {
+                       int ctx;
+
+                       spin_lock_irqsave(&priv->rxfidx_lock, flags);
+                       if (priv->mpt_rxfidx_tail < 0) {
+                               printk (KERN_ERR "%s: Can't alloc context\n",
+                                       __FUNCTION__);
+                               spin_unlock_irqrestore(&priv->rxfidx_lock,
+                                                      flags);
+                               break;
+                       }
+
+                       ctx = priv->mpt_rxfidx[priv->mpt_rxfidx_tail--];
+
+                       skb = priv->RcvCtl[ctx].skb;
+                       if (skb && (priv->RcvCtl[ctx].len != len)) {
+                               pci_unmap_single(mpt_dev->pcidev,
+                                                priv->RcvCtl[ctx].dma,
+                                                priv->RcvCtl[ctx].len,
+                                                PCI_DMA_FROMDEVICE);
+                               dev_kfree_skb(priv->RcvCtl[ctx].skb);
+                               skb = priv->RcvCtl[ctx].skb = NULL;
+                       }
+
+                       if (skb == NULL) {
+                               skb = dev_alloc_skb(len);
+                               if (skb == NULL) {
+/**/                                   printk (KERN_WARNING
+/**/                                           MYNAM "/%s: Can't alloc skb\n",
+/**/                                           __FUNCTION__);
+                                       priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = ctx;
+                                       spin_unlock_irqrestore(&priv->rxfidx_lock, flags);
+                                       break;
+                               }
+
+                               dma = pci_map_single(mpt_dev->pcidev, skb->data,
+                                                    len, PCI_DMA_FROMDEVICE);
+
+                               priv->RcvCtl[ctx].skb = skb;
+                               priv->RcvCtl[ctx].dma = dma;
+                               priv->RcvCtl[ctx].len = len;
+                       }
+
+                       spin_unlock_irqrestore(&priv->rxfidx_lock, flags);
+
+                       pTrans->ContextSize   = sizeof(u32);
+                       pTrans->DetailsLength = 0;
+                       pTrans->Flags         = 0;
+                       pTrans->TransactionContext[0] = cpu_to_le32(ctx);
+
+                       pSimple = (SGESimple64_t *) pTrans->TransactionDetails;
+
+                       pSimple->FlagsLength = cpu_to_le32(
+                               ((MPI_SGE_FLAGS_END_OF_BUFFER |
+                                 MPI_SGE_FLAGS_SIMPLE_ELEMENT |
+                                 MPI_SGE_FLAGS_64_BIT_ADDRESSING) << MPI_SGE_FLAGS_SHIFT) | len);
+                       pSimple->Address.Low = cpu_to_le32((u32) priv->RcvCtl[ctx].dma);
+                       if (sizeof(dma_addr_t) > sizeof(u32))
+                               pSimple->Address.High = cpu_to_le32((u32) ((u64) priv->RcvCtl[ctx].dma >> 32));
+                       else
+                               pSimple->Address.High = 0;
+
+                       pTrans = (SGETransaction32_t *) (pSimple + 1);
+               }
+
+               if (pSimple == NULL) {
+/**/                   printk (KERN_WARNING MYNAM "/%s: No buckets posted\n",
+/**/                           __FUNCTION__);
+                       mpt_free_msg_frame(LanCtx, mpt_dev->id, mf);
+                       goto out;
+               }
+
+               pSimple->FlagsLength |= cpu_to_le32(MPI_SGE_FLAGS_END_OF_LIST << MPI_SGE_FLAGS_SHIFT);
+
+               pRecvReq->BucketCount = cpu_to_le32(i);
+
+/*     printk(KERN_INFO MYNAM ": posting buckets\n   ");
+ *     for (i = 0; i < j + 2; i ++)
+ *         printk (" %08x", le32_to_cpu(msg[i]));
+ *     printk ("\n");
+ */
+
+               mpt_put_msg_frame(LanCtx, mpt_dev->id, mf);
+
+               priv->total_posted += i;
+               buckets -= i;
+               atomic_add(i, &priv->buckets_out);
+       }
+
+out:
+       dioprintk((KERN_INFO MYNAM "/%s: End_buckets = %u, priv->buckets_out = %u\n",
+                 __FUNCTION__, buckets, atomic_read(&priv->buckets_out)));
+       dioprintk((KERN_INFO MYNAM "/%s: Posted %u buckets and received %u back\n",
+       __FUNCTION__, priv->total_posted, priv->total_received)); 
+
+       clear_bit(0, &priv->post_buckets_active);
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+struct net_device *
+mpt_register_lan_device (MPT_ADAPTER *mpt_dev, int pnum)
+{
+       struct net_device *dev = NULL;
+       struct mpt_lan_priv *priv = NULL;
+       u8 HWaddr[FC_ALEN], *a;
+
+       dev = init_fcdev(NULL, sizeof(struct mpt_lan_priv));
+       if (!dev)
+               return (NULL);
+       dev->mtu = MPT_LAN_MTU;
+
+       priv = (struct mpt_lan_priv *) dev->priv;
+
+       priv->mpt_dev = mpt_dev;
+       priv->pnum = pnum;
+
+       memset(&priv->post_buckets_task, 0, sizeof(struct tq_struct));
+       priv->post_buckets_task.routine = mpt_lan_post_receive_buckets;
+       priv->post_buckets_task.data = dev;
+       priv->post_buckets_active = 0;
+
+       dprintk((KERN_INFO MYNAM "@%d: bucketlen = %d\n",
+                       __LINE__, dev->mtu + dev->hard_header_len + 4));
+
+       atomic_set(&priv->buckets_out, 0);
+       priv->total_posted = 0;
+       priv->total_received = 0;
+       priv->max_buckets_out = max_buckets_out;
+       if (mpt_dev->pfacts0.MaxLanBuckets < max_buckets_out)
+               priv->max_buckets_out = mpt_dev->pfacts0.MaxLanBuckets;
+
+       dprintk((KERN_INFO MYNAM "@%d: MaxLanBuckets=%d, max_buckets_out/priv=%d/%d\n",
+                       __LINE__,
+                       mpt_dev->pfacts0.MaxLanBuckets,
+                       max_buckets_out,
+                       priv->max_buckets_out));
+
+       priv->bucketthresh = priv->max_buckets_out * 2 / 3;
+       priv->txfidx_lock = SPIN_LOCK_UNLOCKED;
+       priv->rxfidx_lock = SPIN_LOCK_UNLOCKED;
+
+       memset(&priv->stats, 0, sizeof(priv->stats));
+
+       /*  Grab pre-fetched LANPage1 stuff. :-) */
+       a = (u8 *) &mpt_dev->lan_cnfg_page1.HardwareAddressLow;
+
+       HWaddr[0] = a[5];
+       HWaddr[1] = a[4];
+       HWaddr[2] = a[3];
+       HWaddr[3] = a[2];
+       HWaddr[4] = a[1];
+       HWaddr[5] = a[0];
+
+       dev->addr_len = FC_ALEN;
+       memcpy(dev->dev_addr, HWaddr, FC_ALEN);
+       memset(dev->broadcast, 0xff, FC_ALEN);
+
+       /* The Tx queue is 127 deep on the 909.
+        * Give ourselves some breathing room.
+        */
+       priv->tx_max_out = (tx_max_out_p <= MPT_TX_MAX_OUT_LIM) ?
+                           tx_max_out_p : MPT_TX_MAX_OUT_LIM;
+
+       dev->open = mpt_lan_open;
+       dev->stop = mpt_lan_close;
+       dev->get_stats = mpt_lan_get_stats;
+       dev->set_multicast_list = NULL;
+       dev->change_mtu = mpt_lan_change_mtu;
+       dev->hard_start_xmit = mpt_lan_sdu_send;
+
+/* Not in 2.3.42. Need 2.3.45+ */
+       dev->tx_timeout = mpt_lan_tx_timeout;
+       dev->watchdog_timeo = MPT_LAN_TX_TIMEOUT;
+
+       dprintk((KERN_INFO MYNAM ": Finished registering dev "
+               "and setting initial values\n"));
+
+       SET_MODULE_OWNER(dev);
+
+       return dev;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+int __init
+mpt_lan_init (void)
+{
+       struct net_device *dev;
+       MPT_ADAPTER *curadapter;
+       int i = 0, j;
+
+       show_mptmod_ver(LANAME, LANVER);
+
+       if ((LanCtx = mpt_register(lan_reply, MPTLAN_DRIVER)) < 0) {
+               printk (KERN_ERR MYNAM ": Failed to register with MPT base driver\n");
+               return -EBUSY;
+       }
+
+       /* Set the callback index to be used by driver core for turbo replies */
+       mpt_lan_index = LanCtx;
+
+       dprintk((KERN_INFO MYNAM ": assigned context of %d\n", LanCtx));
+
+       for (j = 0; j < MPT_MAX_ADAPTERS; j++) {
+               mpt_landev[j] = NULL;
+       }
+       j = 0;
+
+       curadapter = mpt_adapter_find_first();
+       while (curadapter != NULL) {
+               for (i = 0; i < curadapter->facts0.NumberOfPorts; i++) {
+                       printk (KERN_INFO MYNAM ": %s: PortNum=%x, ProtocolFlags=%02Xh (%c%c%c%c)\n",
+                                       curadapter->name,
+                                       curadapter->pfacts0.PortNumber,
+                                       curadapter->pfacts0.ProtocolFlags,
+                                       MPT_PROTOCOL_FLAGS_c_c_c_c(curadapter->pfacts0.ProtocolFlags));
+
+                       if (curadapter->pfacts0.ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
+                               dev = mpt_register_lan_device (curadapter, i);
+                               if (dev != NULL) {
+                                       printk (KERN_INFO MYNAM ": %s: Fusion MPT LAN device registered as '%s'\n",
+                                                       curadapter->name, dev->name);
+                                       printk (KERN_INFO MYNAM ": %s/%s: LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
+                                                       IOC_AND_NETDEV_NAMES_s_s(dev),
+                                                       dev->dev_addr[0], dev->dev_addr[1],
+                                                       dev->dev_addr[2], dev->dev_addr[3],
+                                                       dev->dev_addr[4], dev->dev_addr[5]);
+//                                     printk (KERN_INFO MYNAM ": %s/%s: Max_TX_outstanding = %d\n",
+//                                                     IOC_AND_NETDEV_NAMES_s_s(dev),
+//                                                     NETDEV_TO_LANPRIV_PTR(dev)->tx_max_out);
+                                       mpt_landev[j] = dev;
+                                       dprintk((KERN_INFO MYNAM "/init: dev_addr=%p, mpt_landev[%d]=%p\n",
+                                                       dev, j,  mpt_landev[j]));
+
+                                       j++;
+                               } else {
+                                       printk (KERN_ERR MYNAM ": %s: Unable to register port%d as a LAN device\n",
+                                                       curadapter->name,
+                                                       curadapter->pfacts0.PortNumber);
+                               }
+                       } else {
+                               printk (KERN_INFO MYNAM ": %s: Hmmm... LAN protocol seems to be disabled on this adapter port!\n",
+                                               curadapter->name);
+                       }
+               }
+               curadapter = mpt_adapter_find_next(curadapter);
+       }
+
+       return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+void __init mpt_lan_exit(void)
+{
+       int i;
+
+       for (i = 0; mpt_landev[i] != NULL; i++) {
+               struct net_device *dev = mpt_landev[i];
+
+               printk (KERN_INFO MYNAM ": %s/%s: Fusion MPT LAN device unregistered\n",
+                              IOC_AND_NETDEV_NAMES_s_s(dev));
+               unregister_fcdev(dev);
+               mpt_landev[i] = (struct net_device *) 0xdeadbeef; /* Debug */
+       }
+
+       if (LanCtx >= 0) {
+               mpt_deregister(LanCtx);
+               LanCtx = -1;
+               mpt_lan_index = 0;
+       }
+
+       /* deregister any send/receive handler structs. I2Oism? */
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+MODULE_PARM(tx_max_out_p, "i");
+MODULE_PARM(max_buckets_out, "i"); // Debug stuff. FIXME!
+
+module_init(mpt_lan_init);
+module_exit(mpt_lan_exit);
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static unsigned short
+mpt_lan_type_trans(struct sk_buff *skb, struct net_device *dev) 
+{
+       struct mpt_lan_ohdr *fch = (struct mpt_lan_ohdr *)skb->data;
+       struct fcllc *fcllc;
+
+       skb->mac.raw = skb->data;
+       skb_pull(skb, sizeof(struct mpt_lan_ohdr));
+
+       if (fch->dtype == htons(0xffff)) {
+               u32 *p = (u32 *) fch;
+
+               swab32s(p + 0);
+               swab32s(p + 1);
+               swab32s(p + 2);
+               swab32s(p + 3);
+
+               printk (KERN_WARNING MYNAM ": %s: WARNING - Broadcast swap F/W bug detected!\n",
+                               NETDEV_PTR_TO_IOC_NAME_s(dev));
+               printk (KERN_WARNING MYNAM ": Please update sender @ MAC_addr = %02x:%02x:%02x:%02x:%02x:%02x\n",
+                               fch->saddr[0], fch->saddr[1], fch->saddr[2],
+                               fch->saddr[3], fch->saddr[4], fch->saddr[5]);
+       }
+
+       if (*fch->daddr & 1) {
+               if (!memcmp(fch->daddr, dev->broadcast, FC_ALEN)) {
+                       skb->pkt_type = PACKET_BROADCAST;
+               } else {
+                       skb->pkt_type = PACKET_MULTICAST;
+               }
+       } else {
+               if (memcmp(fch->daddr, dev->dev_addr, FC_ALEN)) {
+                       skb->pkt_type = PACKET_OTHERHOST;
+               } else {
+                       skb->pkt_type = PACKET_HOST;
+               }
+       }
+
+       /* Strip the SNAP header from ARP packets since we don't 
+        * pass them through to the 802.2/SNAP layers.
+        */
+       fcllc = (struct fcllc *)skb->data;
+
+       if (fcllc->dsap == EXTENDED_SAP &&
+               (fcllc->ethertype == htons(ETH_P_IP) ||
+                fcllc->ethertype == htons(ETH_P_ARP))) {
+               skb_pull(skb, sizeof(struct fcllc));
+               return fcllc->ethertype;
+       }
+
+       return htons(ETH_P_802_2);
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
diff --git a/drivers/message/fusion/mptlan.h b/drivers/message/fusion/mptlan.h
new file mode 100644 (file)
index 0000000..c32cfa0
--- /dev/null
@@ -0,0 +1,72 @@
+/* mptlan.h */
+
+#ifndef LINUX_MPTLAN_H_INCLUDED
+#define LINUX_MPTLAN_H_INCLUDED
+/*****************************************************************************/
+
+#if !defined(__GENKSYMS__)
+#include <linux/module.h>
+#endif
+
+#include <linux/netdevice.h>
+#include <linux/errno.h>
+// #include <linux/etherdevice.h>
+#include <linux/fcdevice.h>
+// #include <linux/fddidevice.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/miscdevice.h>
+#include <linux/spinlock.h>
+#include <linux/tqueue.h>
+// #include <linux/trdevice.h>
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+    /* Override mptbase.h by pre-defining these! */
+    #define MODULEAUTHOR "Noah Romer, Eddie C. Dost"
+
+#include "mptbase.h"
+
+/*****************************************************************************/
+#define LANAME         "Fusion MPT LAN driver"
+#define LANVER         MPT_LINUX_VERSION_COMMON
+
+#ifdef MODULE
+MODULE_AUTHOR(MODULEAUTHOR);
+MODULE_DESCRIPTION(LANAME);
+#endif
+/*****************************************************************************/
+
+#define MPT_LAN_MAX_BUCKETS_OUT 256
+#define MPT_LAN_BUCKET_THRESH  18 /* 9 buckets in one message */
+#define MPT_LAN_RX_COPYBREAK   200
+#define MPT_LAN_TX_TIMEOUT     (1*HZ)
+#define MPT_TX_MAX_OUT_LIM      127
+
+#define MPT_LAN_MIN_MTU                96              /* RFC2625 */
+#define MPT_LAN_MAX_MTU                65280           /* RFC2625 */
+#define MPT_LAN_MTU             16128          /* be nice to slab allocator */
+
+/* MPT LAN Reset and Suspend Resource Flags Defines */
+
+#define MPT_LAN_RESOURCE_FLAG_RETURN_POSTED_BUCKETS    0x01
+#define MPT_LAN_RESOURCE_FLAG_RETURN_PEND_TRANSMITS    0x02
+
+/*****************************************************************************/
+#ifdef MPT_LAN_IO_DEBUG
+#define dioprintk(x)  printk x
+#else
+#define dioprintk(x)
+#endif
+
+#define NETDEV_TO_LANPRIV_PTR(d)       ((struct mpt_lan_priv *)(d)->priv)
+#define NETDEV_PTR_TO_IOC_NAME_s(d)    (NETDEV_TO_LANPRIV_PTR(d)->mpt_dev->name)
+#define IOC_AND_NETDEV_NAMES_s_s(d)    NETDEV_PTR_TO_IOC_NAME_s(d), (d)->name
+
+/*****************************************************************************/
+#endif
+
diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c
new file mode 100644 (file)
index 0000000..d1a21e1
--- /dev/null
@@ -0,0 +1,2508 @@
+/*
+ *  linux/drivers/message/fusion/mptscsih.c
+ *      High performance SCSI / Fibre Channel SCSI Host device driver.
+ *      For use with PCI chip/adapter(s):
+ *          LSIFC9xx/LSI409xx Fibre Channel
+ *      running LSI Logic Fusion MPT (Message Passing Technology) firmware.
+ *
+ *  Credits:
+ *      This driver would not exist if not for Alan Cox's development
+ *      of the linux i2o driver.
+ *
+ *      A huge debt of gratitude is owed to David S. Miller (DaveM)
+ *      for fixing much of the stupid and broken stuff in the early
+ *      driver while porting to sparc64 platform.  THANK YOU!
+ *
+ *      (see mptbase.c)
+ *
+ *  Copyright (c) 1999-2001 LSI Logic Corporation
+ *  Original author: Steven J. Ralston
+ *  (mailto:Steve.Ralston@lsil.com)
+ *
+ *  $Id: mptscsih.c,v 1.24 2001/03/22 08:45:08 sralston Exp $
+ */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; version 2 of the License.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    NO WARRANTY
+    THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+    CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+    LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+    MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+    solely responsible for determining the appropriateness of using and
+    distributing the Program and assumes all risks associated with its
+    exercise of rights under this Agreement, including but not limited to
+    the risks and costs of program errors, damage to or loss of data,
+    programs or equipment, and unavailability or interruption of operations.
+
+    DISCLAIMER OF LIABILITY
+    NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+    DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
+    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+    TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+    USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+    HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/kdev_t.h>
+#include <linux/blkdev.h>
+#include <linux/blk.h>         /* for io_request_lock (spinlock) decl */
+#include "../../scsi/scsi.h"
+#include "../../scsi/hosts.h"
+#include "../../scsi/sd.h"
+
+#include "mptbase.h"
+#include "mptscsih.h"
+#include "isense.h"
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+#define my_NAME                "Fusion MPT SCSI Host driver"
+#define my_VERSION     MPT_LINUX_VERSION_COMMON
+#define MYNAM          "mptscsih"
+
+MODULE_AUTHOR(MODULEAUTHOR);
+MODULE_DESCRIPTION(my_NAME);
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+typedef struct _BIG_SENSE_BUF {
+       u8              data[256];
+} BIG_SENSE_BUF;
+
+typedef struct _MPT_SCSI_HOST {
+       MPT_ADAPTER              *ioc;
+       int                       port;
+       struct scsi_cmnd        **ScsiLookup;
+       u8                       *SgHunks;
+       dma_addr_t                SgHunksDMA;
+       u32                       qtag_tick;
+       FCDEV_TRACKER             TargetsQ;
+} MPT_SCSI_HOST;
+
+typedef struct _MPT_SCSI_DEV {
+       struct _MPT_SCSI_DEV     *forw;
+       struct _MPT_SCSI_DEV     *back;
+       MPT_ADAPTER              *ioc;
+       int                       sense_sz;
+       BIG_SENSE_BUF             CachedSense;
+       unsigned long             io_cnt;
+       unsigned long             read_cnt;
+} MPT_SCSI_DEV;
+
+/*
+ *  Other private/forward protos...
+ */
+
+static int     mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
+static void    mptscsih_report_queue_full(Scsi_Cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq);
+static int     mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
+static int     mptscsih_io_direction(Scsi_Cmnd *cmd);
+static void    copy_sense_data(Scsi_Cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply);
+static u32     SCPNT_TO_MSGCTX(Scsi_Cmnd *sc);
+
+static int     mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply);
+
+
+static int     mpt_scsi_hosts = 0;
+static atomic_t        queue_depth;
+
+static int     ScsiDoneCtx = -1;
+static int     ScsiTaskCtx = -1;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,28)
+static struct proc_dir_entry proc_mpt_scsihost =
+{
+       low_ino:        PROC_SCSI_MPT,
+       namelen:        8,
+       name:           "mptscsih",
+       mode:           S_IFDIR | S_IRUGO | S_IXUGO,
+       nlink:          2,
+};
+#endif
+
+#define SNS_LEN(scp)  sizeof((scp)->sense_buffer)
+
+#ifndef MPT_SCSI_USE_NEW_EH
+/*
+ *  Stuff to handle single-threading SCSI TaskMgmt
+ *  (abort/reset) requests...
+ */
+static spinlock_t mpt_scsih_taskQ_lock = SPIN_LOCK_UNLOCKED;
+static MPT_Q_TRACKER mpt_scsih_taskQ = {
+       (MPT_FRAME_HDR*) &mpt_scsih_taskQ,
+       (MPT_FRAME_HDR*) &mpt_scsih_taskQ
+};
+static int mpt_scsih_taskQ_cnt = 0;
+static int mpt_scsih_taskQ_bh_active = 0;
+static MPT_FRAME_HDR *mpt_scsih_active_taskmgmt_mf = NULL;
+#endif
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     mptscsih_io_done - Main SCSI IO callback routine registered to
+ *     Fusion MPT (base) driver
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @mf: Pointer to original MPT request frame
+ *     @r: Pointer to MPT reply frame (NULL if TurboReply)
+ *
+ *     This routine is called from mpt.c::mpt_interrupt() at the completion
+ *     of any SCSI IO request.
+ *     This routine is registered with the Fusion MPT (base) driver at driver
+ *     load/init time via the mpt_register() API call.
+ *
+ *     Returns 1 indicating alloc'd request frame ptr should be freed.
+ */
+static int
+mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r)
+{
+       Scsi_Cmnd       *sc;
+       MPT_SCSI_HOST   *hd;
+       MPT_SCSI_DEV    *mpt_sdev = NULL;
+       u16              req_idx;
+
+       if ((mf == NULL) ||
+           (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) {
+               printk(KERN_ERR MYNAM ": ERROR! NULL or BAD req frame ptr (=%p)!\n", mf);
+               return 1;
+       }
+
+       hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
+       req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
+       sc = hd->ScsiLookup[req_idx];
+       hd->ScsiLookup[req_idx] = NULL;
+
+       dmfprintk((KERN_INFO MYNAM ": ScsiDone (req:sc:reply=%p:%p:%p)\n", mf, sc, r));
+
+       atomic_dec(&queue_depth);
+
+       /*
+        *  Check for {1st} {IO} completion to "new" device.
+        *  How do we know it's a new device?
+        *  If we haven't set SDpnt->hostdata I guess...
+        */
+       if (sc && sc->device) {
+               mpt_sdev = (MPT_SCSI_DEV*)sc->device->hostdata;
+               if (!mpt_sdev) {
+                       dprintk((KERN_INFO MYNAM ": *NEW* SCSI device (%d:%d:%d)!\n",
+                                          sc->device->id, sc->device->lun, sc->device->channel));
+                       if ((sc->device->hostdata = kmalloc(sizeof(MPT_SCSI_DEV), GFP_ATOMIC)) == NULL) {
+                               printk(KERN_ERR MYNAM ": ERROR: kmalloc(%d) FAILED!\n", (int)sizeof(MPT_SCSI_DEV));
+                       } else {
+                               memset(sc->device->hostdata, 0, sizeof(MPT_SCSI_DEV));
+                               mpt_sdev = (MPT_SCSI_DEV *) sc->device->hostdata;
+                               mpt_sdev->ioc = ioc;
+                       }
+               } else {
+                       if (++mpt_sdev->io_cnt && mptscsih_io_direction(sc) < 0) {
+                               if (++mpt_sdev->read_cnt == 3) {
+                                       dprintk((KERN_INFO MYNAM ": 3rd DATA_IN, CDB[0]=%02x\n",
+                                                       sc->cmnd[0]));
+                               }
+                       }
+#if 0
+                       if (mpt_sdev->sense_sz) {
+                               /*
+                                *  Completion of first IO down this path
+                                *  *should* invalidate device SenseData...
+                                */
+                               mpt_sdev->sense_sz = 0;
+                       }
+#endif
+               }
+       }
+
+#if 0
+{
+       MPT_FRAME_HDR   *mf_chk;
+
+       /* This, I imagine, is a costly check, but...
+        *  If abort/reset active, check to see if this is a IO
+        *  that completed while ABORT/RESET for it is waiting
+        *  on our taskQ!
+        */
+       if (! Q_IS_EMPTY(&mpt_scsih_taskQ)) {
+               /* If ABORT for this IO is queued, zap it! */
+               mf_chk = search_taskQ(1,sc,MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK);
+               if (mf_chk != NULL) {
+                       sc->result = DID_ABORT << 16;
+                       spin_lock_irqsave(&io_request_lock, flags);
+                       sc->scsi_done(sc);
+                       spin_unlock_irqrestore(&io_request_lock, flags);
+                       return 1;
+               }
+       }
+}
+#endif
+
+       if (r != NULL && sc != NULL) {
+               SCSIIOReply_t   *pScsiReply;
+               SCSIIORequest_t *pScsiReq;
+               u16              status;
+
+               pScsiReply = (SCSIIOReply_t *) r;
+               pScsiReq = (SCSIIORequest_t *) mf;
+
+               status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK;
+
+               dprintk((KERN_NOTICE MYNAM ": Uh-Oh!  (req:sc:reply=%p:%p:%p)\n", mf, sc, r));
+               dprintk((KERN_NOTICE "  IOCStatus=%04xh, SCSIState=%02xh"
+                                    ", SCSIStatus=%02xh, IOCLogInfo=%08xh\n",
+                                    status, pScsiReply->SCSIState, pScsiReply->SCSIStatus,
+                                    le32_to_cpu(pScsiReply->IOCLogInfo)));
+
+               /*
+                *  Look for + dump FCP ResponseInfo[]!
+                */
+               if (pScsiReply->SCSIState & MPI_SCSI_STATE_RESPONSE_INFO_VALID) {
+                       dprintk((KERN_NOTICE "  FCP_ResponseInfo=%08xh\n",
+                                            le32_to_cpu(pScsiReply->ResponseInfo)));
+               }
+
+               switch(status) {
+               case MPI_IOCSTATUS_BUSY:                        /* 0x0002 */
+                       /*sc->result = DID_BUS_BUSY << 16;*/            /* YIKES! - Seems to
+                                                                        * kill linux interrupt
+                                                                        * handler
+                                                                        */
+                       sc->result = STS_BUSY;                          /* Try SCSI BUSY! */
+                       break;
+
+               case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR:        /* 0x0040 */
+                       /*  Not real sure here...  */
+                       sc->result = DID_OK << 16;
+                       break;
+
+               case MPI_IOCSTATUS_SCSI_INVALID_BUS:            /* 0x0041 */
+               case MPI_IOCSTATUS_SCSI_INVALID_TARGETID:       /* 0x0042 */
+                       sc->result = DID_BAD_TARGET << 16;
+                       break;
+
+               case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE:       /* 0x0043 */
+                       /*  Spoof to SCSI Selection Timeout!  */
+                       sc->result = DID_NO_CONNECT << 16;
+                       break;
+
+               case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN:          /* 0x0045 */
+                       /*
+                        *  YIKES!  I just discovered that SCSI IO which
+                        *  returns check condition, SenseKey=05 (ILLEGAL REQUEST)
+                        *  and ASC/ASCQ=94/01 (LSI Logic RAID vendor specific),
+                        *  comes down this path!
+                        *  Do upfront check for valid SenseData and give it
+                        *  precedence!
+                        */
+                       if (pScsiReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
+                               copy_sense_data(sc, hd, mf, pScsiReply);
+                               sc->result = pScsiReply->SCSIStatus;
+                               break;
+                       }
+
+                       dprintk((KERN_NOTICE MYNAM ": sc->underflow={report ERR if < %02xh bytes xfer'd}\n", sc->underflow));
+                       dprintk((KERN_NOTICE MYNAM ": ActBytesXferd=%02xh\n", le32_to_cpu(pScsiReply->TransferCount)));
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
+                       sc->resid = sc->request_bufflen - le32_to_cpu(pScsiReply->TransferCount);
+                       dprintk((KERN_NOTICE MYNAM ": SET sc->resid=%02xh\n", sc->resid));
+#endif
+
+#if 0
+                       if (sc->underflow && (le32_to_cpu(pScsiReply->TransferCount) < sc->underflow)) {
+                               sc->result = DID_ERROR << 16;
+                               sc->resid = sc->request_bufflen - le32_to_cpu(pScsiReply->TransferCount);
+                       } else {
+                               sc->result = 0;
+                       }
+#endif
+
+                       /* workaround attempts... */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
+                       if (sc->resid >= 0x200) {
+                               /* GRRRRR...
+                                *   //sc->result = DID_SOFT_ERROR << 16;
+                                * Try spoofing to BUSY
+                                */
+                               sc->result = STS_BUSY;
+                       } else {
+                               sc->result = 0;
+                       }
+#else
+                       sc->result = 0;
+#endif
+                       break;
+
+               case MPI_IOCSTATUS_SCSI_TASK_TERMINATED:        /* 0x0048 */
+                       sc->result = DID_ABORT << 16;
+                       break;
+
+               case MPI_IOCSTATUS_SCSI_IOC_TERMINATED:         /* 0x004B */
+               case MPI_IOCSTATUS_SCSI_EXT_TERMINATED:         /* 0x004C */
+                       sc->result = DID_RESET << 16;
+                       break;
+
+               case MPI_IOCSTATUS_SUCCESS:                     /* 0x0000 */
+                       sc->result = pScsiReply->SCSIStatus;
+
+                       if (pScsiReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
+                               copy_sense_data(sc, hd, mf, pScsiReply);
+
+                               /*  If running agains circa 200003dd 909 MPT f/w,
+                                *  may get this (AUTOSENSE_VALID) for actual TASK_SET_FULL
+                                *  (QUEUE_FULL) returned from device!  --> get 0x0000?128
+                                *  and with SenseBytes set to 0.
+                                */
+                               if (pScsiReply->SCSIStatus == MPI_SCSI_STATUS_TASK_SET_FULL)
+                                       mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
+                       }
+                       else if (pScsiReply->SCSIState & (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)) {
+                               /*
+                                *  What to do?
+                                */
+                               sc->result = DID_SOFT_ERROR << 16;
+                       }
+                       else if (pScsiReply->SCSIState & MPI_SCSI_STATE_TERMINATED) {
+                               /*  Not real sure here either...  */
+                               sc->result = DID_ABORT << 16;
+                       }
+
+                       if (sc->result == MPI_SCSI_STATUS_TASK_SET_FULL)
+                               mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
+
+                       break;
+
+               case MPI_IOCSTATUS_INVALID_FUNCTION:            /* 0x0001 */
+               case MPI_IOCSTATUS_INVALID_SGL:                 /* 0x0003 */
+               case MPI_IOCSTATUS_INTERNAL_ERROR:              /* 0x0004 */
+               case MPI_IOCSTATUS_RESERVED:                    /* 0x0005 */
+               case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES:      /* 0x0006 */
+               case MPI_IOCSTATUS_INVALID_FIELD:               /* 0x0007 */
+               case MPI_IOCSTATUS_INVALID_STATE:               /* 0x0008 */
+               case MPI_IOCSTATUS_SCSI_DATA_OVERRUN:           /* 0x0044 */
+               case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR:          /* 0x0046 */
+               case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR:         /* 0x0047 */
+               case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:      /* 0x0049 */
+               case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED:       /* 0x004A */
+               default:
+                       /*
+                        *  What to do?
+                        */
+                       sc->result = DID_SOFT_ERROR << 16;
+                       break;
+
+               }       /* switch(status) */
+
+               dprintk((KERN_NOTICE MYNAM ": sc->result set to %08xh\n", sc->result));
+       }
+
+       if (sc != NULL) {
+               unsigned long flags;
+
+               /* Unmap the DMA buffers, if any. */
+               if (sc->use_sg) {
+                       pci_unmap_sg(ioc->pcidev,
+                                    (struct scatterlist *) sc->request_buffer,
+                                    sc->use_sg,
+                                    scsi_to_pci_dma_dir(sc->sc_data_direction));
+               } else if (sc->request_bufflen) {
+                       pci_unmap_single(ioc->pcidev,
+                                        (dma_addr_t)((long)sc->SCp.ptr),
+                                        sc->request_bufflen,
+                                        scsi_to_pci_dma_dir(sc->sc_data_direction));
+               }
+
+               spin_lock_irqsave(&io_request_lock, flags);
+               sc->scsi_done(sc);
+               spin_unlock_irqrestore(&io_request_lock, flags);
+       }
+
+       return 1;
+}
+
+#ifndef MPT_SCSI_USE_NEW_EH
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     search_taskQ - Search SCSI task mgmt request queue for specific
+ *                     request type
+ *     @remove: (Boolean) Should request be removed if found?
+ *     @sc: Pointer to Scsi_Cmnd structure
+ *     @task_type: Task type to search for
+ *
+ *     Returns pointer to MPT request frame if found, or %NULL if request
+ *     was not found.
+ */
+static MPT_FRAME_HDR *
+search_taskQ(int remove, Scsi_Cmnd *sc, u8 task_type)
+{
+       MPT_FRAME_HDR *mf = NULL;
+       unsigned long flags;
+       int count = 0;
+       int list_sz;
+
+       dslprintk((KERN_INFO MYNAM ": spinlock#1\n"));
+       spin_lock_irqsave(&mpt_scsih_taskQ_lock, flags);
+       list_sz = mpt_scsih_taskQ_cnt;
+       if (! Q_IS_EMPTY(&mpt_scsih_taskQ)) {
+               mf = mpt_scsih_taskQ.head;
+               do {
+                       count++;
+                       if (mf->u.frame.linkage.argp1 == sc &&
+                           mf->u.frame.linkage.arg1 == task_type) {
+                               if (remove) {
+                                       Q_DEL_ITEM(&mf->u.frame.linkage);
+                                       mpt_scsih_taskQ_cnt--;
+                               }
+                               break;
+                       }
+               } while ((mf = mf->u.frame.linkage.forw) != (MPT_FRAME_HDR*)&mpt_scsih_taskQ);
+               if (mf == (MPT_FRAME_HDR*)&mpt_scsih_taskQ) {
+                       mf = NULL;
+               }
+       }
+       spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags);
+
+       if (list_sz) {
+               dprintk((KERN_INFO MYNAM ": search_taskQ(%d,%p,%d) results=%p (%sFOUND%s)!\n",
+                                  remove, sc, task_type,
+                                  mf,
+                                  mf ? "" : "NOT_",
+                                  (mf && remove) ? "+REMOVED" : "" ));
+               dprintk((KERN_INFO MYNAM ": (searched thru %d of %d items on taskQ)\n",
+                                  count,
+                                  list_sz ));
+       }
+
+       return mf;
+}
+
+#endif
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+/*
+ *  Hack!  I'd like to report if a device is returning QUEUE_FULL
+ *  but maybe not each and every time...
+ */
+static long last_queue_full = 0;
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     mptscsih_report_queue_full - Report QUEUE_FULL status returned
+ *     from a SCSI target device.
+ *     @sc: Pointer to Scsi_Cmnd structure
+ *     @pScsiReply: Pointer to SCSIIOReply_t
+ *     @pScsiReq: Pointer to original SCSI request
+ *
+ *     This routine periodically reports QUEUE_FULL status returned from a
+ *     SCSI target device.  It reports this to the console via kernel
+ *     printk() API call, not more than once every 10 seconds.
+ */
+static void
+mptscsih_report_queue_full(Scsi_Cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq)
+{
+       long time = jiffies;
+
+       if (time - last_queue_full > 10 * HZ) {
+               printk(KERN_WARNING MYNAM ": Device reported QUEUE_FULL!  SCSI bus:target:lun = %d:%d:%d\n",
+                               0, sc->target, sc->lun);
+               last_queue_full = time;
+       }
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int BeenHereDoneThat = 0;
+
+/*  SCSI fops start here...  */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mptscsih_detect - Register MPT adapter(s) as SCSI host(s) with
+ *     linux scsi mid-layer.
+ *     @tpnt: Pointer to Scsi_Host_Template structure
+ *
+ *     (linux Scsi_Host_Template.detect routine)
+ *
+ *     Returns number of SCSI host adapters that were successfully
+ *     registered with the linux scsi mid-layer via the scsi_register()
+ *     API call.
+ */
+int
+mptscsih_detect(Scsi_Host_Template *tpnt)
+{
+       struct Scsi_Host        *sh = NULL;
+       MPT_SCSI_HOST           *hd = NULL;
+       MPT_ADAPTER             *this;
+       unsigned long            flags;
+       int                      sz;
+       u8                      *mem;
+
+       if (! BeenHereDoneThat++) {
+               show_mptmod_ver(my_NAME, my_VERSION);
+
+               ScsiDoneCtx = mpt_register(mptscsih_io_done, MPTSCSIH_DRIVER);
+               ScsiTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSCSIH_DRIVER);
+
+#ifndef MPT_SCSI_USE_NEW_EH
+               Q_INIT(&mpt_scsih_taskQ, MPT_FRAME_HDR);
+               spin_lock_init(&mpt_scsih_taskQ_lock);
+#endif
+
+               if (mpt_event_register(ScsiDoneCtx, mptscsih_event_process) == 0) {
+                       dprintk((KERN_INFO MYNAM ": Registered for IOC event notifications\n"));
+               } else {
+                       /* FIXME! */
+               }
+       }
+
+       dprintk((KERN_INFO MYNAM ": mpt_scsih_detect()\n"));
+
+       this = mpt_adapter_find_first();
+       while (this != NULL) {
+               /* FIXME!  Multi-port (aka FC929) support...
+                * for (i = 0; i < this->facts.NumberOfPorts; i++)
+                */
+
+               /* 20010215 -sralston
+                *  Added sanity check on SCSI Initiator-mode enabled
+                *  for this MPT adapter.
+                */
+               if (!(this->pfacts0.ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR)) {
+                       printk(KERN_ERR MYNAM ": Skipping %s because SCSI Initiator mode is NOT enabled!\n",
+                                       this->name);
+                       this = mpt_adapter_find_next(this);
+                       continue;
+               }
+
+               /* 20010202 -sralston
+                *  Added sanity check on readiness of the MPT adapter.
+                */
+               if (this->last_state != MPI_IOC_STATE_OPERATIONAL) {
+                       printk(KERN_ERR MYNAM ": ERROR - Skipping %s because it's not operational!\n",
+                                       this->name);
+                       this = mpt_adapter_find_next(this);
+                       continue;
+               }
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
+               tpnt->proc_dir = &proc_mpt_scsihost;
+#endif
+               sh = scsi_register(tpnt, sizeof(MPT_SCSI_HOST));
+               if (sh != NULL) {
+                       save_flags(flags);
+                       cli();
+                       sh->io_port = 0;
+                       sh->n_io_port = 0;
+                       sh->irq = 0;
+
+                       /* Yikes!  This is important!
+                        * Otherwise, by default, linux only scans target IDs 0-7!
+                        */
+                       sh->max_id = this->pfacts0.MaxDevices - 1;
+
+                       sh->this_id = this->pfacts0.PortSCSIID;
+
+                       restore_flags(flags);
+
+                       hd = (MPT_SCSI_HOST *) sh->hostdata;
+                       hd->ioc = this;
+                       hd->port = 0;           /* FIXME! */
+
+                       /* SCSI needs Scsi_Cmnd lookup table!
+                        * (with size equal to req_depth*PtrSz!)
+                        */
+                       sz = hd->ioc->req_depth * sizeof(void *);
+                       mem = kmalloc(sz, GFP_KERNEL);
+                       if (mem == NULL)
+                               return mpt_scsi_hosts;
+
+                       memset(mem, 0, sz);
+                       hd->ScsiLookup = (struct scsi_cmnd **) mem;
+
+                       dprintk((KERN_INFO MYNAM ": ScsiLookup @ %p, sz=%d\n",
+                                hd->ScsiLookup, sz));
+
+                       /* SCSI also needs SG buckets/hunk management!
+                        * (with size equal to N * req_sz * req_depth!)
+                        * (where N is number of SG buckets per hunk)
+                        */
+                       sz = MPT_SG_BUCKETS_PER_HUNK * hd->ioc->req_sz * hd->ioc->req_depth;
+                       mem = pci_alloc_consistent(hd->ioc->pcidev, sz,
+                                                  &hd->SgHunksDMA);
+                       if (mem == NULL)
+                               return mpt_scsi_hosts;
+
+                       memset(mem, 0, sz);
+                       hd->SgHunks = (u8*)mem;
+
+                       dprintk((KERN_INFO MYNAM ": SgHunks    @ %p(%08x), sz=%d\n",
+                                hd->SgHunks, hd->SgHunksDMA, sz));
+
+                       hd->qtag_tick = jiffies;
+
+                       this->sh = sh;
+                       mpt_scsi_hosts++;
+               }
+               this = mpt_adapter_find_next(this);
+       }
+
+       return mpt_scsi_hosts;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+    static char *info_kbuf = NULL;
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mptscsih_release - Unregister SCSI host from linux scsi mid-layer
+ *     @host: Pointer to Scsi_Host structure
+ *
+ *     (linux Scsi_Host_Template.release routine)
+ *     This routine releases all resources associated with the SCSI host
+ *     adapter.
+ *
+ *     Returns 0 for success.
+ */
+int
+mptscsih_release(struct Scsi_Host *host)
+{
+       MPT_SCSI_HOST   *hd;
+#ifndef MPT_SCSI_USE_NEW_EH
+       unsigned long    flags;
+
+       spin_lock_irqsave(&mpt_scsih_taskQ_lock, flags);
+       if (mpt_scsih_taskQ_bh_active) {
+               int count = 10 * HZ;
+
+               dprintk((KERN_INFO MYNAM ": Info: Zapping TaskMgmt thread!\n"));
+
+               /* Zap the taskQ! */
+               Q_INIT(&mpt_scsih_taskQ, MPT_FRAME_HDR);
+               spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags);
+
+               while(mpt_scsih_taskQ_bh_active && --count) {
+                       current->state = TASK_INTERRUPTIBLE;
+                       schedule_timeout(1);
+               }
+               if (!count)
+                       printk(KERN_ERR MYNAM ": ERROR! TaskMgmt thread still active!\n");
+       }
+       spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags);
+#endif
+
+       hd = (MPT_SCSI_HOST *) host->hostdata;
+       if (hd != NULL) {
+               int sz1, sz2;
+
+               sz1 = sz2 = 0;
+               if (hd->ScsiLookup != NULL) {
+                       sz1 = hd->ioc->req_depth * sizeof(void *);
+                       kfree(hd->ScsiLookup);
+                       hd->ScsiLookup = NULL;
+               }
+
+               if (hd->SgHunks != NULL) {
+
+                       sz2 = MPT_SG_BUCKETS_PER_HUNK * hd->ioc->req_sz * hd->ioc->req_depth;
+                       pci_free_consistent(hd->ioc->pcidev, sz2,
+                                           hd->SgHunks, hd->SgHunksDMA);
+                       hd->SgHunks = NULL;
+               }
+               dprintk((KERN_INFO MYNAM ": Free'd ScsiLookup (%d) and SgHunks (%d) memory\n", sz1, sz2));
+       }
+
+       if (mpt_scsi_hosts) {
+               if (--mpt_scsi_hosts == 0) {
+#if 0
+                       mptscsih_flush_pending();
+#endif
+                       mpt_event_deregister(ScsiDoneCtx);
+                       dprintk((KERN_INFO MYNAM ": Deregistered for IOC event notifications\n"));
+
+                       mpt_deregister(ScsiDoneCtx);
+                       mpt_deregister(ScsiTaskCtx);
+
+                       if (info_kbuf != NULL)
+                               kfree(info_kbuf);
+               }
+       }
+
+       return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mptscsih_info - Return information about MPT adapter
+ *     @SChost: Pointer to Scsi_Host structure
+ *
+ *     (linux Scsi_Host_Template.info routine)
+ *
+ *     Returns pointer to buffer where information was written.
+ */
+const char *
+mptscsih_info(struct Scsi_Host *SChost)
+{
+       MPT_SCSI_HOST *h;
+       int size = 0;
+
+       if (info_kbuf == NULL)
+               if ((info_kbuf = kmalloc(0x1000 /* 4Kb */, GFP_KERNEL)) == NULL)
+                       return info_kbuf;
+
+       h = (MPT_SCSI_HOST *)SChost->hostdata;
+       info_kbuf[0] = '\0';
+       mpt_print_ioc_summary(h->ioc, info_kbuf, &size, 0);
+       info_kbuf[size-1] = '\0';
+
+       return info_kbuf;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+       static int max_qd = 1;
+#ifdef MPT_DEBUG
+       static int max_sges = 0;
+       static int max_xfer = 0;
+#endif
+#if 0
+       static int max_num_sges = 0;
+       static int max_sgent_len = 0;
+#endif
+#if 0
+static int index_log[128];
+static int index_ent = 0;
+static __inline__ void ADD_INDEX_LOG(int req_ent)
+{
+       int i = index_ent++;
+
+       index_log[i & (128 - 1)] = req_ent;
+}
+#else
+#define ADD_INDEX_LOG(req_ent) do { } while(0)
+#endif
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mptscsih_qcmd - Primary Fusion MPT SCSI initiator IO start routine.
+ *     @SCpnt: Pointer to Scsi_Cmnd structure
+ *     @done: Pointer SCSI mid-layer IO completion function
+ *
+ *     (linux Scsi_Host_Template.queuecommand routine)
+ *     This is the primary SCSI IO start routine.  Create a MPI SCSIIORequest
+ *     from a linux Scsi_Cmnd request and send it to the IOC.
+ *
+ *     Returns 0. (rtn value discarded by linux scsi mid-layer)
+ */
+int
+mptscsih_qcmd(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
+{
+       struct Scsi_Host        *host;
+       MPT_SCSI_HOST           *hd;
+       MPT_FRAME_HDR           *mf;
+       SCSIIORequest_t         *pScsiReq;
+       int      datadir;
+       u32      len;
+       u32      sgdir;
+       u32      scsictl;
+       u32      scsidir;
+       u32      qtag;
+       u32     *mptr;
+       int      sge_spill1;
+       int      frm_sz;
+       int      sges_left;
+       u32      chain_offset;
+       int      my_idx;
+       int      i;
+
+       dmfprintk((KERN_INFO MYNAM "_qcmd: SCpnt=%p, done()=%p\n",
+                   SCpnt, done));
+
+       host = SCpnt->host;
+       hd = (MPT_SCSI_HOST *) host->hostdata;
+       
+#if 0
+       if (host->host_busy >= 60) {
+               MPT_ADAPTER *ioc = hd->ioc;
+               u16 pci_command, pci_status;
+
+               /* The IOC is probably hung, investigate status. */
+               printk("MPI: IOC probably hung IOCSTAT[%08x] INTSTAT[%08x] REPLYFIFO[%08x]\n",
+                      readl(&ioc->chip.fc9xx->DoorbellValue),
+                      readl(&ioc->chip.fc9xx->IntStatus),
+                      readl(&ioc->chip.fc9xx->ReplyFifo));
+               pci_read_config_word(ioc->pcidev, PCI_COMMAND, &pci_command);
+               pci_read_config_word(ioc->pcidev, PCI_STATUS, &pci_status);
+               printk("MPI: PCI command[%04x] status[%04x]\n", pci_command, pci_status);
+               {
+                       /* DUMP req index logger. */
+                       int begin, end;
+
+                       begin = (index_ent - 65) & (128 - 1);
+                       end = index_ent & (128 - 1);
+                       printk("MPI: REQ_INDEX_HIST[");
+                       while (begin != end) {
+                               printk("(%04x)", index_log[begin]);
+                               begin = (begin + 1) & (128 - 1);
+                       }
+                       printk("\n");
+               }
+               sti();
+               while(1)
+                       barrier();
+       }
+#endif
+
+       SCpnt->scsi_done = done;
+
+       /* 20000617 -sralston
+        *  GRRRRR...  Shouldn't have to do this but...
+        *  Do explicit check for REQUEST_SENSE and cached SenseData.
+        *  If yes, return cached SenseData.
+        */
+#ifdef MPT_SCSI_CACHE_AUTOSENSE
+       {
+               MPT_SCSI_DEV    *mpt_sdev;
+
+               mpt_sdev = (MPT_SCSI_DEV *) SCpnt->device->hostdata;
+               if (mpt_sdev && SCpnt->cmnd[0] == REQUEST_SENSE) {
+                       u8 *dest = NULL;
+
+                       if (!SCpnt->use_sg)
+                               dest = SCpnt->request_buffer;
+                       else {
+                               struct scatterlist *sg = (struct scatterlist *) SCpnt->request_buffer;
+                               if (sg)
+                                       dest = (u8 *) (unsigned long)sg_dma_address(sg);
+                       }
+
+                       if (dest && mpt_sdev->sense_sz) {
+                               memcpy(dest, mpt_sdev->CachedSense.data, mpt_sdev->sense_sz);
+#ifdef MPT_DEBUG
+                               {
+                                       int  i;
+                                       u8  *sb;
+
+                                       sb = mpt_sdev->CachedSense.data;
+                                       if (sb && ((sb[0] & 0x70) == 0x70)) {
+                                               printk(KERN_WARNING MYNAM ": Returning last cached SCSI (hex) SenseData:\n");
+                                               printk(KERN_WARNING " ");
+                                               for (i = 0; i < (8 + sb[7]); i++)
+                                                       printk("%s%02x", i == 13 ? "-" : " ", sb[i]);
+                                               printk("\n");
+                                       }
+                               }
+#endif
+                       }
+                       SCpnt->resid = SCpnt->request_bufflen - mpt_sdev->sense_sz;
+                       SCpnt->result = 0;
+/*                     spin_lock(&io_request_lock);    */
+                       SCpnt->scsi_done(SCpnt);
+/*                     spin_unlock(&io_request_lock);  */
+                       return 0;
+               }
+       }
+#endif
+
+       if ((mf = mpt_get_msg_frame(ScsiDoneCtx, hd->ioc->id)) == NULL) {
+/*             SCpnt->result = DID_SOFT_ERROR << 16;   */
+               SCpnt->result = STS_BUSY;
+               SCpnt->scsi_done(SCpnt);
+/*             return 1;                               */
+               return 0;
+       }
+       pScsiReq = (SCSIIORequest_t *) mf;
+
+       my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
+
+       ADD_INDEX_LOG(my_idx);
+
+       /* Map the data portion, if any. */
+       sges_left = SCpnt->use_sg;
+       if (sges_left) {
+               sges_left = pci_map_sg(hd->ioc->pcidev,
+                                      (struct scatterlist *) SCpnt->request_buffer,
+                                      sges_left,
+                                      scsi_to_pci_dma_dir(SCpnt->sc_data_direction));
+       } else if (SCpnt->request_bufflen) {
+               dma_addr_t buf_dma_addr;
+
+               buf_dma_addr = pci_map_single(hd->ioc->pcidev,
+                                             SCpnt->request_buffer,
+                                             SCpnt->request_bufflen,
+                                             scsi_to_pci_dma_dir(SCpnt->sc_data_direction));
+
+               /* We hide it here for later unmap. */
+               SCpnt->SCp.ptr = (char *)(unsigned long) buf_dma_addr;
+       }
+
+       /*
+        *  Put together a MPT SCSI request...
+        */
+
+       /* Assume SimpleQ, NO DATA XFER for now */
+
+       len = SCpnt->request_bufflen;
+       sgdir = 0x00000000;             /* SGL IN  (host<--ioc) */
+       scsidir = MPI_SCSIIO_CONTROL_NODATATRANSFER;
+
+       /*
+        *  The scsi layer should be handling this stuff
+        *  (In 2.3.x it does -DaveM)
+        */
+
+       /*  BUG FIX!  19991030 -sralston
+        *    TUR's being issued with scsictl=0x02000000 (DATA_IN)!
+        *    Seems we may receive a buffer (len>0) even when there
+        *    will be no data transfer!  GRRRRR...
+        */
+       datadir = mptscsih_io_direction(SCpnt);
+       if (datadir < 0) {
+               scsidir = MPI_SCSIIO_CONTROL_READ;      /* DATA IN  (host<--ioc<--dev) */
+       } else if (datadir > 0) {
+               sgdir   = 0x04000000;                   /* SGL OUT  (host-->ioc) */
+               scsidir = MPI_SCSIIO_CONTROL_WRITE;     /* DATA OUT (host-->ioc-->dev) */
+       } else {
+               len = 0;
+       }
+
+       qtag = MPI_SCSIIO_CONTROL_SIMPLEQ;
+
+       /*
+        *  Attach tags to the devices
+        */
+       if (SCpnt->device->tagged_supported) {
+               /*
+                *  Some drives are too stupid to handle fairness issues
+                *  with tagged queueing. We throw in the odd ordered
+                *  tag to stop them starving themselves.
+                */
+               if ((jiffies - hd->qtag_tick) > (5*HZ)) {
+                       qtag = MPI_SCSIIO_CONTROL_ORDEREDQ;
+                       hd->qtag_tick = jiffies;
+
+#if 0
+                       /* These are ALWAYS zero!
+                        * (Because this is a place for the device driver to dynamically
+                        *  assign tag numbers any way it sees fit.  That's why -DaveM)
+                        */
+                       dprintk((KERN_DEBUG MYNAM ": sc->device->current_tag = %08x\n",
+                                       SCpnt->device->current_tag));
+                       dprintk((KERN_DEBUG MYNAM ": sc->tag                 = %08x\n",
+                                       SCpnt->tag));
+#endif
+               }
+#if 0
+               else {
+                       /* Hmmm...  I always see value of 0 here,
+                        *  of which {HEAD_OF, ORDERED, SIMPLE} are NOT!  -sralston
+                        * (Because this is a place for the device driver to dynamically
+                        *  assign tag numbers any way it sees fit.  That's why -DaveM)
+                        *
+                        * if (SCpnt->tag == HEAD_OF_QUEUE_TAG)
+                        */
+                       if (SCpnt->device->current_tag == HEAD_OF_QUEUE_TAG)
+                               qtag = MPI_SCSIIO_CONTROL_HEADOFQ;
+                       else if (SCpnt->tag == ORDERED_QUEUE_TAG)
+                               qtag = MPI_SCSIIO_CONTROL_ORDEREDQ;
+               }
+#endif
+       }
+
+       scsictl = scsidir | qtag;
+
+       frm_sz = hd->ioc->req_sz;
+
+       /* Ack!
+        * sge_spill1 = 9;
+        */
+       sge_spill1 = (frm_sz - (sizeof(SCSIIORequest_t) - sizeof(SGEIOUnion_t) + sizeof(SGEChain32_t))) / 8;
+       /*  spill1: for req_sz == 128 (128-48==80, 80/8==10 SGEs max, first time!), --> use 9
+        *  spill1: for req_sz ==  96 ( 96-48==48, 48/8== 6 SGEs max, first time!), --> use 5
+        */
+       dsgprintk((KERN_INFO MYNAM ": SG: %x     spill1 = %d\n",
+                  my_idx, sge_spill1));
+
+#ifdef MPT_DEBUG
+       if (sges_left > max_sges) {
+               max_sges = sges_left;
+               dprintk((KERN_INFO MYNAM ": MPT_MaxSges = %d\n", max_sges));
+       }
+#endif
+#if 0
+       if (sges_left > max_num_sges) {
+               max_num_sges = sges_left;
+               printk(KERN_INFO MYNAM ": MPT_MaxNumSges = %d\n", max_num_sges);
+       }
+#endif
+
+       dsgprintk((KERN_INFO MYNAM ": SG: %x     sges_left = %d (initially)\n",
+                  my_idx, sges_left));
+
+       chain_offset = 0;
+       if (sges_left > (sge_spill1+1)) {
+#if 0
+               chain_offset = 0x1E;
+#endif
+               chain_offset = (frm_sz - 8) / 4;
+       }
+
+       pScsiReq->TargetID = SCpnt->target;
+       pScsiReq->Bus = hd->port;
+       pScsiReq->ChainOffset = chain_offset;
+       pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
+       pScsiReq->CDBLength = SCpnt->cmd_len;
+
+/* We have 256 bytes alloc'd per IO; let's use it. */
+/*     pScsiReq->SenseBufferLength = SNS_LEN(SCpnt);   */
+       pScsiReq->SenseBufferLength = 255;
+
+       pScsiReq->Reserved = 0;
+       pScsiReq->MsgFlags = 0;
+       pScsiReq->LUN[0] = 0;
+       pScsiReq->LUN[1] = SCpnt->lun;
+       pScsiReq->LUN[2] = 0;
+       pScsiReq->LUN[3] = 0;
+       pScsiReq->LUN[4] = 0;
+       pScsiReq->LUN[5] = 0;
+       pScsiReq->LUN[6] = 0;
+       pScsiReq->LUN[7] = 0;
+       pScsiReq->Control = cpu_to_le32(scsictl);
+
+       /*
+        *  Write SCSI CDB into the message
+        */
+       for (i = 0; i < 12; i++)
+               pScsiReq->CDB[i] = SCpnt->cmnd[i];
+       for (i = 12; i < 16; i++)
+               pScsiReq->CDB[i] = 0;
+
+       /* DataLength */
+       pScsiReq->DataLength = cpu_to_le32(len);
+
+       /* SenseBuffer low address */
+       pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_pool_dma + (my_idx * 256));
+
+       mptr = (u32 *) &pScsiReq->SGL;
+
+       /*
+        *  Now fill in the SGList...
+        *  NOTES: For 128 byte req_sz, we can hold up to 10 simple SGE's
+        *  in the remaining request frame.  We -could- do unlimited chains
+        *  but each chain buffer can only be req_sz bytes in size, and
+        *  we lose one SGE whenever we chain.
+        *  For 128 req_sz, we can hold up to 16 SGE's per chain buffer.
+        *  For practical reasons, limit ourselves to 1 overflow chain buffer;
+        *  giving us 9 + 16 == 25 SGE's max.
+        *  At 4 Kb per SGE, that yields 100 Kb max transfer.
+        *
+        *  (This code needs to be completely changed when/if 64-bit DMA
+        *   addressing is used, since we will be able to fit much less than
+        *   10 embedded SG entries. -DaveM)
+        */
+       if (sges_left) {
+               struct scatterlist *sg = (struct scatterlist *) SCpnt->request_buffer;
+               u32  v1, v2;
+               int  sge_spill2;
+               int  sge_cur_spill;
+               int  sgCnt;
+               u8  *pSgBucket;
+               int  chain_sz;
+
+               len = 0;
+
+               /*      sge_spill2 = 15;
+                *  spill2: for req_sz == 128 (128/8==16 SGEs max, first time!), --> use 15
+                *  spill2: for req_sz ==  96 ( 96/8==12 SGEs max, first time!), --> use 11
+                */
+               sge_spill2 = frm_sz / 8 - 1;
+               dsgprintk((KERN_INFO MYNAM ": SG: %x     spill2 = %d\n",
+                          my_idx, sge_spill2));
+
+               pSgBucket = NULL;
+               sgCnt = 0;
+               sge_cur_spill = sge_spill1;
+               while (sges_left) {
+#if 0
+                       if (sg_dma_len(sg) > max_sgent_len) {
+                               max_sgent_len = sg_dma_len(sg);
+                               printk(KERN_INFO MYNAM ": MPT_MaxSgentLen = %d\n", max_sgent_len);
+                       }
+#endif
+                       /* Write one simple SGE */
+                       v1 = sgdir | 0x10000000 | sg_dma_len(sg);
+                       len += sg_dma_len(sg);
+                       v2 = sg_dma_address(sg);
+                       dsgprintk((KERN_INFO MYNAM ": SG: %x     Writing SGE @%p: %08x %08x, sges_left=%d\n",
+                                  my_idx, mptr, v1, v2, sges_left));
+                       *mptr++ = cpu_to_le32(v1);
+                       *mptr++ = cpu_to_le32(v2);
+                       sg++;
+                       sgCnt++;
+
+                       if (--sges_left == 0) {
+                               /* re-write 1st word of previous SGE with SIMPLE,
+                                * LE, EOB, and EOL bits!
+                                */
+                               v1 = 0xD1000000 | sgdir | sg_dma_len(sg-1);
+                               dsgprintk((KERN_INFO MYNAM ": SG: %x (re)Writing SGE @%p: %08x (VERY LAST SGE!)\n",
+                                          my_idx, mptr-2, v1));
+                               *(mptr - 2) = cpu_to_le32(v1);
+                       } else {
+                               if ((sges_left > 1) && ((sgCnt % sge_cur_spill) == 0)) {
+                                       dsgprintk((KERN_INFO MYNAM ": SG: %x     SG spill at modulo 0!\n",
+                                                  my_idx));
+
+                                       /* Fixup previous SGE with LE bit! */
+                                       v1 = sgdir | 0x90000000 | sg_dma_len(sg-1);
+                                       dsgprintk((KERN_INFO MYNAM ": SG: %x (re)Writing SGE @%p: %08x (LAST BUCKET SGE!)\n",
+                                                  my_idx, mptr-2, v1));
+                                       *(mptr - 2) = cpu_to_le32(v1);
+
+                                       chain_offset = 0;
+                                       /* Going to need another chain? */
+                                       if (sges_left > (sge_spill2+1)) {
+#if 0
+                                               chain_offset = 0x1E;
+#endif
+                                               chain_offset = (frm_sz - 8) / 4;
+                                               chain_sz = frm_sz;
+                                       } else {
+                                               chain_sz = sges_left * 8;
+                                       }
+
+                                       /* write chain SGE at mptr. */
+                                       v1 = 0x30000000 | chain_offset<<16 | chain_sz;
+                                       if (pSgBucket == NULL) {
+                                               pSgBucket = hd->SgHunks
+                                                       + (my_idx * frm_sz * MPT_SG_BUCKETS_PER_HUNK);
+                                       } else {
+                                               pSgBucket += frm_sz;
+                                       }
+                                       v2 = (hd->SgHunksDMA +
+                                             ((u8 *)pSgBucket - (u8 *)hd->SgHunks));
+                                       dsgprintk((KERN_INFO MYNAM ": SG: %x     Writing SGE @%p: %08x %08x (CHAIN!)\n",
+                                                  my_idx, mptr, v1, v2));
+                                       *(mptr++) = cpu_to_le32(v1);
+                                       *(mptr) = cpu_to_le32(v2);
+
+                                       mptr = (u32 *) pSgBucket;
+                                       sgCnt = 0;
+                                       sge_cur_spill = sge_spill2;
+                               }
+                       }
+               }
+       } else {
+               dsgprintk((KERN_INFO MYNAM ": SG: non-SG for %p, len=%d\n",
+                          SCpnt, SCpnt->request_bufflen));
+
+               if (len > 0) {
+                       dma_addr_t buf_dma_addr;
+
+                       buf_dma_addr = (dma_addr_t) (unsigned long)SCpnt->SCp.ptr;
+                       *(mptr++) = cpu_to_le32(0xD1000000|sgdir|SCpnt->request_bufflen);
+                       *(mptr++) = cpu_to_le32(buf_dma_addr);
+               }
+       }
+
+#ifdef MPT_DEBUG
+       /* if (SCpnt->request_bufflen > max_xfer) */
+       if (len > max_xfer) {
+               max_xfer = len;
+               dprintk((KERN_INFO MYNAM ": MPT_MaxXfer = %d\n", max_xfer));
+       }
+#endif
+
+       hd->ScsiLookup[my_idx] = SCpnt;
+
+       /* Main banana... */
+       mpt_put_msg_frame(ScsiDoneCtx, hd->ioc->id, mf);
+
+       atomic_inc(&queue_depth);
+       if (atomic_read(&queue_depth) > max_qd) {
+               max_qd = atomic_read(&queue_depth);
+               dprintk((KERN_INFO MYNAM ": Queue depth now %d.\n", max_qd));
+       }
+
+       mb();
+       dmfprintk((KERN_INFO MYNAM ": Issued SCSI cmd (%p)\n", SCpnt));
+
+       return 0;
+}
+
+#ifdef MPT_SCSI_USE_NEW_EH             /* { */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+    mptscsih_abort
+    Returns: 0=SUCCESS, else FAILED
+*/
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mptscsih_abort - Abort linux Scsi_Cmnd routine, new_eh variant
+ *     @SCpnt: Pointer to Scsi_Cmnd structure, IO to be aborted
+ *
+ *     (linux Scsi_Host_Template.eh_abort_handler routine)
+ *
+ *     Returns SUCCESS or FAILED.  
+ */
+int
+mptscsih_abort(Scsi_Cmnd * SCpnt)
+{
+       MPT_FRAME_HDR   *mf;
+       SCSITaskMgmt_t  *pScsiTm;
+       MPT_SCSI_HOST   *hd;
+       u32             *msg;
+       u32              ctx2abort;
+       int              i;
+
+       printk(KERN_WARNING MYNAM ": Attempting _ABORT SCSI IO (=%p)\n", SCpnt);
+       printk(KERN_WARNING MYNAM ": IOs outstanding = %d\n", atomic_read(&queue_depth));
+
+       hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata;
+
+       if ((mf = mpt_get_msg_frame(ScsiTaskCtx, hd->ioc->id)) == NULL) {
+/*             SCpnt->result = DID_SOFT_ERROR << 16;   */
+               SCpnt->result = STS_BUSY;
+               SCpnt->scsi_done(SCpnt);
+               return FAILED;
+       }
+
+       pScsiTm = (SCSITaskMgmt_t *) mf;
+       msg = (u32 *) mf;
+
+       pScsiTm->TargetID = SCpnt->target;
+       pScsiTm->Bus = hd->port;
+       pScsiTm->ChainOffset = 0;
+       pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
+
+       pScsiTm->Reserved = 0;
+       pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK;
+       pScsiTm->Reserved1 = 0;
+       pScsiTm->MsgFlags = 0;
+
+       for (i = 0; i < 8; i++) {
+               u8 val = 0;
+               if (i == 1)
+                       val = SCpnt->lun;
+               pScsiTm->LUN[i] = val;
+       }
+
+       for (i = 0; i < 7; i++)
+               pScsiTm->Reserved2[i] = 0;
+
+       /* Most important!  Set TaskMsgContext to SCpnt's MsgContext!
+        * (the IO to be ABORT'd)
+        *
+        * NOTE: Since we do not byteswap MsgContext, we do not
+        *       swap it here either.  It is an opaque cookie to
+        *       the controller, so it does not matter. -DaveM
+        */
+       ctx2abort = SCPNT_TO_MSGCTX(SCpnt);
+       dprintk((KERN_INFO MYNAM ":DbG: ctx2abort = %08x\n", ctx2abort));
+       pScsiTm->TaskMsgContext = ctx2abort;
+
+       wmb();
+
+/* MPI v0.10 requires SCSITaskMgmt requests be sent via Doorbell/handshake
+       mpt_put_msg_frame(hd->ioc->id, mf);
+*/
+/* FIXME!  Check return status! */
+       (void) mpt_send_handshake_request(ScsiTaskCtx, hd->ioc->id, sizeof(SCSITaskMgmt_t), msg);
+
+       wmb();
+
+       return SUCCESS;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mptscsih_bus_reset - Perform a SCSI BUS_RESET!  new_eh variant
+ *     @SCpnt: Pointer to Scsi_Cmnd structure, IO which reset is due to
+ *
+ *     (linux Scsi_Host_Template.eh_bus_reset_handler routine)
+ *
+ *     Returns SUCCESS or FAILED.
+ */
+int
+mptscsih_bus_reset(Scsi_Cmnd * SCpnt)
+{
+       MPT_FRAME_HDR   *mf;
+       SCSITaskMgmt_t  *pScsiTm;
+       MPT_SCSI_HOST   *hd;
+       u32             *msg;
+       int              i;
+
+       printk(KERN_WARNING MYNAM ": Attempting _BUS_RESET (%p)\n", SCpnt);
+       printk(KERN_WARNING MYNAM ": IOs outstanding = %d\n", atomic_read(&queue_depth));
+
+       hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata;
+
+       if ((mf = mpt_get_msg_frame(ScsiTaskCtx, hd->ioc->id)) == NULL) {
+/*             SCpnt->result = DID_SOFT_ERROR << 16;   */
+               SCpnt->result = STS_BUSY;
+               SCpnt->scsi_done(SCpnt);
+               return FAILED;
+       }
+
+       pScsiTm = (SCSITaskMgmt_t *) mf;
+       msg = (u32 *) mf;
+
+       pScsiTm->TargetID = SCpnt->target;
+       pScsiTm->Bus = hd->port;
+       pScsiTm->ChainOffset = 0;
+       pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
+
+       pScsiTm->Reserved = 0;
+       pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS;
+       pScsiTm->Reserved1 = 0;
+       pScsiTm->MsgFlags = 0;
+
+       for (i = 0; i < 8; i++)
+               pScsiTm->LUN[i] = 0;
+
+       /* Control: No data direction, set task mgmt bit? */
+       for (i = 0; i < 7; i++)
+               pScsiTm->Reserved2[i] = 0;
+
+       pScsiTm->TaskMsgContext = cpu_to_le32(0);
+
+       wmb();
+
+/* MPI v0.10 requires SCSITaskMgmt requests be sent via Doorbell/handshake
+       mpt_put_msg_frame(hd->ioc->id, mf);
+*/
+/* FIXME!  Check return status! */
+       (void) mpt_send_handshake_request(ScsiTaskCtx, hd->ioc->id, sizeof(SCSITaskMgmt_t), msg);
+
+       wmb();
+
+       return SUCCESS;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mptscsih_dev_reset - Perform a SCSI TARGET_RESET!  new_eh variant
+ *     @SCpnt: Pointer to Scsi_Cmnd structure, IO which reset is due to
+ *
+ *     (linux Scsi_Host_Template.eh_dev_reset_handler routine)
+ *
+ *     Returns SUCCESS or FAILED.
+ */
+int
+mptscsih_dev_reset(Scsi_Cmnd * SCpnt)
+{
+       MPT_FRAME_HDR   *mf;
+       SCSITaskMgmt_t  *pScsiTm;
+       MPT_SCSI_HOST   *hd;
+       u32             *msg;
+       int              i;
+
+       printk(KERN_WARNING MYNAM ": Attempting _TARGET_RESET (%p)\n", SCpnt);
+       printk(KERN_WARNING MYNAM ": IOs outstanding = %d\n", atomic_read(&queue_depth));
+
+       hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata;
+
+       if ((mf = mpt_get_msg_frame(ScsiTaskCtx, hd->ioc->id)) == NULL) {
+/*             SCpnt->result = DID_SOFT_ERROR << 16;   */
+               SCpnt->result = STS_BUSY;
+               SCpnt->scsi_done(SCpnt);
+               return FAILED;
+       }
+
+       pScsiTm = (SCSITaskMgmt_t *) mf;
+       msg = (u32*)mf;
+
+       pScsiTm->TargetID = SCpnt->target;
+       pScsiTm->Bus = hd->port;
+       pScsiTm->ChainOffset = 0;
+       pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
+
+       pScsiTm->Reserved = 0;
+       pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
+       pScsiTm->Reserved1 = 0;
+       pScsiTm->MsgFlags = 0;
+
+       /* _TARGET_RESET goes to LUN 0 always! */
+       for (i = 0; i < 8; i++)
+               pScsiTm->LUN[i] = 0;
+
+       /* Control: No data direction, set task mgmt bit? */
+       for (i = 0; i < 7; i++)
+               pScsiTm->Reserved2[i] = 0;
+
+       pScsiTm->TaskMsgContext = cpu_to_le32(0);
+
+       wmb();
+
+/* MPI v0.10 requires SCSITaskMgmt requests be sent via Doorbell/handshake
+       mpt_put_msg_frame(hd->ioc->id, mf);
+*/
+/* FIXME!  Check return status! */
+       (void) mpt_send_handshake_request(ScsiTaskCtx, hd->ioc->id, sizeof(SCSITaskMgmt_t), msg);
+
+       wmb();
+
+       return SUCCESS;
+}
+
+#if 0  /* { */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mptscsih_host_reset - Perform a SCSI host adapter RESET!
+ *     new_eh variant
+ *     @SCpnt: Pointer to Scsi_Cmnd structure, IO which reset is due to
+ *
+ *     (linux Scsi_Host_Template.eh_host_reset_handler routine)
+ *
+ *     Returns SUCCESS or FAILED.
+ */
+int
+mptscsih_host_reset(Scsi_Cmnd * SCpnt)
+{
+       return FAILED;
+}
+#endif /* } */
+
+#else          /* MPT_SCSI old EH stuff... */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mptscsih_old_abort - Abort linux Scsi_Cmnd routine
+ *     @SCpnt: Pointer to Scsi_Cmnd structure, IO to be aborted
+ *
+ *     (linux Scsi_Host_Template.abort routine)
+ *
+ *     Returns SCSI_ABORT_{SUCCESS,BUSY,PENDING}.
+ */
+int
+mptscsih_old_abort(Scsi_Cmnd *SCpnt)
+{
+       MPT_SCSI_HOST           *hd;
+       MPT_FRAME_HDR           *mf;
+       struct tq_struct        *ptaskfoo;
+       unsigned long            flags;
+
+       printk(KERN_WARNING MYNAM ": Scheduling _ABORT SCSI IO (=%p)\n", SCpnt);
+       printk(KERN_WARNING MYNAM ": IOs outstanding = %d\n", atomic_read(&queue_depth));
+
+       if ((hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata) == NULL) {
+               SCpnt->result = DID_ABORT << 16;
+               SCpnt->scsi_done(SCpnt);
+               return SCSI_ABORT_SUCCESS;
+       }
+
+       /*
+        *  Check to see if there's already an ABORT queued for this guy.
+        */
+       mf = search_taskQ(0,SCpnt,MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK);
+       if (mf != NULL) {
+               return SCSI_ABORT_PENDING;
+       }
+
+       if ((mf = mpt_get_msg_frame(ScsiTaskCtx, hd->ioc->id)) == NULL) {
+/*             SCpnt->result = DID_SOFT_ERROR << 16;   */
+               SCpnt->result = STS_BUSY;
+               SCpnt->scsi_done(SCpnt);
+               return SCSI_ABORT_BUSY;
+       }
+
+       /*
+        *  Add ourselves to (end of) mpt_scsih_taskQ.
+        *  Check to see if our _bh is running.  If NOT, schedule it.
+        */
+       dslprintk((KERN_INFO MYNAM ": spinlock#2\n"));
+       spin_lock_irqsave(&mpt_scsih_taskQ_lock, flags);
+       Q_ADD_TAIL(&mpt_scsih_taskQ, &mf->u.frame.linkage, MPT_FRAME_HDR);
+       mpt_scsih_taskQ_cnt++;
+       /* Yikes - linkage! */
+/*     SCpnt->host_scribble = (unsigned char *)mf;     */
+       mf->u.frame.linkage.arg1 = MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK;
+       mf->u.frame.linkage.argp1 = SCpnt;
+       if (! mpt_scsih_taskQ_bh_active) {
+               mpt_scsih_taskQ_bh_active = 1;
+               /*
+                *  Oh how cute, no alloc/free/mgmt needed if we use
+                *  (bottom/unused portion of) MPT request frame.
+                */
+               ptaskfoo = (struct tq_struct *) ((u8*)mf + hd->ioc->req_sz - sizeof(*ptaskfoo));
+               ptaskfoo->sync = 0;
+               ptaskfoo->routine = mptscsih_taskmgmt_bh;
+               ptaskfoo->data = SCpnt;
+
+               SCHEDULE_TASK(ptaskfoo);
+       }
+       spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags);
+
+       return SCSI_ABORT_PENDING;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mptscsih_old_reset - Perform a SCSI BUS_RESET!
+ *     @SCpnt: Pointer to Scsi_Cmnd structure, IO which reset is due to
+ *     @reset_flags: (not used?)
+ *
+ *     (linux Scsi_Host_Template.reset routine)
+ *
+ *     Returns SCSI_RESET_{SUCCESS,PUNT,PENDING}.
+ */
+int
+mptscsih_old_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags)
+{
+       MPT_SCSI_HOST           *hd;
+       MPT_FRAME_HDR           *mf;
+       struct tq_struct        *ptaskfoo;
+       unsigned long            flags;
+
+       printk(KERN_WARNING MYNAM ": Scheduling _BUS_RESET (=%p)\n", SCpnt);
+       printk(KERN_WARNING MYNAM ": IOs outstanding = %d\n", atomic_read(&queue_depth));
+
+       if ((hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata) == NULL) {
+               SCpnt->result = DID_RESET << 16;
+               SCpnt->scsi_done(SCpnt);
+               return SCSI_RESET_SUCCESS;
+       }
+
+       /*
+        *  Check to see if there's already a BUS_RESET queued for this guy.
+        */
+       mf = search_taskQ(0,SCpnt,MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS);
+       if (mf != NULL) {
+               return SCSI_RESET_PENDING;
+       }
+
+       if ((mf = mpt_get_msg_frame(ScsiTaskCtx, hd->ioc->id)) == NULL) {
+/*             SCpnt->result = DID_SOFT_ERROR << 16;   */
+               SCpnt->result = STS_BUSY;
+               SCpnt->scsi_done(SCpnt);
+               return SCSI_RESET_PUNT;
+       }
+
+       /*
+        *  Add ourselves to (end of) mpt_scsih_taskQ.
+        *  Check to see if our _bh is running.  If NOT, schedule it.
+        */
+       dslprintk((KERN_INFO MYNAM ": spinlock#3\n"));
+       spin_lock_irqsave(&mpt_scsih_taskQ_lock, flags);
+       Q_ADD_TAIL(&mpt_scsih_taskQ, &mf->u.frame.linkage, MPT_FRAME_HDR);
+       mpt_scsih_taskQ_cnt++;
+       /* Yikes - linkage! */
+/*     SCpnt->host_scribble = (unsigned char *)mf;     */
+       mf->u.frame.linkage.arg1 = MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS;
+       mf->u.frame.linkage.argp1 = SCpnt;
+       if (! mpt_scsih_taskQ_bh_active) {
+               mpt_scsih_taskQ_bh_active = 1;
+               /*
+                *  Oh how cute, no alloc/free/mgmt needed if we use
+                *  (bottom/unused portion of) MPT request frame.
+                */
+               ptaskfoo = (struct tq_struct *) ((u8*)mf + hd->ioc->req_sz - sizeof(*ptaskfoo));
+               ptaskfoo->sync = 0;
+               ptaskfoo->routine = mptscsih_taskmgmt_bh;
+               ptaskfoo->data = SCpnt;
+
+               SCHEDULE_TASK(ptaskfoo);
+       }
+       spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags);
+
+       return SCSI_RESET_PENDING;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     mptscsih_taskmgmt_bh - SCSI task mgmt bottom half handler
+ *     @sc: (unused)
+ *
+ *     This routine (thread) is active whenever there are any outstanding
+ *     SCSI task management requests for a SCSI host adapter.
+ *     IMPORTANT!  This routine is scheduled therefore should never be
+ *     running in ISR context.  i.e., it's safe to sleep here.
+ */
+void
+mptscsih_taskmgmt_bh(void *sc)
+{
+       Scsi_Cmnd       *SCpnt;
+       MPT_FRAME_HDR   *mf;
+       SCSITaskMgmt_t  *pScsiTm;
+       MPT_SCSI_HOST   *hd;
+       u32              ctx2abort = 0;
+       int              i;
+       unsigned long    flags;
+       u8               task_type;
+
+       dslprintk((KERN_INFO MYNAM ": spinlock#4\n"));
+       spin_lock_irqsave(&mpt_scsih_taskQ_lock, flags);
+       mpt_scsih_taskQ_bh_active = 1;
+       spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags);
+
+       while (1) {
+               /*
+                *  We MUST remove item from taskQ *before* we format the
+                *  frame as a SCSITaskMgmt request and send it down to the IOC.
+                */
+               dslprintk((KERN_INFO MYNAM ": spinlock#5\n"));
+               spin_lock_irqsave(&mpt_scsih_taskQ_lock, flags);
+               if (Q_IS_EMPTY(&mpt_scsih_taskQ)) {
+                       spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags);
+                       break;
+               }
+               mf = mpt_scsih_taskQ.head;
+               Q_DEL_ITEM(&mf->u.frame.linkage);
+               mpt_scsih_taskQ_cnt--;
+               mpt_scsih_active_taskmgmt_mf = mf;
+               spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags);
+
+               SCpnt = (Scsi_Cmnd*)mf->u.frame.linkage.argp1;
+               if (SCpnt == NULL) {
+                       printk(KERN_ERR MYNAM ": ERROR: TaskMgmt has NULL SCpnt! (%p:%p)\n", mf, SCpnt);
+                       continue;
+               }
+               pScsiTm = (SCSITaskMgmt_t *) mf;
+
+               for (i = 0; i < 8; i++) {
+                       pScsiTm->LUN[i] = 0;
+               }
+
+               task_type = mf->u.frame.linkage.arg1;
+               if (task_type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK)
+               {
+                       printk(KERN_WARNING MYNAM ": Attempting _ABORT SCSI IO! (mf:sc=%p:%p)\n", mf, SCpnt);
+
+                       /* Most important!  Set TaskMsgContext to SCpnt's MsgContext!
+                        * (the IO to be ABORT'd)
+                        *
+                        * NOTE: Since we do not byteswap MsgContext, we do not
+                        *       swap it here either.  It is an opaque cookie to
+                        *       the controller, so it does not matter. -DaveM
+                        */
+                       ctx2abort = SCPNT_TO_MSGCTX(SCpnt);
+                       pScsiTm->LUN[1] = SCpnt->lun;
+               }
+               else if (task_type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS)
+               {
+                       printk(KERN_WARNING MYNAM ": Attempting _BUS_RESET! (against SCSI IO mf:sc=%p:%p)\n", mf, SCpnt);
+               }
+#if 0
+               else if (task_type == MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET) {}
+               else if (task_type == MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET) {}
+#endif
+
+               printk(KERN_WARNING MYNAM ": IOs outstanding = %d\n", atomic_read(&queue_depth));
+
+               hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata;
+
+               pScsiTm->TargetID = SCpnt->target;
+               pScsiTm->Bus = hd->port;
+               pScsiTm->ChainOffset = 0;
+               pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
+
+               pScsiTm->Reserved = 0;
+               pScsiTm->TaskType = task_type;
+               pScsiTm->Reserved1 = 0;
+               pScsiTm->MsgFlags = 0;
+
+               for (i = 0; i < 7; i++)
+                       pScsiTm->Reserved2[i] = 0;
+
+               dprintk((KERN_INFO MYNAM ":DbG: ctx2abort = %08x\n", ctx2abort));
+               pScsiTm->TaskMsgContext = ctx2abort;
+
+               /* Control: No data direction, set task mgmt bit? */
+
+               /*
+                *  As of MPI v0.10 this request can NOT be sent (normally)
+                *  via FIFOs.  So we can't:
+                *              mpt_put_msg_frame(ScsiTaskCtx, hd->ioc->id, mf);
+                *  SCSITaskMgmt requests MUST be sent ONLY via
+                *  Doorbell/handshake now.   :-(
+                *
+                *  FIXME!  Check return status!
+                */
+               (void) mpt_send_handshake_request(ScsiTaskCtx, hd->ioc->id, sizeof(SCSITaskMgmt_t), (u32*)mf);
+
+               /* Spin-Wait for TaskMgmt complete!!! */
+               while (mpt_scsih_active_taskmgmt_mf != NULL) {
+                       current->state = TASK_INTERRUPTIBLE;
+                       schedule_timeout(HZ/2);
+               }
+       }
+
+       dslprintk((KERN_INFO MYNAM ": spinlock#6\n"));
+       spin_lock_irqsave(&mpt_scsih_taskQ_lock, flags);
+       mpt_scsih_taskQ_bh_active = 0;
+       spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags);
+
+       return;
+}
+
+#endif         /* } */
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mptscsih_taskmgmt_complete - Callback routine, gets registered to
+ *     Fusion MPT base driver
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @mf: Pointer to SCSI task mgmt request frame
+ *     @r: Pointer to SCSI task mgmt reply frame
+ *
+ *     This routine is called from mptbase.c::mpt_interrupt() at the completion
+ *     of any SCSI task management request.
+ *     This routine is registered with the MPT (base) driver at driver
+ *     load/init time via the mpt_register() API call.
+ *
+ *     Returns 1 indicating alloc'd request frame ptr should be freed.
+ */
+static int
+mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r)
+{
+       SCSITaskMgmtReply_t     *pScsiTmReply;
+       SCSITaskMgmt_t          *pScsiTmReq;
+       u8                       tmType;
+#ifndef MPT_SCSI_USE_NEW_EH
+       unsigned long            flags;
+#endif
+
+       dprintk((KERN_INFO MYNAM ": SCSI TaskMgmt completed mf=%p, r=%p\n",
+                mf, r));
+
+#ifndef MPT_SCSI_USE_NEW_EH
+       dslprintk((KERN_INFO MYNAM ": spinlock#7\n"));
+       spin_lock_irqsave(&mpt_scsih_taskQ_lock, flags);
+       /* It better be the active one! */
+       if (mf != mpt_scsih_active_taskmgmt_mf) {
+               printk(KERN_ERR MYNAM ": ERROR! Non-active TaskMgmt (=%p) completed!\n", mf);
+               mpt_scsih_active_taskmgmt_mf = NULL;
+               spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags);
+               return 1;
+       }
+
+#ifdef MPT_DEBUG
+       if ((mf == NULL) ||
+           (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) {
+               printk(KERN_ERR MYNAM ": ERROR! NULL or BAD TaskMgmt ptr (=%p)!\n", mf);
+               mpt_scsih_active_taskmgmt_mf = NULL;
+               spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags);
+               return 1;
+       }
+#endif
+       spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags);
+#endif
+
+       if (r != NULL) {
+               pScsiTmReply = (SCSITaskMgmtReply_t*)r;
+               pScsiTmReq = (SCSITaskMgmt_t*)mf;
+
+               /* Figure out if this was ABORT_TASK, TARGET_RESET, or BUS_RESET! */
+               tmType = pScsiTmReq->TaskType;
+
+               dprintk((KERN_INFO MYNAM ": TaskType = %d\n", tmType));
+               dprintk((KERN_INFO MYNAM ": TerminationCount = %d\n",
+                        le32_to_cpu(pScsiTmReply->TerminationCount)));
+
+               /* Error?  (anything non-zero?) */
+               if (*(u32 *)&pScsiTmReply->Reserved2[0]) {
+                       dprintk((KERN_INFO MYNAM ": SCSI TaskMgmt (%d) - Oops!\n", tmType));
+                       dprintk((KERN_INFO MYNAM ": IOCStatus = %04xh\n",
+                                le16_to_cpu(pScsiTmReply->IOCStatus)));
+                       dprintk((KERN_INFO MYNAM ": IOCLogInfo = %08xh\n",
+                                le32_to_cpu(pScsiTmReply->IOCLogInfo)));
+               } else {
+                       dprintk((KERN_INFO MYNAM ": SCSI TaskMgmt (%d) SUCCESS!\n", tmType));
+               }
+       }
+
+#ifndef MPT_SCSI_USE_NEW_EH
+       /*
+        *  Signal to _bh thread that we finished.
+        */
+       dslprintk((KERN_INFO MYNAM ": spinlock#8\n"));
+       spin_lock_irqsave(&mpt_scsih_taskQ_lock, flags);
+       mpt_scsih_active_taskmgmt_mf = NULL;
+       spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags);
+#endif
+
+       return 1;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     This is anyones guess quite frankly.
+ */
+
+int
+mptscsih_bios_param(Disk * disk, kdev_t dev, int *ip)
+{
+       int size;
+
+       size = disk->capacity;
+       ip[0] = 64;                             /* heads                        */
+       ip[1] = 32;                             /* sectors                      */
+       if ((ip[2] = size >> 11) > 1024) {      /* cylinders, test for big disk */
+               ip[0] = 255;                    /* heads                        */
+               ip[1] = 63;                     /* sectors                      */
+               ip[2] = size / (255 * 63);      /* cylinders                    */
+       }
+       return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *  Private routines...
+ */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/* 19991030 -sralston
+ *  Return absolute SCSI data direction:
+ *     1 = _DATA_OUT
+ *     0 = _DIR_NONE
+ *    -1 = _DATA_IN
+ */
+static int
+mptscsih_io_direction(Scsi_Cmnd *cmd)
+{
+       switch (cmd->cmnd[0]) {
+       /*  _DATA_OUT commands  */
+       case WRITE_6:           case WRITE_10:          case WRITE_12:
+       case WRITE_LONG:        case WRITE_SAME:        case WRITE_BUFFER:
+       case WRITE_VERIFY:      case WRITE_VERIFY_12:
+       case COMPARE:           case COPY:              case COPY_VERIFY:
+       case SEARCH_EQUAL:      case SEARCH_HIGH:       case SEARCH_LOW:
+       case SEARCH_EQUAL_12:   case SEARCH_HIGH_12:    case SEARCH_LOW_12:
+       case MODE_SELECT:       case MODE_SELECT_10:    case LOG_SELECT:
+       case SEND_DIAGNOSTIC:   case CHANGE_DEFINITION: case UPDATE_BLOCK:
+       case SET_WINDOW:        case MEDIUM_SCAN:       case SEND_VOLUME_TAG:
+       case REASSIGN_BLOCKS:
+       case PERSISTENT_RESERVE_OUT:
+       case 0xea:
+               return 1;
+
+       /*  No data transfer commands  */
+       case SEEK_6:            case SEEK_10:
+       case RESERVE:           case RELEASE:
+       case TEST_UNIT_READY:
+       case START_STOP:
+       case ALLOW_MEDIUM_REMOVAL:
+               return 0;
+
+       /*  Conditional data transfer commands  */
+       case FORMAT_UNIT:
+               if (cmd->cmnd[1] & 0x10)        /* FmtData (data out phase)? */
+                       return 1;
+               else
+                       return 0;
+
+       case VERIFY:
+               if (cmd->cmnd[1] & 0x02)        /* VERIFY:BYTCHK (data out phase)? */
+                       return 1;
+               else
+                       return 0;
+
+       case RESERVE_10:
+               if (cmd->cmnd[1] & 0x03)        /* RESERSE:{LongID|Extent} (data out phase)? */
+                       return 1;
+               else
+                       return 0;
+
+#if 0
+       case REZERO_UNIT:       /* (or REWIND) */
+       case SPACE:
+       case ERASE:             case ERASE_10:
+       case SYNCHRONIZE_CACHE:
+       case LOCK_UNLOCK_CACHE:
+#endif
+
+       /*  Must be data _IN!  */
+       default:
+               return -1;
+       }
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static void
+copy_sense_data(Scsi_Cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply)
+{
+       MPT_SCSI_DEV    *mpt_sdev = NULL;
+       u32              sense_count = le32_to_cpu(pScsiReply->SenseCount);
+       char             devFoo[32];
+       IO_Info_t        thisIo;
+
+       if (sc && sc->device)
+               mpt_sdev = (MPT_SCSI_DEV*) sc->device->hostdata;
+
+       if (sense_count) {
+               u8 *sense_data;
+               int req_index;
+
+               /* Copy the sense received into the scsi command block. */
+               req_index = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
+               sense_data = ((u8 *)hd->ioc->sense_buf_pool + (req_index * 256));
+               memcpy(sc->sense_buffer, sense_data, SNS_LEN(sc));
+               /* Cache SenseData for this SCSI device! */
+               if (mpt_sdev) {
+                       memcpy(mpt_sdev->CachedSense.data, sense_data, sense_count);
+                       mpt_sdev->sense_sz = sense_count;
+               }
+       } else {
+               dprintk((KERN_INFO MYNAM ": Hmmm... SenseData len=0! (?)\n"));
+       }
+
+
+       thisIo.cdbPtr = sc->cmnd;
+       thisIo.sensePtr = sc->sense_buffer;
+       thisIo.SCSIStatus = pScsiReply->SCSIStatus;
+       thisIo.DoDisplay = 1;
+       sprintf(devFoo, "ioc%d,scsi%d:%d", hd->ioc->id, sc->target, sc->lun);
+       thisIo.DevIDStr = devFoo;
+/* fubar */
+       thisIo.dataPtr = NULL;
+       thisIo.inqPtr = NULL;
+       if (sc->device) {
+               thisIo.inqPtr = sc->device->vendor-8;           /* FIXME!!! */
+       }
+       (void) mpt_ScsiHost_ErrorReport(&thisIo);
+
+       return;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static u32
+SCPNT_TO_MSGCTX(Scsi_Cmnd *sc)
+{
+       MPT_SCSI_HOST *hd;
+       MPT_FRAME_HDR *mf;
+       int i;
+
+       hd = (MPT_SCSI_HOST *) sc->host->hostdata;
+
+       for (i = 0; i < hd->ioc->req_depth; i++) {
+               if (hd->ScsiLookup[i] == sc) {
+                       mf = MPT_INDEX_2_MFPTR(hd->ioc, i);
+                       return mf->u.frame.hwhdr.msgctxu.MsgContext;
+               }
+       }
+
+       return -1;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+/* see mptscsih.h */
+
+#ifdef MPT_SCSIHOST_NEED_ENTRY_EXIT_HOOKUPS
+       static Scsi_Host_Template driver_template = MPT_SCSIHOST;
+#      include "../../scsi/scsi_module.c"
+#endif
+
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
+{
+       u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
+
+       dprintk((KERN_INFO MYNAM ": MPT event (=%02Xh) routed to SCSI host driver!\n", event));
+
+       switch (event) {
+       case MPI_EVENT_UNIT_ATTENTION:                  /* 03 */
+               /* FIXME! */
+               break;
+       case MPI_EVENT_IOC_BUS_RESET:                   /* 04 */
+               /* FIXME! */
+               break;
+       case MPI_EVENT_EXT_BUS_RESET:                   /* 05 */
+               /* FIXME! */
+               break;
+       case MPI_EVENT_LOGOUT:                          /* 09 */
+               /* FIXME! */
+               break;
+
+               /*
+                *  CHECKME! Don't think we need to do
+                *  anything for these, but...
+                */
+       case MPI_EVENT_RESCAN:                          /* 06 */
+       case MPI_EVENT_LINK_STATUS_CHANGE:              /* 07 */
+       case MPI_EVENT_LOOP_STATE_CHANGE:               /* 08 */
+               /*
+                *  CHECKME!  Falling thru...
+                */
+
+       case MPI_EVENT_NONE:                            /* 00 */
+       case MPI_EVENT_LOG_DATA:                        /* 01 */
+       case MPI_EVENT_STATE_CHANGE:                    /* 02 */
+       case MPI_EVENT_EVENT_CHANGE:                    /* 0A */
+       default:
+               dprintk((KERN_INFO MYNAM ": Ignoring event (=%02Xh)\n", event));
+               break;
+       }
+
+       return 1;               /* currently means nothing really */
+}
+
+#if 0          /* { */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     scsiherr.c - Fusion MPT SCSI Host driver error handling/reporting.
+ *
+ *     drivers/message/fusion/scsiherr.c
+ */
+
+//extern const char    **mpt_ScsiOpcodesPtr;   /* needed by mptscsih.c */
+//extern ASCQ_Table_t   *mpt_ASCQ_TablePtr;
+//extern int             mpt_ASCQ_TableSz;
+
+/*  Lie!  */
+#define MYNAM  "mptscsih"
+
+#endif         /* } */
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *  Private data...
+ */
+static ASCQ_Table_t *mptscsih_ASCQ_TablePtr;
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/* old symsense.c stuff... */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * Private data...
+ * To protect ourselves against those that would pass us bogus pointers
+ */
+static u8 dummyInqData[SCSI_STD_INQUIRY_BYTES]
+    = { 0x1F, 0x00, 0x00, 0x00,
+       0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+static u8 dummySenseData[SCSI_STD_SENSE_BYTES]
+    = { 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00 };
+static u8 dummyCDB[16]
+    = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+static u8 dummyScsiData[16]
+    = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+#if 0
+static const char *PeripheralDeviceTypeString[32] = {
+       "Direct-access",                /* 00h */
+       "Sequential-access",            /* 01h */
+       "Printer",                      /* 02h */
+       "Processor",                    /* 03h */
+                       /*"Write-Once-Read-Multiple",*/ /* 04h */
+       "WORM",                         /* 04h */
+       "CD-ROM",                       /* 05h */
+       "Scanner",                      /* 06h */
+       "Optical memory",               /* 07h */
+       "Media Changer",                /* 08h */
+       "Communications",               /* 09h */
+       "(Graphics arts pre-press)",    /* 0Ah */
+       "(Graphics arts pre-press)",    /* 0Bh */
+       "Array controller",             /* 0Ch */
+       "Enclosure services",           /* 0Dh */
+       "Simplified direct-access",     /* 0Eh */
+       "Reserved-0Fh",                 /* 0Fh */
+       "Reserved-10h",                 /* 10h */
+       "Reserved-11h",                 /* 11h */
+       "Reserved-12h",                 /* 12h */
+       "Reserved-13h",                 /* 13h */
+       "Reserved-14h",                 /* 14h */
+       "Reserved-15h",                 /* 15h */
+       "Reserved-16h",                 /* 16h */
+       "Reserved-17h",                 /* 17h */
+       "Reserved-18h",                 /* 18h */
+       "Reserved-19h",                 /* 19h */
+       "Reserved-1Ah",                 /* 1Ah */
+       "Reserved-1Bh",                 /* 1Bh */
+       "Reserved-1Ch",                 /* 1Ch */
+       "Reserved-1Dh",                 /* 1Dh */
+       "Reserved-1Eh",                 /* 1Eh */
+       "Unknown"                       /* 1Fh */
+};
+#endif
+
+static char *ScsiStatusString[] = {
+       "GOOD",                                 /* 00h */
+       NULL,                                   /* 01h */
+       "CHECK CONDITION",                      /* 02h */
+       NULL,                                   /* 03h */
+       "CONDITION MET",                        /* 04h */
+       NULL,                                   /* 05h */
+       NULL,                                   /* 06h */
+       NULL,                                   /* 07h */
+       "BUSY",                                 /* 08h */
+       NULL,                                   /* 09h */
+       NULL,                                   /* 0Ah */
+       NULL,                                   /* 0Bh */
+       NULL,                                   /* 0Ch */
+       NULL,                                   /* 0Dh */
+       NULL,                                   /* 0Eh */
+       NULL,                                   /* 0Fh */
+       "INTERMEDIATE",                         /* 10h */
+       NULL,                                   /* 11h */
+       NULL,                                   /* 12h */
+       NULL,                                   /* 13h */
+       "INTERMEDIATE-CONDITION MET",           /* 14h */
+       NULL,                                   /* 15h */
+       NULL,                                   /* 16h */
+       NULL,                                   /* 17h */
+       "RESERVATION CONFLICT",                 /* 18h */
+       NULL,                                   /* 19h */
+       NULL,                                   /* 1Ah */
+       NULL,                                   /* 1Bh */
+       NULL,                                   /* 1Ch */
+       NULL,                                   /* 1Dh */
+       NULL,                                   /* 1Eh */
+       NULL,                                   /* 1Fh */
+       NULL,                                   /* 20h */
+       NULL,                                   /* 21h */
+       "COMMAND TERMINATED",                   /* 22h */
+       NULL,                                   /* 23h */
+       NULL,                                   /* 24h */
+       NULL,                                   /* 25h */
+       NULL,                                   /* 26h */
+       NULL,                                   /* 27h */
+       "TASK SET FULL",                        /* 28h */
+       NULL,                                   /* 29h */
+       NULL,                                   /* 2Ah */
+       NULL,                                   /* 2Bh */
+       NULL,                                   /* 2Ch */
+       NULL,                                   /* 2Dh */
+       NULL,                                   /* 2Eh */
+       NULL,                                   /* 2Fh */
+       "ACA ACTIVE",                           /* 30h */
+       NULL
+};
+
+static const char *ScsiCommonOpString[] = {
+       "TEST UNIT READY",                      /* 00h */
+       "REZERO UNIT (REWIND)",                 /* 01h */
+       NULL,                                   /* 02h */
+       "REQUEST_SENSE",                        /* 03h */
+       "FORMAT UNIT (MEDIUM)",                 /* 04h */
+       "READ BLOCK LIMITS",                    /* 05h */
+       NULL,                                   /* 06h */
+       "REASSIGN BLOCKS",                      /* 07h */
+       "READ(6)",                              /* 08h */
+       NULL,                                   /* 09h */
+       "WRITE(6)",                             /* 0Ah */
+       "SEEK(6)",                              /* 0Bh */
+       NULL,                                   /* 0Ch */
+       NULL,                                   /* 0Dh */
+       NULL,                                   /* 0Eh */
+       "READ REVERSE",                         /* 0Fh */
+       "WRITE_FILEMARKS",                      /* 10h */
+       "SPACE(6)",                             /* 11h */
+       "INQUIRY",                              /* 12h */
+       NULL
+};
+
+static const char *SenseKeyString[] = {
+       "NO SENSE",                             /* 0h */
+       "RECOVERED ERROR",                      /* 1h */
+       "NOT READY",                            /* 2h */
+       "MEDIUM ERROR",                         /* 3h */
+       "HARDWARE ERROR",                       /* 4h */
+       "ILLEGAL REQUEST",                      /* 5h */
+       "UNIT ATTENTION",                       /* 6h */
+       "DATA PROTECT",                         /* 7h */
+       "BLANK CHECK",                          /* 8h */
+       "VENDOR-SPECIFIC",                      /* 9h */
+       "ABORTED COPY",                         /* Ah */
+       "ABORTED COMMAND",                      /* Bh */
+       "EQUAL (obsolete)",                     /* Ch */
+       "VOLUME OVERFLOW",                      /* Dh */
+       "MISCOMPARE",                           /* Eh */
+       "RESERVED",                             /* Fh */
+       NULL
+};
+
+#define SPECIAL_ASCQ(c,q) \
+       (((c) == 0x40 && (q) != 0x00) || ((c) == 0x4D) || ((c) == 0x70))
+
+#if 0
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *  Sense_Key_Specific() - If Sense_Key_Specific_Valid bit is set,
+ *                        then print additional information via
+ *                        a call to SDMS_SystemAlert().
+ *
+ *  Return: nothing
+ */
+static void Sense_Key_Specific(IO_Info_t *ioop, char *msg1)
+{
+       u8      *sd;
+       u8       BadValue;
+       u8       SenseKey;
+       int      Offset;
+       int      len = strlen(msg1);
+
+       sd = ioop->sensePtr;
+       if (SD_Additional_Sense_Length(sd) < 8)
+               return;
+
+       SenseKey = SD_Sense_Key(sd);
+
+       if (SD_Sense_Key_Specific_Valid(sd)) {
+               if (SenseKey == SK_ILLEGAL_REQUEST) {
+                       Offset = SD_Bad_Byte(sd);
+                       if (SD_Was_Illegal_Request(sd)) {
+                               BadValue = ioop->cdbPtr[Offset];
+                               len += sprintf(msg1+len, "\n  Illegal CDB value=%02Xh found at CDB ",
+                                               BadValue);
+               } else {
+                       BadValue = ioop->dataPtr[Offset];
+                       len += sprintf(msg1+len, "\n  Illegal DATA value=%02Xh found at DATA ",
+                                       BadValue);
+               }
+               len += sprintf(msg1+len, "byte=%02Xh", Offset);
+               if (SD_SKS_Bit_Pointer_Valid(sd))
+                       len += sprintf(msg1+len, "/bit=%1Xh", SD_SKS_Bit_Pointer(sd));
+               } else if ((SenseKey == SK_RECOVERED_ERROR) ||
+                          (SenseKey == SK_HARDWARE_ERROR) ||
+                          (SenseKey == SK_MEDIUM_ERROR)) {
+                       len += sprintf(msg1+len, "\n  Recovery algorithm Actual_Retry_Count=%02Xh",
+                       SD_Actual_Retry_Count(sd));
+               }
+       }
+}
+#endif
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int dump_cdb(char *foo, unsigned char *cdb)
+{
+       int i, grpCode, cdbLen;
+       int l = 0;
+
+       grpCode = cdb[0] >> 5;
+       if (grpCode < 1)
+               cdbLen = 6;
+       else if (grpCode < 3)
+               cdbLen = 10;
+       else if (grpCode == 5)
+               cdbLen = 12;
+       else
+               cdbLen = 16;
+
+       for (i=0; i < cdbLen; i++)
+               l += sprintf(foo+l, " %02X", cdb[i]);
+
+       return l;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int dump_sd(char *foo, unsigned char *sd)
+{
+       int snsLen = 8 + SD_Additional_Sense_Length(sd);
+       int l = 0;
+       int i;
+
+       for (i=0; i < MIN(snsLen,18); i++)
+               l += sprintf(foo+l, " %02X", sd[i]);
+       l += sprintf(foo+l, "%s", snsLen>18 ? " ..." : "");
+
+       return l;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*  Do ASC/ASCQ lookup/grindage to English readable string(s)  */
+static const char * ascq_set_strings_4max(
+               u8 ASC, u8 ASCQ,
+               const char **s1, const char **s2, const char **s3, const char **s4)
+{
+       static const char *asc_04_part1_string = "LOGICAL UNIT ";
+       static const char *asc_04_part2a_string = "NOT READY, ";
+       static const char *asc_04_part2b_string = "IS ";
+       static const char *asc_04_ascq_NN_part3_strings[] = {   /* ASC ASCQ (hex) */
+         "CAUSE NOT REPORTABLE",                               /* 04 00 */
+         "IN PROCESS OF BECOMING READY",                       /* 04 01 */
+         "INITIALIZING CMD. REQUIRED",                         /* 04 02 */
+         "MANUAL INTERVENTION REQUIRED",                       /* 04 03 */
+         /* Add        " IN PROGRESS" to all the following... */
+         "FORMAT",                                             /* 04 04 */
+         "REBUILD",                                            /* 04 05 */
+         "RECALCULATION",                                      /* 04 06 */
+         "OPERATION",                                          /* 04 07 */
+         "LONG WRITE",                                         /* 04 08 */
+         "SELF-TEST",                                          /* 04 09 */
+         NULL
+       };
+       static char *asc_04_part4_string = " IN PROGRESS";
+
+       static char *asc_29_ascq_NN_strings[] = {               /* ASC ASCQ (hex) */
+         "POWER ON, RESET, OR BUS DEVICE RESET OCCURRED",      /* 29 00 */
+         "POWER ON OCCURRED",                                  /* 29 01 */
+         "SCSI BUS RESET OCCURRED",                            /* 29 02 */
+         "BUS DEVICE RESET FUNCTION OCCURRED",                 /* 29 03 */
+         "DEVICE INTERNAL RESET",                              /* 29 04 */
+         "TRANSCEIVER MODE CHANGED TO SINGLE-ENDED",           /* 29 05 */
+         "TRANSCEIVER MODE CHANGED TO LVD",                    /* 29 06 */
+         NULL
+       };
+       static char *ascq_vendor_uniq = "(Vendor Unique)";
+       static char *ascq_noone = "(no matching ASC/ASCQ description found)";
+       int idx;
+
+       *s1 = *s2 = *s3 = *s4 = "";             /* set'em all to the empty "" string */
+
+       /* CHECKME! Need lock/sem?
+        *  Update and examine for isense module presense.
+        */
+       mptscsih_ASCQ_TablePtr = (ASCQ_Table_t *)mpt_v_ASCQ_TablePtr;
+
+       if (mptscsih_ASCQ_TablePtr == NULL) {
+               /* 2nd chances... */
+               if (ASC == 0x04 && (ASCQ < sizeof(asc_04_ascq_NN_part3_strings)/sizeof(char*)-1)) {
+                       *s1 = asc_04_part1_string;
+                       *s2 = (ASCQ == 0x01) ? asc_04_part2b_string : asc_04_part2a_string;
+                       *s3 = asc_04_ascq_NN_part3_strings[ASCQ];
+                       /* check for " IN PROGRESS" ones */
+                       if (ASCQ >= 0x04)
+                               *s4 = asc_04_part4_string;
+               } else if (ASC == 0x29 && (ASCQ < sizeof(asc_29_ascq_NN_strings)/sizeof(char*)-1))
+                       *s1 = asc_29_ascq_NN_strings[ASCQ];
+               /*
+                *      else { leave all *s[1-4] values pointing to the empty "" string }
+                */
+               return *s1;
+       }
+
+       /*
+        *  Need to check ASC here; if it is "special," then
+        *  the ASCQ is variable, and indicates failed component number.
+        *  We must treat the ASCQ as a "don't care" while searching the
+        *  mptscsih_ASCQ_Table[] by masking it off, and then restoring it later
+        *  on when we actually need to identify the failed component.
+        */
+       if (SPECIAL_ASCQ(ASC,ASCQ))
+               ASCQ = 0xFF;
+
+       /*  OK, now search mptscsih_ASCQ_Table[] for a matching entry  */
+       for (idx = 0; mptscsih_ASCQ_TablePtr && idx < mpt_ASCQ_TableSz; idx++)
+               if ((ASC == mptscsih_ASCQ_TablePtr[idx].ASC) && (ASCQ == mptscsih_ASCQ_TablePtr[idx].ASCQ))
+                       return (*s1 = mptscsih_ASCQ_TablePtr[idx].Description);
+
+       if ((ASC >= 0x80) || (ASCQ >= 0x80))
+               *s1 = ascq_vendor_uniq;
+       else
+               *s1 = ascq_noone;
+
+       return *s1;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *  SCSI Error Report; desired output format...
+ *---
+SCSI Error Report =-=-=-=-=-=-=-=-=-=-=-=-=-= (ioc0,scsi0:0)
+  SCSI_Status=02h (CHECK CONDITION)
+  Original_CDB[]: 00 00 00 00 00 00 - TestUnitReady
+  SenseData[12h]: 70 00 06 00 00 00 00 0A 00 00 00 00 29 00 03 00 00 00
+  SenseKey=6h (UNIT ATTENTION); FRU=03h
+  ASC/ASCQ=29h/00h, "POWER ON, RESET, OR BUS DEVICE RESET OCCURRED"
+ *---
+ */
+
+int mpt_ScsiHost_ErrorReport(IO_Info_t *ioop)
+{
+       char             foo[512];
+       char             buf2[32];
+       char            *statstr;
+       const char      *opstr;
+       int              sk             = SD_Sense_Key(ioop->sensePtr);
+       const char      *skstr          = SenseKeyString[sk];
+       unsigned char    asc            = SD_ASC(ioop->sensePtr);
+       unsigned char    ascq           = SD_ASCQ(ioop->sensePtr);
+       int              l;
+
+       /*
+        *  More quiet mode.
+        *  Filter out common, repetitive, warning-type errors...  like:
+        *    POWER ON (06,29/00 or 06,29/01),
+        *    SPINNING UP (02,04/01),
+        *    LOGICAL UNIT NOT SUPPORTED (05,25/00), etc.
+        */
+       if (    (sk==SK_UNIT_ATTENTION  && asc==0x29 && (ascq==0x00 || ascq==0x01))
+            || (sk==SK_NOT_READY       && asc==0x04 && ascq==0x01)
+            || (sk==SK_ILLEGAL_REQUEST && asc==0x25 && ascq==0x00)
+          )
+       {
+               /* Do nothing! */
+               return 0;
+       }
+
+       /*
+        *  Protect ourselves...
+        */
+       if (ioop->cdbPtr == NULL)
+               ioop->cdbPtr = dummyCDB;
+       if (ioop->sensePtr == NULL)
+               ioop->sensePtr = dummySenseData;
+       if (ioop->inqPtr == NULL)
+               ioop->inqPtr = dummyInqData;
+       if (ioop->dataPtr == NULL)
+               ioop->dataPtr = dummyScsiData;
+
+       statstr = NULL;
+       if ((ioop->SCSIStatus >= sizeof(ScsiStatusString)/sizeof(char*)-1) ||
+           ((statstr = (char*)ScsiStatusString[ioop->SCSIStatus]) == NULL)) {
+               (void) sprintf(buf2, "Bad-Reserved-%02Xh", ioop->SCSIStatus);
+               statstr = buf2;
+       }
+
+       opstr = NULL;
+       if (1+ioop->cdbPtr[0] <= sizeof(ScsiCommonOpString)/sizeof(char*))
+               opstr = ScsiCommonOpString[ioop->cdbPtr[0]];
+       else if (mpt_ScsiOpcodesPtr)
+               opstr = mpt_ScsiOpcodesPtr[ioop->cdbPtr[0]];
+
+       l = sprintf(foo, "SCSI Error Report =-=-= (%s)\n"
+         "  SCSI_Status=%02Xh (%s)\n"
+         "  Original_CDB[]:",
+                       ioop->DevIDStr,
+                       ioop->SCSIStatus,
+                       statstr);
+       l += dump_cdb(foo+l, ioop->cdbPtr);
+       if (opstr)
+               l += sprintf(foo+l, " - \"%s\"", opstr);
+       l += sprintf(foo+l, "\n  SenseData[%02Xh]:", 8+SD_Additional_Sense_Length(ioop->sensePtr));
+       l += dump_sd(foo+l, ioop->sensePtr);
+       l += sprintf(foo+l, "\n  SenseKey=%Xh (%s); FRU=%02Xh\n  ASC/ASCQ=%02Xh/%02Xh",
+                       sk, skstr, SD_FRU(ioop->sensePtr), asc, ascq );
+
+       {
+               const char      *x1, *x2, *x3, *x4;
+               x1 = x2 = x3 = x4 = "";
+               x1 = ascq_set_strings_4max(asc, ascq, &x1, &x2, &x3, &x4);
+               if (x1 != NULL) {
+                       if (x1[0] != '(')
+                               l += sprintf(foo+l, " \"%s%s%s%s\"", x1,x2,x3,x4);
+                       else
+                               l += sprintf(foo+l, " %s%s%s%s", x1,x2,x3,x4);
+               }
+       }
+
+#if 0
+       if (SPECIAL_ASCQ(asc,ascq))
+               l += sprintf(foo+l, " (%02Xh)", ascq);
+#endif
+
+       PrintF(("%s\n", foo));
+
+       return l;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
diff --git a/drivers/message/fusion/mptscsih.h b/drivers/message/fusion/mptscsih.h
new file mode 100644 (file)
index 0000000..ba14460
--- /dev/null
@@ -0,0 +1,247 @@
+/*
+ *  linux/drivers/message/fusion/mptscsih.h
+ *      High performance SCSI / Fibre Channel SCSI Host device driver.
+ *      For use with PCI chip/adapter(s):
+ *          LSIFC9xx/LSI409xx Fibre Channel
+ *      running LSI Logic Fusion MPT (Message Passing Technology) firmware.
+ *
+ *  Credits:
+ *      This driver would not exist if not for Alan Cox's development
+ *      of the linux i2o driver.
+ *
+ *      A huge debt of gratitude is owed to David S. Miller (DaveM)
+ *      for fixing much of the stupid and broken stuff in the early
+ *      driver while porting to sparc64 platform.  THANK YOU!
+ *
+ *      (see also mptbase.c)
+ *
+ *  Copyright (c) 1999-2001 LSI Logic Corporation
+ *  Originally By: Steven J. Ralston
+ *  (mailto:Steve.Ralston@lsil.com)
+ *
+ *  $Id: mptscsih.h,v 1.7 2001/01/11 16:56:43 sralston Exp $
+ */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; version 2 of the License.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    NO WARRANTY
+    THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+    CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+    LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+    MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+    solely responsible for determining the appropriateness of using and
+    distributing the Program and assumes all risks associated with its
+    exercise of rights under this Agreement, including but not limited to
+    the risks and costs of program errors, damage to or loss of data,
+    programs or equipment, and unavailability or interruption of operations.
+
+    DISCLAIMER OF LIABILITY
+    NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+    DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
+    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+    TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+    USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+    HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#ifndef SCSIHOST_H_INCLUDED
+#define SCSIHOST_H_INCLUDED
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+#include "linux/version.h"
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     SCSI Public stuff...
+ */
+
+#ifdef __sparc__
+#define MPT_SCSI_CAN_QUEUE     63
+#define MPT_SCSI_CMD_PER_LUN   63
+       /* FIXME!  Still investigating qd=64 hang on sparc64... */
+#else
+#define MPT_SCSI_CAN_QUEUE     64
+#define MPT_SCSI_CMD_PER_LUN   64
+#endif
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     Various bits and pieces broke within the lk-2.4.0-testN series:-(
+ *     So here are various HACKS to work around them.
+ */
+
+/*
+ *     Conditionalizing with "#ifdef MODULE/#endif" around:
+ *             static Scsi_Host_Template driver_template = XX;
+ *             #include <../../scsi/scsi_module.c>
+ *     lines was REMOVED @ lk-2.4.0-test9
+ *     Issue discovered 20001213 by: sshirron
+ */
+#define MPT_SCSIHOST_NEED_ENTRY_EXIT_HOOKUPS                   1
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,4,0)
+#      if LINUX_VERSION_CODE == KERNEL_VERSION(2,4,0)
+               /*
+                *      Super HACK!  -by sralston:-(
+                *      (good grief; heaven help me!)
+                */
+#              include <linux/capability.h>
+#              if !defined(CAP_LEASE) && !defined(MODULE)
+#                      undef MPT_SCSIHOST_NEED_ENTRY_EXIT_HOOKUPS
+#              endif
+#      else
+#              ifndef MODULE
+#                      undef MPT_SCSIHOST_NEED_ENTRY_EXIT_HOOKUPS
+#              endif
+#      endif
+#endif
+
+/*
+ *     tq_scheduler disappeared @ lk-2.4.0-test12
+ *     (right when <linux/sched.h> newly defined TQ_ACTIVE)
+ */
+#define HAVE_TQ_SCHED  1
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+#      include <linux/sched.h>
+#      ifdef TQ_ACTIVE
+#              undef HAVE_TQ_SCHED
+#      endif
+#endif
+#ifdef HAVE_TQ_SCHED
+#define SCHEDULE_TASK(x)               \
+       /*MOD_INC_USE_COUNT*/;          \
+       (x)->next = NULL;               \
+       queue_task(x, &tq_scheduler)
+#else
+#define SCHEDULE_TASK(x)               \
+       /*MOD_INC_USE_COUNT*/;          \
+       if (schedule_task(x) == 0) {    \
+               /*MOD_DEC_USE_COUNT*/;  \
+       }
+#endif
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+#define x_scsi_detect          mptscsih_detect
+#define x_scsi_release         mptscsih_release
+#define x_scsi_info            mptscsih_info
+#define x_scsi_queuecommand    mptscsih_qcmd
+#define x_scsi_abort           mptscsih_abort
+#define x_scsi_bus_reset       mptscsih_bus_reset
+#define x_scsi_dev_reset       mptscsih_dev_reset
+#define x_scsi_host_reset      mptscsih_host_reset
+#define x_scsi_bios_param      mptscsih_bios_param
+
+#define x_scsi_taskmgmt_bh     mptscsih_taskmgmt_bh
+#define x_scsi_old_abort       mptscsih_old_abort
+#define x_scsi_old_reset       mptscsih_old_reset
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     MPT SCSI Host / Initiator decls...
+ */
+extern int              x_scsi_detect(Scsi_Host_Template *);
+extern int              x_scsi_release(struct Scsi_Host *host);
+extern const char      *x_scsi_info(struct Scsi_Host *);
+/*extern       int              x_scsi_command(Scsi_Cmnd *);*/
+extern int              x_scsi_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+#ifdef MPT_SCSI_USE_NEW_EH
+extern int              x_scsi_abort(Scsi_Cmnd *);
+extern int              x_scsi_bus_reset(Scsi_Cmnd *);
+extern int              x_scsi_dev_reset(Scsi_Cmnd *);
+/*extern       int              x_scsi_host_reset(Scsi_Cmnd *);*/
+#else
+extern int              x_scsi_old_abort(Scsi_Cmnd *);
+extern int              x_scsi_old_reset(Scsi_Cmnd *, unsigned int);
+#endif
+extern int              x_scsi_bios_param(Disk *, kdev_t, int *);
+extern void             x_scsi_taskmgmt_bh(void *);
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
+#define PROC_SCSI_DECL
+#else
+#define PROC_SCSI_DECL  proc_name: "mptscsih",
+#endif
+
+#ifdef MPT_SCSI_USE_NEW_EH
+
+#define MPT_SCSIHOST {                                         \
+       next:                           NULL,                   \
+       PROC_SCSI_DECL                                          \
+       name:                           "MPT SCSI Host",        \
+       detect:                         x_scsi_detect,          \
+       release:                        x_scsi_release,         \
+       info:                           x_scsi_info,            \
+       command:                        NULL,                   \
+       queuecommand:                   x_scsi_queuecommand,    \
+       eh_strategy_handler:            NULL,                   \
+       eh_abort_handler:               x_scsi_abort,           \
+       eh_device_reset_handler:        x_scsi_dev_reset,       \
+       eh_bus_reset_handler:           x_scsi_bus_reset,       \
+       eh_host_reset_handler:          NULL,                   \
+       bios_param:                     x_scsi_bios_param,      \
+       can_queue:                      MPT_SCSI_CAN_QUEUE,     \
+       this_id:                        -1,                     \
+       sg_tablesize:                   25,                     \
+       cmd_per_lun:                    MPT_SCSI_CMD_PER_LUN,   \
+       unchecked_isa_dma:              0,                      \
+       use_clustering:                 ENABLE_CLUSTERING,      \
+       use_new_eh_code:                1                       \
+}
+
+#else
+
+#define MPT_SCSIHOST {                                         \
+       next:                           NULL,                   \
+       PROC_SCSI_DECL                                          \
+       name:                           "MPT SCSI Host",        \
+       detect:                         x_scsi_detect,          \
+       release:                        x_scsi_release,         \
+       info:                           x_scsi_info,            \
+       command:                        NULL,                   \
+       queuecommand:                   x_scsi_queuecommand,    \
+       abort:                          x_scsi_old_abort,       \
+       reset:                          x_scsi_old_reset,       \
+       bios_param:                     x_scsi_bios_param,      \
+       can_queue:                      MPT_SCSI_CAN_QUEUE,     \
+       this_id:                        -1,                     \
+       sg_tablesize:                   25,                     \
+       cmd_per_lun:                    MPT_SCSI_CMD_PER_LUN,   \
+       unchecked_isa_dma:              0,                      \
+       use_clustering:                 ENABLE_CLUSTERING       \
+}
+#endif
+
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+/*  include/scsi/scsi.h may not be quite complete...  */
+#ifndef RESERVE_10
+#define RESERVE_10             0x56
+#endif
+#ifndef RELEASE_10
+#define RELEASE_10             0x57
+#endif
+#ifndef PERSISTENT_RESERVE_IN
+#define PERSISTENT_RESERVE_IN  0x5e
+#endif
+#ifndef PERSISTENT_RESERVE_OUT
+#define PERSISTENT_RESERVE_OUT 0x5f
+#endif
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+#endif
+
diff --git a/drivers/message/fusion/scsi3.h b/drivers/message/fusion/scsi3.h
new file mode 100644 (file)
index 0000000..fbb4e37
--- /dev/null
@@ -0,0 +1,700 @@
+/*
+ *  linux/drivers/message/fusion/scsi3.h
+ *      SCSI-3 definitions and macros.
+ *      (Ultimately) SCSI-3 definitions; for now, inheriting
+ *      SCSI-2 definitions.
+ *
+ *  Copyright (c) 1996-2001 Steven J. Ralston
+ *  Written By: Steven J. Ralston (19960517)
+ *  (mailto:Steve.Ralston@lsil.com)
+ *
+ *  $Id: scsi3.h,v 1.4 2001/01/06 15:54:25 sralston Exp $
+ */
+
+#ifndef SCSI3_H_INCLUDED
+#define SCSI3_H_INCLUDED
+/***************************************************************************/
+
+/****************************************************************************
+ *
+ *  Includes
+ */
+#ifdef __KERNEL__
+#include <linux/types.h>
+#else
+    #ifndef U_STUFF_DEFINED
+    #define U_STUFF_DEFINED
+    typedef unsigned char u8;
+    typedef unsigned short u16;
+    typedef unsigned int u32;
+    #endif
+#endif
+
+/****************************************************************************
+ *
+ *  Defines
+ */
+
+/*
+ *    SCSI Commands
+ */
+#define CMD_TestUnitReady      0x00
+#define CMD_RezeroUnit         0x01  /* direct-access devices */
+#define CMD_Rewind             0x01  /* sequential-access devices */
+#define CMD_RequestSense       0x03
+#define CMD_FormatUnit         0x04
+#define CMD_ReassignBlock      0x07
+#define CMD_Read6              0x08
+#define CMD_Write6             0x0A
+#define CMD_WriteFilemark      0x10
+#define CMD_Space              0x11
+#define CMD_Inquiry            0x12
+#define CMD_ModeSelect6        0x15
+#define CMD_ModeSense6         0x1A
+#define CMD_Reserve6           0x16
+#define CMD_Release6           0x17
+#define CMD_Erase              0x19
+#define CMD_StartStopUnit      0x1b  /* direct-access devices */
+#define CMD_LoadUnload         0x1b  /* sequential-access devices */
+#define CMD_ReceiveDiagnostic  0x1C
+#define CMD_SendDiagnostic     0x1D
+#define CMD_ReadCapacity       0x25
+#define CMD_Read10             0x28
+#define CMD_Write10            0x2A
+#define CMD_WriteVerify        0x2E
+#define CMD_Verify             0x2F
+#define CMD_ReadDefectData     0x37
+#define CMD_LogSelect          0x4C
+#define CMD_LogSense           0x4D
+#define CMD_ModeSelect10       0x55
+#define CMD_Reserve10          0x56
+#define CMD_Release10          0x57
+#define CMD_ModeSense10        0x5A
+#define CMD_ReportLuns         0xA0
+
+/*
+ *    Control byte field
+ */
+#define CONTROL_BYTE_NACA_BIT  0x04
+#define CONTROL_BYTE_Flag_BIT  0x02
+#define CONTROL_BYTE_Link_BIT  0x01
+
+/*
+ *    SCSI Messages
+ */
+#define MSG_COMPLETE             0x00
+#define MSG_EXTENDED             0x01
+#define MSG_SAVE_POINTERS        0x02
+#define MSG_RESTORE_POINTERS     0x03
+#define MSG_DISCONNECT           0x04
+#define MSG_IDERROR              0x05
+#define MSG_ABORT                0x06
+#define MSG_REJECT               0x07
+#define MSG_NOP                  0x08
+#define MSG_PARITY_ERROR         0x09
+#define MSG_LINKED_CMD_COMPLETE  0x0a
+#define MSG_LCMD_COMPLETE_W_FLG  0x0b
+#define MSG_BUS_DEVICE_RESET     0x0c
+#define MSG_ABORT_TAG            0x0d
+#define MSG_CLEAR_QUEUE          0x0e
+#define MSG_INITIATE_RECOVERY    0x0f
+
+#define MSG_RELEASE_RECOVRY      0x10
+#define MSG_TERMINATE_IO         0x11
+
+#define MSG_SIMPLE_QUEUE         0x20
+#define MSG_HEAD_OF_QUEUE        0x21
+#define MSG_ORDERED_QUEUE        0x22
+#define MSG_IGNORE_WIDE_RESIDUE  0x23
+
+#define MSG_IDENTIFY             0x80
+#define MSG_IDENTIFY_W_DISC      0xc0
+
+/*
+ *    SCSI Phases
+ */
+#define PHS_DATA_OUT  0x00
+#define PHS_DATA_IN   0x01
+#define PHS_COMMAND   0x02
+#define PHS_STATUS    0x03
+#define PHS_MSG_OUT   0x06
+#define PHS_MSG_IN    0x07
+
+/*
+ *    Statuses
+ */
+#define STS_GOOD                        0x00
+#define STS_CHECK_CONDITION             0x02
+#define STS_CONDITION_MET               0x04
+#define STS_BUSY                        0x08
+#define STS_INTERMEDIATE                0x10
+#define STS_INTERMEDIATE_CONDITION_MET  0x14
+#define STS_RESERVATION_CONFLICT        0x18
+#define STS_COMMAND_TERMINATED          0x22
+#define STS_TASK_SET_FULL               0x28
+#define    STS_QUEUE_FULL               0x28
+#define STS_ACA_ACTIVE                  0x30
+
+#define STS_VALID_MASK                  0x3e
+
+#define SCSI_STATUS(x)  ((x) & STS_VALID_MASK)
+
+/*
+ *    SCSI QTag Types
+ */
+#define QTAG_SIMPLE     0x20
+#define QTAG_HEAD_OF_Q  0x21
+#define QTAG_ORDERED    0x22
+
+/*
+ *    SCSI Sense Key Definitons
+ */
+#define SK_NO_SENSE         0x00
+#define SK_RECOVERED_ERROR  0x01
+#define SK_NOT_READY        0x02
+#define SK_MEDIUM_ERROR     0x03
+#define SK_HARDWARE_ERROR   0x04
+#define SK_ILLEGAL_REQUEST  0x05
+#define SK_UNIT_ATTENTION   0x06
+#define SK_DATA_PROTECT     0x07
+#define SK_BLANK_CHECK      0x08
+#define SK_VENDOR_SPECIFIC  0x09
+#define SK_COPY_ABORTED     0x0a
+#define SK_ABORTED_COMMAND  0x0b
+#define SK_EQUAL            0x0c
+#define SK_VOLUME_OVERFLOW  0x0d
+#define SK_MISCOMPARE       0x0e
+#define SK_RESERVED         0x0f
+
+
+
+#define SCSI_MAX_INQUIRY_BYTES  96
+#define SCSI_STD_INQUIRY_BYTES  36
+
+#undef USE_SCSI_COMPLETE_INQDATA
+/*
+ *      Structure definition for SCSI Inquiry Data
+ *
+ *  NOTE: The following structure is 96 bytes in size
+ *      iff USE_SCSI_COMPLETE_INQDATA IS defined above (i.e. w/ "#define").
+ *      If USE_SCSI_COMPLETE_INQDATA is NOT defined above (i.e. w/ "#undef")
+ *      then the following structure is only 36 bytes in size.
+ *  THE CHOICE IS YOURS!
+ */
+typedef struct SCSI_Inquiry_Data
+{
+#ifdef USE_SCSI_COMPLETE_INQDATA
+    u8   InqByte[SCSI_MAX_INQUIRY_BYTES];
+#else
+    u8   InqByte[SCSI_STD_INQUIRY_BYTES];
+#endif
+
+/*
+ * the following structure works only for little-endian (Intel,
+ * LSB first (1234) byte order) systems with 4-byte ints.
+ *
+        u32    Periph_Device_Type    : 5,
+               Periph_Qualifier      : 3,
+               Device_Type_Modifier  : 7,
+               Removable_Media       : 1,
+               ANSI_Version          : 3,
+               ECMA_Version          : 3,
+               ISO_Version           : 2,
+               Response_Data_Format  : 4,
+               reserved_0            : 3,
+               AERC                  : 1  ;
+        u32    Additional_Length     : 8,
+               reserved_1            :16,
+               SftReset              : 1,
+               CmdQue                : 1,
+               reserved_2            : 1,
+               Linked                : 1,
+               Sync                  : 1,
+               WBus16                : 1,
+               WBus32                : 1,
+               RelAdr                : 1  ;
+        u8     Vendor_ID[8];
+        u8     Product_ID[16];
+        u8     Revision_Level [4];
+#ifdef USE_SCSI_COMPLETE_INQDATA
+        u8     Vendor_Specific[20];
+        u8     reserved_3[40];
+#endif
+ *
+ */
+
+} SCSI_Inquiry_Data_t;
+
+#define INQ_PERIPHINFO_BYTE            0
+#define   INQ_Periph_Qualifier_MASK      0xe0
+#define   INQ_Periph_Device_Type_MASK    0x1f
+
+#define INQ_Peripheral_Qualifier(inqp) \
+    (int)((*((u8*)(inqp)+INQ_PERIPHINFO_BYTE) & INQ_Periph_Qualifier_MASK) >> 5)
+#define INQ_Peripheral_Device_Type(inqp) \
+    (int)(*((u8*)(inqp)+INQ_PERIPHINFO_BYTE) & INQ_Periph_Device_Type_MASK)
+
+
+#define INQ_DEVTYPEMOD_BYTE            1
+#define   INQ_RMB_BIT                    0x80
+#define   INQ_Device_Type_Modifier_MASK  0x7f
+
+#define INQ_Removable_Medium(inqp) \
+    (int)(*((u8*)(inqp)+INQ_DEVTYPEMOD_BYTE) & INQ_RMB_BIT)
+#define INQ_Device_Type_Modifier(inqp) \
+    (int)(*((u8*)(inqp)+INQ_DEVTYPEMOD_BYTE) & INQ_Device_Type_Modifier_MASK)
+
+
+#define INQ_VERSIONINFO_BYTE           2
+#define   INQ_ISO_Version_MASK           0xc0
+#define   INQ_ECMA_Version_MASK          0x38
+#define   INQ_ANSI_Version_MASK          0x07
+
+#define INQ_ISO_Version(inqp) \
+    (int)(*((u8*)(inqp)+INQ_VERSIONINFO_BYTE) & INQ_ISO_Version_MASK)
+#define INQ_ECMA_Version(inqp) \
+    (int)(*((u8*)(inqp)+INQ_VERSIONINFO_BYTE) & INQ_ECMA_Version_MASK)
+#define INQ_ANSI_Version(inqp) \
+    (int)(*((u8*)(inqp)+INQ_VERSIONINFO_BYTE) & INQ_ANSI_Version_MASK)
+
+
+#define INQ_BYTE3                      3
+#define   INQ_AERC_BIT                   0x80
+#define   INQ_TrmTsk_BIT                 0x40
+#define   INQ_NormACA_BIT                0x20
+#define   INQ_RDF_MASK                   0x0F
+
+#define INQ_AER_Capable(inqp) \
+    (int)(*((u8*)(inqp)+INQ_BYTE3) & INQ_AERC_BIT)
+#define INQ_TrmTsk(inqp) \
+    (int)(*((u8*)(inqp)+INQ_BYTE3) & INQ_TrmTsk_BIT)
+#define INQ_NormACA(inqp) \
+    (int)(*((u8*)(inqp)+INQ_BYTE3) & INQ_NormACA_BIT)
+#define INQ_Response_Data_Format(inqp) \
+    (int)(*((u8*)(inqp)+INQ_BYTE3) & INQ_RDF_MASK)
+
+
+#define INQ_CAPABILITY_BYTE            7
+#define   INQ_RelAdr_BIT                 0x80
+#define   INQ_WBus32_BIT                 0x40
+#define   INQ_WBus16_BIT                 0x20
+#define   INQ_Sync_BIT                   0x10
+#define   INQ_Linked_BIT                 0x08
+  /*      INQ_Reserved BIT               0x40 */
+#define   INQ_CmdQue_BIT                 0x02
+#define   INQ_SftRe_BIT                  0x01
+
+#define IS_RelAdr_DEV(inqp) \
+    (int)(*((u8*)(inqp)+INQ_CAPABILITY_BYTE) & INQ_RelAdr_BIT)
+#define IS_WBus32_DEV(inqp) \
+    (int)(*((u8*)(inqp)+INQ_CAPABILITY_BYTE) & INQ_WBus32_BIT)
+#define IS_WBus16_DEV(inqp) \
+    (int)(*((u8*)(inqp)+INQ_CAPABILITY_BYTE) & INQ_WBus16_BIT)
+#define IS_Sync_DEV(inqp) \
+    (int)(*((u8*)(inqp)+INQ_CAPABILITY_BYTE) & INQ_Sync_BIT)
+#define IS_Linked_DEV(inqp) \
+    (int)(*((u8*)(inqp)+INQ_CAPABILITY_BYTE) & INQ_Linked_BIT)
+#define IS_CmdQue_DEV(inqp) \
+    (int)(*((u8*)(inqp)+INQ_CAPABILITY_BYTE) & INQ_CmdQue_BIT)
+#define IS_SftRe_DEV(inqp) \
+    (int)(*((u8*)(inqp)+INQ_CAPABILITY_BYTE) & INQ_SftRe_BIT)
+
+#define INQ_Width_BITS \
+    (INQ_WBus32_BIT | INQ_WBus16_BIT)
+#define IS_Wide_DEV(inqp) \
+    (int)(*((u8*)(inqp)+INQ_CAPABILITY_BYTE) & INQ_Width_BITS)
+
+
+/*
+ *      SCSI peripheral device types
+ */
+#define SCSI_TYPE_DAD               0x00  /* Direct Access Device */
+#define SCSI_TYPE_SAD               0x01  /* Sequential Access Device */
+#define SCSI_TYPE_TAPE  SCSI_TYPE_SAD
+#define SCSI_TYPE_PRT               0x02  /* Printer */
+#define SCSI_TYPE_PROC              0x03  /* Processor */
+#define SCSI_TYPE_WORM              0x04
+#define SCSI_TYPE_CDROM             0x05
+#define SCSI_TYPE_SCAN              0x06  /* Scanner */
+#define SCSI_TYPE_OPTICAL           0x07  /* Magneto/Optical */
+#define SCSI_TYPE_CHANGER           0x08
+#define SCSI_TYPE_COMM              0x09  /* Communications device */
+#define SCSI_TYPE_UNKNOWN           0x1f
+#define SCSI_TYPE_UNCONFIGURED_LUN  0x7f
+
+#define SCSI_TYPE_MAX_KNOWN         SCSI_TYPE_COMM
+
+/*
+ *      Peripheral Qualifiers
+ */
+#define DEVICE_PRESENT     0x00
+#define LUN_NOT_PRESENT    0x01
+#define LUN_NOT_SUPPORTED  0x03
+
+/*
+ *      ANSI Versions
+ */
+#ifndef SCSI_1
+#define SCSI_1  0x01
+#endif
+#ifndef SCSI_2
+#define SCSI_2  0x02
+#endif
+#ifndef SCSI_3
+#define SCSI_3  0x03
+#endif
+
+
+#define SCSI_MAX_SENSE_BYTES  255
+#define SCSI_STD_SENSE_BYTES   18
+#define SCSI_PAD_SENSE_BYTES      (SCSI_MAX_SENSE_BYTES - SCSI_STD_SENSE_BYTES)
+
+#undef USE_SCSI_COMPLETE_SENSE
+/*
+ *      Structure definition for SCSI Sense Data
+ *
+ *  NOTE: The following structure is 255 bytes in size
+ *      iiff USE_SCSI_COMPLETE_SENSE IS defined above (i.e. w/ "#define").
+ *      If USE_SCSI_COMPLETE_SENSE is NOT defined above (i.e. w/ "#undef")
+ *      then the following structure is only 19 bytes in size.
+ *  THE CHOICE IS YOURS!
+ *
+ */
+typedef struct SCSI_Sense_Data
+{
+#ifdef USE_SCSI_COMPLETE_SENSE
+    u8       SenseByte[SCSI_MAX_SENSE_BYTES];
+#else
+    u8       SenseByte[SCSI_STD_SENSE_BYTES];
+#endif
+
+/*
+ * the following structure works only for little-endian (Intel,
+ * LSB first (1234) byte order) systems with 4-byte ints.
+ *
+    u8     Error_Code                :4,            // 0x00
+           Error_Class               :3,
+           Valid                     :1
+     ;
+    u8     Segment_Number                           // 0x01
+     ;
+    u8     Sense_Key                 :4,            // 0x02
+           Reserved                  :1,
+           Incorrect_Length_Indicator:1,
+           End_Of_Media              :1,
+           Filemark                  :1
+     ;
+    u8     Information_MSB;                         // 0x03
+    u8     Information_Byte2;                       // 0x04
+    u8     Information_Byte1;                       // 0x05
+    u8     Information_LSB;                         // 0x06
+    u8     Additional_Length;                       // 0x07
+
+    u32    Command_Specific_Information;            // 0x08 - 0x0b
+
+    u8     Additional_Sense_Code;                   // 0x0c
+    u8     Additional_Sense_Code_Qualifier;         // 0x0d
+    u8     Field_Replaceable_Unit_Code;             // 0x0e
+    u8     Illegal_Req_Bit_Pointer   :3,            // 0x0f
+           Illegal_Req_Bit_Valid     :1,
+           Illegal_Req_Reserved      :2,
+           Illegal_Req_Cmd_Data      :1,
+           Sense_Key_Specific_Valid  :1
+     ;
+    u16    Sense_Key_Specific_Data;                 // 0x10 - 0x11
+
+#ifdef USE_SCSI_COMPLETE_SENSE
+    u8     Additional_Sense_Data[SCSI_PAD_SENSE_BYTES];
+#else
+    u8     Additional_Sense_Data[1];
+#endif
+ *
+ */
+
+} SCSI_Sense_Data_t;
+
+
+#define SD_ERRCODE_BYTE                0
+#define   SD_Valid_BIT                   0x80
+#define   SD_Error_Code_MASK             0x7f
+#define SD_Valid(sdp) \
+    (int)(*((u8*)(sdp)+SD_ERRCODE_BYTE) & SD_Valid_BIT)
+#define SD_Error_Code(sdp) \
+    (int)(*((u8*)(sdp)+SD_ERRCODE_BYTE) & SD_Error_Code_MASK)
+
+
+#define SD_SEGNUM_BYTE                 1
+#define SD_Segment_Number(sdp)  (int)(*((u8*)(sdp)+SD_SEGNUM_BYTE))
+
+
+#define SD_SENSEKEY_BYTE               2
+#define   SD_Filemark_BIT                0x80
+#define   SD_EOM_BIT                     0x40
+#define   SD_ILI_BIT                     0x20
+#define   SD_Sense_Key_MASK              0x0f
+#define SD_Filemark(sdp) \
+    (int)(*((u8*)(sdp)+SD_SENSEKEY_BYTE) & SD_Filemark_BIT)
+#define SD_EOM(sdp) \
+    (int)(*((u8*)(sdp)+SD_SENSEKEY_BYTE) & SD_EOM_BIT)
+#define SD_ILI(sdp) \
+    (int)(*((u8*)(sdp)+SD_SENSEKEY_BYTE) & SD_ILI_BIT)
+#define SD_Sense_Key(sdp) \
+    (int)(*((u8*)(sdp)+SD_SENSEKEY_BYTE) & SD_Sense_Key_MASK)
+
+
+#define SD_INFO3_BYTE                  3
+#define SD_INFO2_BYTE                  4
+#define SD_INFO1_BYTE                  5
+#define SD_INFO0_BYTE                  6
+#define SD_Information3(sdp)  (int)(*((u8*)(sdp)+SD_INFO3_BYTE))
+#define SD_Information2(sdp)  (int)(*((u8*)(sdp)+SD_INFO2_BYTE))
+#define SD_Information1(sdp)  (int)(*((u8*)(sdp)+SD_INFO1_BYTE))
+#define SD_Information0(sdp)  (int)(*((u8*)(sdp)+SD_INFO0_BYTE))
+
+
+#define SD_ADDL_LEN_BYTE               7
+#define SD_Additional_Sense_Length(sdp) \
+    (int)(*((u8*)(sdp)+SD_ADDL_LEN_BYTE))
+#define SD_Addl_Sense_Len  SD_Additional_Sense_Length
+
+
+#define SD_CMD_SPECIFIC3_BYTE          8
+#define SD_CMD_SPECIFIC2_BYTE          9
+#define SD_CMD_SPECIFIC1_BYTE         10
+#define SD_CMD_SPECIFIC0_BYTE         11
+#define SD_Cmd_Specific_Info3(sdp)  (int)(*((u8*)(sdp)+SD_CMD_SPECIFIC3_BYTE))
+#define SD_Cmd_Specific_Info2(sdp)  (int)(*((u8*)(sdp)+SD_CMD_SPECIFIC2_BYTE))
+#define SD_Cmd_Specific_Info1(sdp)  (int)(*((u8*)(sdp)+SD_CMD_SPECIFIC1_BYTE))
+#define SD_Cmd_Specific_Info0(sdp)  (int)(*((u8*)(sdp)+SD_CMD_SPECIFIC0_BYTE))
+
+
+#define SD_ADDL_SENSE_CODE_BYTE       12
+#define SD_Additional_Sense_Code(sdp) \
+    (int)(*((u8*)(sdp)+SD_ADDL_SENSE_CODE_BYTE))
+#define SD_Addl_Sense_Code  SD_Additional_Sense_Code
+#define SD_ASC  SD_Additional_Sense_Code
+
+
+#define SD_ADDL_SENSE_CODE_QUAL_BYTE  13
+#define SD_Additional_Sense_Code_Qualifier(sdp) \
+    (int)(*((u8*)(sdp)+SD_ADDL_SENSE_CODE_QUAL_BYTE))
+#define SD_Addl_Sense_Code_Qual  SD_Additional_Sense_Code_Qualifier
+#define SD_ASCQ  SD_Additional_Sense_Code_Qualifier
+
+
+#define SD_FIELD_REPL_UNIT_CODE_BYTE  14
+#define SD_Field_Replaceable_Unit_Code(sdp) \
+    (int)(*((u8*)(sdp)+SD_FIELD_REPL_UNIT_CODE_BYTE))
+#define SD_Field_Repl_Unit_Code  SD_Field_Replaceable_Unit_Code
+#define SD_FRUC  SD_Field_Replaceable_Unit_Code
+#define SD_FRU  SD_Field_Replaceable_Unit_Code
+
+
+/*
+ *  Sense-Key Specific offsets and macros.
+ */
+#define SD_SKS2_BYTE                  15
+#define   SD_SKS_Valid_BIT               0x80
+#define   SD_SKS_Cmd_Data_BIT            0x40
+#define   SD_SKS_Bit_Ptr_Valid_BIT       0x08
+#define   SD_SKS_Bit_Ptr_MASK            0x07
+#define SD_SKS1_BYTE                  16
+#define SD_SKS0_BYTE                  17
+#define SD_Sense_Key_Specific_Valid(sdp) \
+    (int)(*((u8*)(sdp)+SD_SKS2_BYTE) & SD_SKS_Valid_BIT)
+#define SD_SKS_Valid  SD_Sense_Key_Specific_Valid
+#define SD_SKS_CDB_Error(sdp)  \
+    (int)(*((u8*)(sdp)+SD_SKS2_BYTE) & SD_SKS_Cmd_Data_BIT)
+#define SD_Was_Illegal_Request  SD_SKS_CDB_Error
+#define SD_SKS_Bit_Pointer_Valid(sdp)  \
+    (int)(*((u8*)(sdp)+SD_SKS2_BYTE) & SD_SKS_Bit_Ptr_Valid_BIT)
+#define SD_SKS_Bit_Pointer(sdp)  \
+    (int)(*((u8*)(sdp)+SD_SKS2_BYTE) & SD_SKS_Bit_Ptr_MASK)
+#define SD_Field_Pointer(sdp)  \
+    (int)( ((u16)(*((u8*)(sdp)+SD_SKS1_BYTE)) << 8) \
+      + *((u8*)(sdp)+SD_SKS0_BYTE) )
+#define SD_Bad_Byte  SD_Field_Pointer
+#define SD_Actual_Retry_Count  SD_Field_Pointer
+#define SD_Progress_Indication  SD_Field_Pointer
+
+/*
+ *  Mode Sense Write Protect Mask
+ */
+#define WRITE_PROTECT_MASK      0X80
+
+/*
+ *  Medium Type Codes
+ */
+#define OPTICAL_DEFAULT                 0x00
+#define OPTICAL_READ_ONLY_MEDIUM        0x01
+#define OPTICAL_WRITE_ONCE_MEDIUM       0x02
+#define OPTICAL_READ_WRITABLE_MEDIUM    0x03
+#define OPTICAL_RO_OR_WO_MEDIUM         0x04
+#define OPTICAL_RO_OR_RW_MEDIUM         0x05
+#define OPTICAL_WO_OR_RW_MEDIUM         0x06
+
+
+
+/*
+ *    Structure definition for READ6, WRITE6 (6-byte CDB)
+ */
+typedef struct SCSI_RW6_CDB
+{
+    u32    OpCode      :8,
+           LBA_HI      :5,    /* 5 MSBit's of the LBA */
+           Lun         :3,
+           LBA_MID     :8,    /* NOTE: total of 21 bits in LBA */
+           LBA_LO      :8  ;  /* Max LBA = 0x001fffff          */
+    u8     BlockCount;
+    u8     Control;
+} SCSI_RW6_t;
+
+#define MAX_RW6_LBA  ((u32)0x001fffff)
+
+/*
+ *  Structure definition for READ10, WRITE10 (10-byte CDB)
+ *
+ *    NOTE: ParityCheck bit is applicable only for VERIFY and WRITE VERIFY for
+ *    the ADP-92 DAC only.  In the SCSI2 spec. this same bit is defined as a
+ *    FUA (forced unit access) bit for READs and WRITEs.  Since this driver
+ *    does not use the FUA, this bit is defined as it is used by the ADP-92.
+ *    Also, for READ CAPACITY, only the OpCode field is used.
+ */
+typedef struct SCSI_RW10_CDB
+{
+    u8     OpCode;
+    u8     Reserved1;
+    u32    LBA;
+    u8     Reserved2;
+    u16    BlockCount;
+    u8     Control;
+} SCSI_RW10_t;
+
+#define PARITY_CHECK  0x08    /* parity check bit - byte[1], bit 3 */
+
+    /*
+     *  Structure definition for data returned by READ CAPACITY cmd;
+     *  READ CAPACITY data
+     */
+    typedef struct READ_CAP_DATA
+    {
+        u32    MaxLBA;
+        u32    BlockBytes;
+    } SCSI_READ_CAP_DATA_t, *pSCSI_READ_CAP_DATA_t;
+
+
+/*
+ *  Structure definition for FORMAT UNIT CDB (6-byte CDB)
+ */
+typedef struct _SCSI_FORMAT_UNIT
+{
+    u8     OpCode;
+    u8     Reserved1;
+    u8     VendorSpecific;
+    u16    Interleave;
+    u8     Control;
+} SCSI_FORMAT_UNIT_t;
+
+/*
+ *    Structure definition for REQUEST SENSE (6-byte CDB)
+ */
+typedef struct _SCSI_REQUEST_SENSE
+{
+    u8     OpCode;
+    u8     Reserved1;
+    u8     Reserved2;
+    u8     Reserved3;
+    u8     AllocLength;
+    u8     Control;
+} SCSI_REQ_SENSE_t;
+
+/*
+ *  Structure definition for REPORT LUNS (12-byte CDB)
+ */
+typedef struct _SCSI_REPORT_LUNS
+{
+    u8     OpCode;
+    u8     Reserved1[5];
+    u32    AllocationLength;
+    u8     Reserved2;
+    u8     Control;
+} SCSI_REPORT_LUNS_t, *pSCSI_REPORT_LUNS_t;
+
+    /*
+     *  (per-level) LUN information bytes
+     */
+/*
+ *  Following doesn't work on ARMCC compiler
+ *  [apparently] because it pads every struct
+ *  to be multiple of 4 bytes!
+ *  So SCSI_LUN_LEVELS_t winds up being 16
+ *  bytes instead of 8!
+ *
+    typedef struct LUN_INFO
+    {
+        u8     AddrMethod_plus_LunOrBusNumber;
+        u8     LunOrTarget;
+    } SCSI_LUN_INFO_t, *pSCSI_LUN_INFO_t;
+
+    typedef struct LUN_LEVELS
+    {
+        SCSI_LUN_INFO_t  LUN_0;
+        SCSI_LUN_INFO_t  LUN_1;
+        SCSI_LUN_INFO_t  LUN_2;
+        SCSI_LUN_INFO_t  LUN_3;
+    } SCSI_LUN_LEVELS_t, *pSCSI_LUN_LEVELS_t;
+*/
+    /*
+     *  All 4 levels (8 bytes) of LUN information
+     */
+    typedef struct LUN_LEVELS
+    {
+        u8     LVL1_AddrMethod_plus_LunOrBusNumber;
+        u8     LVL1_LunOrTarget;
+        u8     LVL2_AddrMethod_plus_LunOrBusNumber;
+        u8     LVL2_LunOrTarget;
+        u8     LVL3_AddrMethod_plus_LunOrBusNumber;
+        u8     LVL3_LunOrTarget;
+        u8     LVL4_AddrMethod_plus_LunOrBusNumber;
+        u8     LVL4_LunOrTarget;
+    } SCSI_LUN_LEVELS_t, *pSCSI_LUN_LEVELS_t;
+
+    /*
+     *  Structure definition for data returned by REPORT LUNS cmd;
+     *  LUN reporting parameter list format
+     */
+    typedef struct LUN_REPORT
+    {
+        u32                LunListLength;
+        u32                Reserved;
+        SCSI_LUN_LEVELS_t  LunInfo[1];
+    } SCSI_LUN_REPORT_t, *pSCSI_LUN_REPORT_t;
+
+/****************************************************************************
+ *
+ *  Externals
+ */
+
+/****************************************************************************
+ *
+ *  Public Typedefs & Related Defines
+ */
+
+/****************************************************************************
+ *
+ *  Macros (embedded, above)
+ */
+
+/****************************************************************************
+ *
+ *  Public Variables
+ */
+
+/****************************************************************************
+ *
+ *  Public Prototypes (module entry points)
+ */
+
+
+/***************************************************************************/
+#endif
diff --git a/drivers/message/fusion/scsiops.c b/drivers/message/fusion/scsiops.c
new file mode 100644 (file)
index 0000000..2143e42
--- /dev/null
@@ -0,0 +1,309 @@
+
+static const char *ScsiOpcodeString[256] = {
+       "TEST UNIT READY\0\01",                         /* 00h */
+       "REWIND\0\002"
+               "\001REZERO UNIT",                      /* 01h */
+       "\0\0",                                         /* 02h */
+       "REQUEST SENSE\0\01",                           /* 03h */
+       "FORMAT UNIT\0\03"
+               "\001FORMAT MEDIUM\0"
+               "\002FORMAT",                           /* 04h */
+       "READ BLOCK LIMITS\0\1",                        /* 05h */
+       "\0\0",                                         /* 06h */
+       "REASSIGN BLOCKS\0\02"
+               "\010INITIALIZE ELEMENT STATUS",        /* 07h */
+       "READ(06)\0\04"
+               "\001READ\0"
+               "\003RECEIVE\0"
+               "\011GET MESSAGE(06)",                  /* 08h */
+       "\0\0",                                         /* 09h */
+       "WRITE(06)\0\05"
+               "\001WRITE\0"
+               "\002PRINT\0"
+               "\003SEND(6)\0"
+               "\011SEND MESSAGE(06)",                 /* 0Ah */
+       "SEEK(06)\0\02"
+               "\003SLEW AND PRINT",                   /* 0Bh */
+       "\0\0",                                         /* 0Ch */
+       "\0\0",                                         /* 0Dh */
+       "\0\0",                                         /* 0Eh */
+       "READ REVERSE\0\01",                            /* 0Fh */
+       "WRITE FILEMARKS\0\02"
+               "\003SYNCRONIZE BUFFER",                /* 10h */
+       "SPACE(6)\0\01",                                /* 11h */
+       "INQUIRY\0\01",                                 /* 12h */
+       "VERIFY\0\01",                                  /* 13h */
+       "RECOVER BUFFERED DATA\0\01",                   /* 14h */
+       "MODE SELECT(06)\0\01",                         /* 15h */
+       "RESERVE(06)\0\02"
+               "\010RESERVE ELEMENT(06)",              /* 16h */
+       "RELEASE(06)\0\02"
+               "\010RELEASE ELEMENT(06)",              /* 17h */
+       "COPY\0\01",                                    /* 18h */
+       "ERASE\0\01",                                   /* 19h */
+       "MODE SENSE(06)\0\01",                          /* 1Ah */
+       "STOP START UNIT\0\04"
+               "\001LOAD UNLOAD\0"
+               "\002STOP PRINT\0"
+               "\006SCAN\0\002",                       /* 1Bh */
+       "RECEIVE DIAGNOSTIC RESULTS\0\01",              /* 1Ch */
+       "SEND DIAGNOSTIC\0\01",                         /* 1Dh */
+       "PREVENT ALLOW MEDIUM REMOVAL\0\01",            /* 1Eh */
+       "\0\0",                                         /* 1Fh */
+       "\0\0",                                         /* 20h */
+       "\0\0",                                         /* 21h */
+       "\0\0",                                         /* 22h */
+       "READ FORMAT CAPACITIES\0\01",                  /* 23h */
+       "SET WINDOW\0\01",                              /* 24h */
+       "READ CAPACITY\0\03"
+               "\006GET WINDOW\0"
+               "\037FREAD CARD CAPACITY",              /* 25h */
+       "\0\0",                                         /* 26h */
+       "\0\0",                                         /* 27h */
+       "READ(10)\0\02"
+               "\011GET MESSAGE(10)",                  /* 28h */
+       "READ GENERATION\0\01",                         /* 29h */
+       "WRITE(10)\0\03"
+               "\011SEND(10)\0"
+               "\011SEND MESSAGE(10)",                 /* 2Ah */
+       "SEEK(10)\0\03"
+               "LOCATE(10)\0"
+               "POSITION TO ELEMENT",                  /* 2Bh */
+       "ERASE(10)\0\01",                               /* 2Ch */
+       "READ UPDATED BLOCK\0\01",                      /* 2Dh */
+       "WRITE AND VERIFY(10)\0\01",                    /* 2Eh */
+       "VERIFY(10)\0\01",                              /* 2Fh */
+       "SEARCH DATA HIGH(10)\0\01",                    /* 30h */
+       "SEARCH DATA EQUAL(10)\0\02"
+               "OBJECT POSITION",                      /* 31h */
+       "SEARCH DATA LOW(10)\0\01",                     /* 32h */
+       "SET LIMITS(10)\0\01",                          /* 33h */
+       "PRE-FETCH(10)\0\03"
+               "READ POSITION\0"
+               "GET DATA BUFFER STATUS",               /* 34h */
+       "SYNCHRONIZE CACHE(10)\0\01",                   /* 35h */
+       "LOCK UNLOCK CACHE(10)\0\01",                   /* 36h */
+       "READ DEFECT DATA(10)\0\01",                    /* 37h */
+       "MEDIUM SCAN\0\01",                             /* 38h */
+       "COMPARE\0\01",                                 /* 39h */
+       "COPY AND VERIFY\0\01",                         /* 3Ah */
+       "WRITE BUFFER\0\01",                            /* 3Bh */
+       "READ BUFFER\0\01",                             /* 3Ch */
+       "UPDATE BLOCK\0\01",                            /* 3Dh */
+       "READ LONG\0\01",                               /* 3Eh */
+       "WRITE LONG\0\01",                              /* 3Fh */
+       "CHANGE DEFINITION\0\01",                       /* 40h */
+       "WRITE SAME(10)\0\01",                          /* 41h */
+       "READ SUB-CHANNEL\0\01",                        /* 42h */
+       "READ TOC/PMA/ATIP\0\01",                       /* 43h */
+       "REPORT DENSITY SUPPORT\0\01",                  /* 44h */
+       "READ HEADER\0\01",                             /* 44h */
+       "PLAY AUDIO(10)\0\01",                          /* 45h */
+       "GET CONFIGURATION\0\01",                       /* 46h */
+       "PLAY AUDIO MSF\0\01",                          /* 47h */
+       "PLAY AUDIO TRACK INDEX\0\01",                  /* 48h */
+       "PLAY TRACK RELATIVE(10)\0\01",                 /* 49h */
+       "GET EVENT STATUS NOTIFICATION\0\01",           /* 4Ah */
+       "PAUSE/RESUME\0\01",                            /* 4Bh */
+       "LOG SELECT\0\01",                              /* 4Ch */
+       "LOG SENSE\0\01",                               /* 4Dh */
+       "STOP PLAY/SCAN\0\01",                          /* 4Eh */
+       "\0\0",                                         /* 4Fh */
+       "XDWRITE(10)\0\01",                             /* 50h */
+       "XPWRITE(10)\0\02"
+               "READ DISC INFORMATION",                /* 51h */
+       "XDREAD(10)\0\01"
+               "READ TRACK INFORMATION",               /* 52h */
+       "RESERVE TRACK\0\01",                           /* 53h */
+       "SEND OPC INFORMATION\0\01",                    /* 54h */
+       "MODE SELECT(10)\0\01",                         /* 55h */
+       "RESERVE(10)\0\02"
+               "RESERVE ELEMENT(10)",                  /* 56h */
+       "RELEASE(10)\0\02"
+               "RELEASE ELEMENT(10)",                  /* 57h */
+       "REPAIR TRACK\0\01",                            /* 58h */
+       "READ MASTER CUE\0\01",                         /* 59h */
+       "MODE SENSE(10)\0\01",                          /* 5Ah */
+       "CLOSE TRACK/SESSION\0\01",                     /* 5Bh */
+       "READ BUFFER CAPACITY\0\01",                    /* 5Ch */
+       "SEND CUE SHEET\0\01",                          /* 5Dh */
+       "PERSISTENT RESERVE IN\0\01",                   /* 5Eh */
+       "PERSISTENT RESERVE OUT\0\01",                  /* 5Fh */
+       "\0\0",                                         /* 60h */
+       "\0\0",                                         /* 61h */
+       "\0\0",                                         /* 62h */
+       "\0\0",                                         /* 63h */
+       "\0\0",                                         /* 64h */
+       "\0\0",                                         /* 65h */
+       "\0\0",                                         /* 66h */
+       "\0\0",                                         /* 67h */
+       "\0\0",                                         /* 68h */
+       "\0\0",                                         /* 69h */
+       "\0\0",                                         /* 6Ah */
+       "\0\0",                                         /* 6Bh */
+       "\0\0",                                         /* 6Ch */
+       "\0\0",                                         /* 6Dh */
+       "\0\0",                                         /* 6Eh */
+       "\0\0",                                         /* 6Fh */
+       "\0\0",                                         /* 70h */
+       "\0\0",                                         /* 71h */
+       "\0\0",                                         /* 72h */
+       "\0\0",                                         /* 73h */
+       "\0\0",                                         /* 74h */
+       "\0\0",                                         /* 75h */
+       "\0\0",                                         /* 76h */
+       "\0\0",                                         /* 77h */
+       "\0\0",                                         /* 78h */
+       "\0\0",                                         /* 79h */
+       "\0\0",                                         /* 7Ah */
+       "\0\0",                                         /* 7Bh */
+       "\0\0",                                         /* 7Ch */
+       "\0\0",                                         /* 7Eh */
+       "\0\0",                                         /* 7Eh */
+       "\0\0",                                         /* 7Fh */
+       "XDWRITE EXTENDED(16)\0\01",                    /* 80h */
+       "REBUILD(16)\0\01",                             /* 81h */
+       "REGENERATE(16)\0\01",                          /* 82h */
+       "EXTENDED COPY\0\01",                           /* 83h */
+       "RECEIVE COPY RESULTS\0\01",                    /* 84h */
+       "ACCESS CONTROL IN  [proposed]\0\01",           /* 86h */
+       "ACCESS CONTROL OUT  [proposed]\0\01",          /* 87h */
+       "READ(16)\0\01",                                /* 88h */
+       "DEVICE LOCKS  [proposed]\0\01",                /* 89h */
+       "WRITE(16)\0\01",                               /* 8Ah */
+       "\0\0",                                         /* 8Bh */
+       "READ ATTRIBUTES [proposed]\0\01",              /* 8Ch */
+       "WRITE ATTRIBUTES [proposed]\0\01",             /* 8Dh */
+       "WRITE AND VERIFY(16)\0\01",                    /* 8Eh */
+       "VERIFY(16)\0\01",                              /* 8Fh */
+       "PRE-FETCH(16)\0\01",                           /* 90h */
+       "SYNCHRONIZE CACHE(16)\0\02"
+               "SPACE(16) [1]",                        /* 91h */
+       "LOCK UNLOCK CACHE(16)\0\02"
+               "LOCATE(16) [1]",                       /* 92h */
+       "WRITE SAME(16)\0\01",                          /* 93h */
+       "[usage proposed by SCSI Socket Services project]\0\01",        /* 94h */
+       "[usage proposed by SCSI Socket Services project]\0\01",        /* 95h */
+       "[usage proposed by SCSI Socket Services project]\0\01",        /* 96h */
+       "[usage proposed by SCSI Socket Services project]\0\01",        /* 97h */
+       "MARGIN CONTROL [proposed]\0\01",               /* 98h */
+       "\0\0",                                         /* 99h */
+       "\0\0",                                         /* 9Ah */
+       "\0\0",                                         /* 9Bh */
+       "\0\0",                                         /* 9Ch */
+       "\0\0",                                         /* 9Dh */
+       "SERVICE ACTION IN [proposed]\0\01",            /* 9Eh */
+       "SERVICE ACTION OUT [proposed]\0\01",           /* 9Fh */
+       "REPORT LUNS\0\01",                             /* A0h */
+       "BLANK\0\01",                                   /* A1h */
+       "SEND EVENT\0\01",                              /* A2h */
+       "MAINTENANCE (IN)\0\02"
+               "SEND KEY",                             /* A3h */
+       "MAINTENANCE (OUT)\0\02"
+               "REPORT KEY",                           /* A4h */
+       "MOVE MEDIUM\0\02"
+               "PLAY AUDIO(12)",                       /* A5h */
+       "EXCHANGE MEDIUM\0\02"
+               "LOAD/UNLOAD C/DVD",                    /* A6h */
+       "MOVE MEDIUM ATTACHED\0\02"
+               "SET READ AHEAD\0\01",                  /* A7h */
+       "READ(12)\0\02"
+               "GET MESSAGE(12)",                      /* A8h */
+       "PLAY TRACK RELATIVE(12)\0\01",                 /* A9h */
+       "WRITE(12)\0\02"
+               "SEND MESSAGE(12)",                     /* AAh */
+       "\0\0",                                         /* ABh */
+       "ERASE(12)\0\02"
+               "GET PERFORMANCE",                      /* ACh */
+       "READ DVD STRUCTURE\0\01",                      /* ADh */
+       "WRITE AND VERIFY(12)\0\01",                    /* AEh */
+       "VERIFY(12)\0\01",                              /* AFh */
+       "SEARCH DATA HIGH(12)\0\01",                    /* B0h */
+       "SEARCH DATA EQUAL(12)\0\01",                   /* B1h */
+       "SEARCH DATA LOW(12)\0\01",                     /* B2h */
+       "SET LIMITS(12)\0\01",                          /* B3h */
+       "READ ELEMENT STATUS ATTACHED\0\01",            /* B4h */
+       "REQUEST VOLUME ELEMENT ADDRESS\0\01",          /* B5h */
+       "SEND VOLUME TAG\0\02"
+               "SET STREAMING",                        /* B6h */
+       "READ DEFECT DATA(12)\0\01",                    /* B7h */
+       "READ ELEMENT STATUS\0\01",                     /* B8h */
+       "READ CD MSF\0\01",                             /* B9h */
+       "REDUNDANCY GROUP (IN)\0\02"
+               "SCAN",                                 /* BAh */
+       "REDUNDANCY GROUP (OUT)\0\02"
+               "SET CD-ROM SPEED",                     /* BBh */
+       "SPARE (IN)\0\02"
+               "PLAY CD",                              /* BCh */
+       "SPARE (OUT)\0\02"
+               "MECHANISM STATUS",                     /* BDh */
+       "VOLUME SET (IN)\0\02"
+               "READ CD",                              /* BEh */
+       "VOLUME SET (OUT)\0\0\02"
+               "SEND DVD STRUCTURE",                   /* BFh */
+       "\0\0",                                         /* C0h */
+       "\0\0",                                         /* C1h */
+       "\0\0",                                         /* C2h */
+       "\0\0",                                         /* C3h */
+       "\0\0",                                         /* C4h */
+       "\0\0",                                         /* C5h */
+       "\0\0",                                         /* C6h */
+       "\0\0",                                         /* C7h */
+       "\0\0",                                         /* C8h */
+       "\0\0",                                         /* C9h */
+       "\0\0",                                         /* CAh */
+       "\0\0",                                         /* CBh */
+       "\0\0",                                         /* CCh */
+       "\0\0",                                         /* CDh */
+       "\0\0",                                         /* CEh */
+       "\0\0",                                         /* CFh */
+       "\0\0",                                         /* D0h */
+       "\0\0",                                         /* D1h */
+       "\0\0",                                         /* D2h */
+       "\0\0",                                         /* D3h */
+       "\0\0",                                         /* D4h */
+       "\0\0",                                         /* D5h */
+       "\0\0",                                         /* D6h */
+       "\0\0",                                         /* D7h */
+       "\0\0",                                         /* D8h */
+       "\0\0",                                         /* D9h */
+       "\0\0",                                         /* DAh */
+       "\0\0",                                         /* DBh */
+       "\0\0",                                         /* DCh */
+       "\0\0",                                         /* DEh */
+       "\0\0",                                         /* DEh */
+       "\0\0",                                         /* DFh */
+       "\0\0",                                         /* E0h */
+       "\0\0",                                         /* E1h */
+       "\0\0",                                         /* E2h */
+       "\0\0",                                         /* E3h */
+       "\0\0",                                         /* E4h */
+       "\0\0",                                         /* E5h */
+       "\0\0",                                         /* E6h */
+       "\0\0",                                         /* E7h */
+       "\0\0",                                         /* E8h */
+       "\0\0",                                         /* E9h */
+       "\0\0",                                         /* EAh */
+       "\0\0",                                         /* EBh */
+       "\0\0",                                         /* ECh */
+       "\0\0",                                         /* EDh */
+       "\0\0",                                         /* EEh */
+       "\0\0",                                         /* EFh */
+       "\0\0",                                         /* F0h */
+       "\0\0",                                         /* F1h */
+       "\0\0",                                         /* F2h */
+       "\0\0",                                         /* F3h */
+       "\0\0",                                         /* F4h */
+       "\0\0",                                         /* F5h */
+       "\0\0",                                         /* F6h */
+       "\0\0",                                         /* F7h */
+       "\0\0",                                         /* F8h */
+       "\0\0",                                         /* F9h */
+       "\0\0",                                         /* FAh */
+       "\0\0",                                         /* FBh */
+       "\0\0",                                         /* FEh */
+       "\0\0",                                         /* FEh */
+       "\0\0",                                         /* FEh */
+       "\0\0"                                          /* FFh */
+};
+
index ece6677f0ae77657b9f4da781c411cdcb1c3111a..c2584037ce1f4b128d680364fa39ba5c44e57616 100644 (file)
@@ -174,7 +174,7 @@ static struct el3_mca_adapters_struct el3_mca_adapters[] __initdata = {
 };
 #endif /* CONFIG_MCA */
 
-#ifdef CONFIG_ISAPNP
+#if defined(CONFIG_ISAPNP) || defined(CONFIG_ISAPNP_MODULE)
 static struct isapnp_device_id el3_isapnp_adapters[] __initdata = {
        {       ISAPNP_ANY_ID, ISAPNP_ANY_ID,
                ISAPNP_VENDOR('T', 'C', 'M'), ISAPNP_FUNCTION(0x5090),
@@ -203,8 +203,8 @@ static struct isapnp_device_id el3_isapnp_adapters[] __initdata = {
 MODULE_DEVICE_TABLE(isapnp, el3_isapnp_adapters);
 
 static u16 el3_isapnp_phys_addr[8][3];
+#endif /* CONFIG_ISAPNP || CONFIG_ISAPNP_MODULE */
 static int nopnp;
-#endif /* CONFIG_ISAPNP */
 
 int __init el3_probe(struct net_device *dev)
 {
@@ -214,9 +214,9 @@ int __init el3_probe(struct net_device *dev)
        u16 phys_addr[3];
        static int current_tag;
        int mca_slot = -1;
-#ifdef CONFIG_ISAPNP
+#if defined(CONFIG_ISAPNP) || defined(CONFIG_ISAPNP_MODULE)
        static int pnp_cards;
-#endif /* CONFIG_ISAPNP */
+#endif /* CONFIG_ISAPNP || CONFIG_ISAPNP_MODULE */
 
        if (dev) SET_MODULE_OWNER(dev);
 
@@ -320,7 +320,7 @@ int __init el3_probe(struct net_device *dev)
        }
 #endif /* CONFIG_MCA */
 
-#ifdef CONFIG_ISAPNP
+#if defined(CONFIG_ISAPNP) || defined(CONFIG_ISAPNP_MODULE)
        if (nopnp == 1)
                goto no_pnp;
 
@@ -356,7 +356,7 @@ int __init el3_probe(struct net_device *dev)
                }
        }
 no_pnp:
-#endif /* CONFIG_ISAPNP */
+#endif /* CONFIG_ISAPNP || CONFIG_ISAPNP_MODULE */
 
        /* Select an open I/O location at 0x1*0 to do contention select. */
        for ( ; id_port < 0x200; id_port += 0x10) {
@@ -402,7 +402,7 @@ no_pnp:
                phys_addr[i] = htons(id_read_eeprom(i));
        }
 
-#ifdef CONFIG_ISAPNP
+#if defined(CONFIG_ISAPNP) || defined(CONFIG_ISAPNP_MODULE)
        if (nopnp == 0) {
                /* The ISA PnP 3c509 cards respond to the ID sequence.
                   This check is needed in order not to register them twice. */
@@ -422,7 +422,7 @@ no_pnp:
                        }
                }
        }
-#endif /* CONFIG_ISAPNP */
+#endif /* CONFIG_ISAPNP || CONFIG_ISAPNP_MODULE */
 
        {
                unsigned int iobase = id_read_eeprom(8);
index f06e5bb347084e7dd4e5794efed8ab3526e56127..680659a92eb8683cec9144261fd671585f5a6b0b 100644 (file)
@@ -137,7 +137,7 @@ an MMIO register read.
 */
 
 #define DRV_NAME       "8139too"
-#define DRV_VERSION    "0.9.18-pre4"
+#define DRV_VERSION    "0.9.18"
 
 
 #include <linux/config.h>
@@ -209,7 +209,7 @@ static int multicast_filter_limit = 32;
 #define RX_BUF_PAD 16
 #define RX_BUF_WRAP_PAD 2048 /* spare padding to handle lack of packet wrap */
 #define RX_BUF_TOT_LEN (RX_BUF_LEN + RX_BUF_PAD + RX_BUF_WRAP_PAD)
-#define RX_EARLY_THRESH 2
+#define RX_EARLY_THRESH 14
 
 /* Number of Tx descriptor registers. */
 #define NUM_TX_DESC    4
index c8d15d27ec8762dbb326e29f3f5403772fd35a91..e433d8fb47c654ffb89d822423d99cc8733f17c7 100644 (file)
@@ -207,6 +207,7 @@ comment 'Ethernet (1000 Mbit)'
 
 dep_tristate 'Alteon AceNIC/3Com 3C985/NetGear GA620 Gigabit support' CONFIG_ACENIC $CONFIG_PCI
 dep_mbool '  Omit support for old Tigon I based AceNICs' CONFIG_ACENIC_OMIT_TIGON_I $CONFIG_ACENIC
+dep_tristate 'D-Link 2000-based Gigabit Ethernet support' CONFIG_DL2K $CONFIG_PCI
 dep_tristate 'MyriCOM Gigabit Ethernet support' CONFIG_MYRI_SBUS $CONFIG_SBUS
 dep_tristate 'Packet Engines Hamachi GNIC-II support' CONFIG_HAMACHI $CONFIG_PCI
 dep_tristate 'Packet Engines Yellowfin Gigabit-NIC support (EXPERIMENTAL)' CONFIG_YELLOWFIN $CONFIG_PCI $CONFIG_EXPERIMENTAL
index d9db1063c04e805af684d5942d2ba0e6c4ffdeb3..23074af321f0a24182d65955a9786c61cc6a5b9d 100644 (file)
@@ -207,6 +207,7 @@ obj-$(CONFIG_MACSONIC) += macsonic.o
 obj-$(CONFIG_MACMACE) += macmace.o
 obj-$(CONFIG_MAC89x0) += mac89x0.o
 obj-$(CONFIG_TUN) += tun.o
+obj-$(CONFIG_DL2K) += dl2k.o
 
 ifeq ($(CONFIG_ARCH_ACORN),y)
 mod-subdirs    += ../acorn/net
diff --git a/drivers/net/dl2k.c b/drivers/net/dl2k.c
new file mode 100644 (file)
index 0000000..d9a7472
--- /dev/null
@@ -0,0 +1,1443 @@
+/*  D-Link DL2000-based Gigabit Ethernet Adapter Linux driver */
+/*
+    Copyright (c) 2001 by D-Link Corporation
+    Written by Edward Peng.<edward_peng@dlink.com.tw>
+    Created 03-May-2001, base on Linux' sundance.c.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+*/
+/*
+    Rev                Date            Description
+    ==========================================================================
+    0.01       2001/05/03      Create DL2000-based linux driver
+    0.02       2001/05/21      Add VLAN and hardware checksum support.
+    1.00       2001/06/26      Add jumbo frame support.
+*/
+
+#include "dl2k.h"
+
+
+static char version[] __devinitdata =
+KERN_INFO "D-Link DL2000-based linux driver v1.00 2001/06/26\n";
+
+
+
+#define MAX_UNITS 8
+static int mtu[MAX_UNITS];
+static int vlan[MAX_UNITS];
+static int jumbo[MAX_UNITS];
+static char *media[MAX_UNITS];
+static int copy_thresh;
+
+MODULE_AUTHOR ("Edward Peng");
+MODULE_DESCRIPTION ("D-Link DL2000-based Gigabit Ethernet Adapter");
+MODULE_PARM (mtu, "1-" __MODULE_STRING (MAX_UNITS) "i");
+MODULE_PARM (media, "1-" __MODULE_STRING (MAX_UNITS) "s");
+MODULE_PARM (vlan, "1-" __MODULE_STRING (MAX_UNITS) "i");
+MODULE_PARM (jumbo, "1-" __MODULE_STRING (MAX_UNITS) "i");
+MODULE_PARM (copy_thresh, "i");
+
+/* Enable the default interrupts */
+#define EnableInt() \
+writew(RxComplete| RxDMAComplete | HostError | IntRequested | TxComplete| \
+       TxDMAComplete| UpdateStats | LinkEvent, ioaddr + IntEnable)
+static int max_intrloop = 25;
+static int multicast_filter_limit = 0x40;
+
+static int rio_open (struct net_device *dev);
+static void tx_timeout (struct net_device *dev);
+static void alloc_list (struct net_device *dev);
+static int start_xmit (struct sk_buff *skb, struct net_device *dev);
+static void rio_interrupt (int irq, void *dev_instance, struct pt_regs *regs);
+static void tx_error (struct net_device *dev, int tx_status);
+static int receive_packet (struct net_device *dev);
+static void rio_error (struct net_device *dev, int int_status);
+static int change_mtu (struct net_device *dev, int new_mtu);
+static void set_multicast (struct net_device *dev);
+static struct net_device_stats *get_stats (struct net_device *dev);
+static int rio_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);
+static int rio_close (struct net_device *dev);
+static int find_miiphy (struct net_device *dev);
+static int parse_eeprom (struct net_device *dev);
+static int read_eeprom (long ioaddr, int eep_addr);
+static unsigned get_crc (unsigned char *p, int len);
+static int mii_wait_link (struct net_device *dev, int wait);
+static int mii_set_media (struct net_device *dev);
+static int mii_get_media (struct net_device *dev);
+static int mii_read (struct net_device *dev, int phy_addr, int reg_num);
+static int mii_write (struct net_device *dev, int phy_addr, int reg_num,
+                     u16 data);
+#ifdef RIO_DEBUG
+static int rio_ioctl_ext (struct net_device *dev, struct ioctl_data *iodata);
+#endif
+
+static int __devinit
+rio_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+       struct net_device *dev;
+       struct netdev_private *np;
+       static int card_idx;
+       int chip_idx = ent->driver_data;
+       int err, irq = pdev->irq;
+       long ioaddr;
+       static int version_printed;
+
+       if (!version_printed++)
+               printk ("%s", version);
+
+       err = pci_enable_device (pdev);
+       if (err)
+               return err;
+
+       err = pci_request_regions (pdev, "dl2k");
+       if (err)
+               goto err_out_disable;
+
+       pci_set_master (pdev);
+
+       dev = alloc_etherdev (sizeof (*np));
+       if (!dev) {
+               err = -ENOMEM;
+               goto err_out_res;
+       }
+       SET_MODULE_OWNER (dev);
+
+#ifdef USE_IO_OPS
+       ioaddr = pci_resource_start (pdev, 0);
+#else
+       ioaddr = pci_resource_start (pdev, 1);
+       ioaddr = (long) ioremap (ioaddr, RIO_IO_SIZE);
+       if (!ioaddr) {
+               err = -ENOMEM;
+               goto err_out_dev;
+       }
+#endif
+       dev->base_addr = ioaddr;
+       dev->irq = irq;
+       np = dev->priv;
+       np->chip_id = chip_idx;
+       spin_lock_init (&np->lock);
+
+       /* Parse manual configuration */
+       np->an_enable = 1;
+       if (card_idx < MAX_UNITS) {
+               if (media[card_idx] != NULL) {
+                       np->an_enable = 0;
+                       if (strcmp (media[card_idx], "100mbps_fd") == 0 ||
+                           strcmp (media[card_idx], "4") == 0) {
+                               np->speed = 100;
+                               np->full_duplex = 1;
+                       } else if (strcmp (media[card_idx], "100mbps_hd") == 0
+                                  || strcmp (media[card_idx], "3") == 0) {
+                               np->speed = 100;
+                               np->full_duplex = 0;
+                       } else if (strcmp (media[card_idx], "10mbps_fd") == 0 ||
+                                  strcmp (media[card_idx], "2") == 0) {
+                               np->speed = 10;
+                               np->full_duplex = 1;
+                       } else if (strcmp (media[card_idx], "10mbps_hd") == 0 ||
+                                  strcmp (media[card_idx], "1") == 0) {
+                               np->speed = 10;
+                               np->full_duplex = 0;
+                       }
+                       /* Auto-Negotiation is mandatory for 1000BASE-T,
+                          IEEE 802.3ab Annex 28D page 14 */
+                       else if (strcmp (media[card_idx], "1000mbps_fd") == 0 ||
+                                strcmp (media[card_idx], "5") == 0 ||
+                                strcmp (media[card_idx], "1000mbps_hd") == 0 ||
+                                strcmp (media[card_idx], "6") == 0) {
+                               np->speed = 1000;
+                               np->full_duplex = 1;
+                               np->an_enable = 1;
+                       } else {
+                               np->an_enable = 1;
+                       }
+               }
+               if (jumbo[card_idx] != 0) {
+                       np->jumbo = 1;
+                       dev->mtu = 9000;
+               } else {
+                       np->jumbo = 0;
+                       if (mtu[card_idx] > 0 && mtu[card_idx] < PACKET_SIZE)
+                               dev->mtu = mtu[card_idx];
+               }
+               np->vlan = (vlan[card_idx] > 0 && vlan[card_idx] < 4096) ?
+                   vlan[card_idx] : 0;
+       }
+       dev->open = &rio_open;
+       dev->hard_start_xmit = &start_xmit;
+       dev->stop = &rio_close;
+       dev->get_stats = &get_stats;
+       dev->set_multicast_list = &set_multicast;
+       dev->do_ioctl = &rio_ioctl;
+       dev->tx_timeout = &tx_timeout;
+       dev->watchdog_timeo = TX_TIMEOUT;
+       dev->change_mtu = &change_mtu;
+#ifdef TX_HW_CHECKSUM
+       dev->features = NETIF_F_SG | NETIF_F_HW_CSUM;
+#endif
+       pci_set_drvdata (pdev, dev);
+
+       /* Parse eeprom data */
+       parse_eeprom (dev);
+
+       /* Find PHY address */
+       err = find_miiphy (dev);
+       if (err)
+               goto err_out_unmap;
+
+       /* Set media and reset PHY */
+       mii_set_media (dev);
+
+       /* Reset all logic functions */
+       writew (GlobalReset | DMAReset | FIFOReset | NetworkReset | HostReset,
+               ioaddr + ASICCtrl + 2);
+
+       err = register_netdev (dev);
+       if (err)
+               goto err_out_unmap;
+
+       card_idx++;
+
+       printk (KERN_INFO "%s: %s, %2x:%2x:%2x:%2x:%2x:%2x, IRQ %d\n",
+               dev->name, np->name,
+               dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
+               dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5],
+               irq);
+       return 0;
+
+err_out_unmap:
+#ifndef USE_IO_OPS
+       iounmap ((void *) ioaddr);
+
+err_out_dev:
+#endif
+       kfree (dev);
+
+err_out_res:
+       pci_release_regions (pdev);
+
+err_out_disable:
+       pci_disable_device (pdev);
+       return err;
+}
+
+int
+find_miiphy (struct net_device *dev)
+{
+       int i, phy_found = 0;
+       struct netdev_private *np;
+       long ioaddr;
+       np = dev->priv;
+       ioaddr = dev->base_addr;
+       np->phy_addr = 1;
+
+       for (i = 31; i >= 0; i--) {
+               int mii_status = mii_read (dev, i, 1);
+               if (mii_status != 0xffff && mii_status != 0x0000) {
+                       np->phy_addr = i;
+                       phy_found++;
+               }
+       }
+       if (!phy_found) {
+               printk (KERN_ERR "%s: No MII PHY found!\n", dev->name);
+               return -ENODEV;
+       }
+       return 0;
+}
+
+int
+parse_eeprom (struct net_device *dev)
+{
+       int i, j;
+       int ioaddr = dev->base_addr;
+       u8 sromdata[256];
+       u8 *psib;
+       u32 crc;
+       PSROM_t psrom = (PSROM_t) sromdata;
+       struct netdev_private *np = dev->priv;
+
+       int cid, next;
+
+       /* Read eeprom */
+       for (i = 0; i < 128; i++) {
+               ((u16 *) sromdata)[i] = le16_to_cpu (read_eeprom (ioaddr, i));
+       }
+
+       /* Check CRC */
+       crc = ~get_crc (sromdata, 256 - 4);
+       if (psrom->crc != ~get_crc (sromdata, 256 - 4)) {
+               printk (KERN_ERR "%s: EEPROM data CRC error.\n", dev->name);
+               return -1;
+       }
+
+       /* Set MAC address */
+       for (i = 0; i < 6; i++)
+               dev->dev_addr[i] = psrom->mac_addr[i];
+
+       /* Parse Software Infomation Block */
+       i = 0x30;
+       psib = (u8 *) sromdata;
+       do {
+               cid = psib[i++];
+               next = psib[i++];
+               if ((cid == 0 && next == 0) || (cid == 0xff && next == 0xff)) {
+                       printk (KERN_ERR "Cell data error\n");
+                       return -1;
+               }
+               switch (cid) {
+               case 0: /* Format version */
+                       break;
+               case 1: /* End of cell */
+                       return 0;
+               case 2: /* Duplex Polarity */
+                       np->duplex_polarity = psib[i];
+                       writeb (readb (ioaddr + PhyCtrl) | psib[i],
+                               ioaddr + PhyCtrl);
+                       break;
+               case 3: /* Wake Polarity */
+                       np->wake_polarity = psib[i];
+                       break;
+               case 9: /* Adapter description */
+                       j = (next - i > 255) ? 255 : next - i;
+                       memcpy (np->name, &(psib[i]), j);
+                       break;
+               case 4:
+               case 5:
+               case 6:
+               case 7:
+               case 8: /* Reversed */
+                       break;
+               default:        /* Unknown cell */
+                       return -1;
+               }
+               i = next;
+       } while (1);
+
+       return 0;
+}
+
+static int
+rio_open (struct net_device *dev)
+{
+       struct netdev_private *np = dev->priv;
+       long ioaddr = dev->base_addr;
+       int i;
+
+       i = request_irq (dev->irq, &rio_interrupt, SA_SHIRQ, dev->name, dev);
+       if (i)
+               return i;
+
+       /* DebugCtrl bit 4, 5, 9 must set */
+       writel (readl (ioaddr + DebugCtrl) | 0x0230, ioaddr + DebugCtrl);
+
+       /* Jumbo frame */
+       if (jumbo != 0)
+               writew (9014, ioaddr + MaxFrameSize);
+
+       alloc_list (dev);
+
+       /* Get station address */
+       for (i = 0; i < 6; i++)
+               writeb (dev->dev_addr[i], ioaddr + StationAddr0 + i);
+
+       set_multicast (dev);
+
+       /* Set RIO to poll every N*320nsec. */
+       writeb (0xff, ioaddr + RxDMAPollPeriod);
+       writeb (0xff, ioaddr + TxDMAPollPeriod);
+       netif_start_queue (dev);
+       writel (StatsEnable | RxEnable | TxEnable, ioaddr + MACCtrl);
+
+       /* VLAN supported */
+       if (np->vlan) {
+               /* priority field in RxDMAIntCtrl  */
+               writel (0x7 << 10, ioaddr + RxDMAIntCtrl);
+               /* VLANId */
+               writew (np->vlan, ioaddr + VLANId);
+               /* Length/Type should be 0x8100 */
+               writel (0x8100 << 16 | np->vlan, ioaddr + VLANTag);
+               /* Enable AutoVLANuntagging, but disable AutoVLANtagging.
+                  VLAN information tagged by TFC' VID, CFI fields. */
+               writel (readl (ioaddr + MACCtrl) | AutoVLANuntagging,
+                       ioaddr + MACCtrl);
+       }
+
+       /* Enable default interrupts */
+       EnableInt ();
+
+       /* clear statistics */
+       get_stats (dev);
+       return 0;
+}
+
+static void
+tx_timeout (struct net_device *dev)
+{
+       struct netdev_private *np = dev->priv;
+       long ioaddr = dev->base_addr;
+
+       printk (KERN_WARNING "%s: Transmit timed out, TxStatus %4.4x.\n",
+               dev->name, readl (ioaddr + TxStatus));
+       dev->if_port = 0;
+       dev->trans_start = jiffies;
+       np->stats.tx_errors++;
+       if (!np->tx_full)
+               netif_wake_queue (dev);
+}
+
+ /* allocate and initialize Tx and Rx descriptors */
+static void
+alloc_list (struct net_device *dev)
+{
+       struct netdev_private *np = dev->priv;
+       int i;
+
+       np->tx_full = 0;
+       np->cur_rx = np->cur_tx = 0;
+       np->old_rx = np->old_tx = 0;
+       np->rx_buf_sz = (dev->mtu <= 1500 ? PACKET_SIZE : dev->mtu + 32);
+       np->rx_head_desc = &np->rx_ring[0];
+
+       /* Initialize Tx descriptors, TFDListPtr leaves in start_xmit(). */
+       for (i = 0; i < TX_RING_SIZE; i++) {
+               np->tx_skbuff[i] = 0;
+               np->tx_ring[i].status = 0;
+       }
+
+       /* Initialize Rx descriptors */
+       for (i = 0; i < RX_RING_SIZE; i++) {
+               np->rx_ring[i].next_desc =
+                   virt_to_le64desc (&np->rx_ring[i + 1]);
+               np->rx_ring[i].status = 0;
+               np->rx_ring[i].fraginfo = 0;
+               np->rx_skbuff[i] = 0;
+       }
+
+       /* Chain the next pointer to the top */
+       np->rx_ring[i - 1].next_desc = virt_to_le64desc (&np->rx_ring[0]);
+
+       /* Allocate the rx buffers */
+       for (i = 0; i < RX_RING_SIZE; i++) {
+               /* Allocated fixed size of skbuff */
+               struct sk_buff *skb = dev_alloc_skb (np->rx_buf_sz);
+               np->rx_skbuff[i] = skb;
+               if (skb == NULL) {
+                       printk (KERN_ERR
+                               "%s: alloc_list: allocate Rx buffer error! ",
+                               dev->name);
+                       break;
+               }
+               skb->dev = dev; /* Mark as being used by this device. */
+               skb_reserve (skb, 2);   /* 16 byte align the IP header. */
+               /* Rubicon now supports 40 bits of addressing space. */
+               np->rx_ring[i].fraginfo = virt_to_le64desc (skb->tail);
+               np->rx_ring[i].fraginfo |= cpu_to_le64 (np->rx_buf_sz) << 48;
+       }
+
+       /* Set RFDListPtr */
+       writel (cpu_to_le32 (virt_to_bus (&np->rx_ring[0])),
+               dev->base_addr + RFDListPtr0);
+       writel (0, dev->base_addr + RFDListPtr1);
+
+       return;
+}
+
+static int
+start_xmit (struct sk_buff *skb, struct net_device *dev)
+{
+       struct netdev_private *np = dev->priv;
+       struct netdev_desc *txdesc;
+       unsigned entry;
+       u32 ioaddr;
+
+       ioaddr = dev->base_addr;
+       entry = np->cur_tx % TX_RING_SIZE;
+       np->tx_skbuff[entry] = skb;
+       txdesc = &np->tx_ring[entry];
+       txdesc->next_desc = 0;
+
+       /* Set TFDDone to avoid TxDMA gather this descriptor */
+       txdesc->status = cpu_to_le64 (TFDDone);
+       txdesc->status |=
+           cpu_to_le64 (entry | WordAlignDisable | (1 << FragCountShift));
+#ifdef TX_HW_CHECKSUM
+       if (skb->ip_summed == CHECKSUM_HW) {
+               txdesc->status |=
+                   cpu_to_le64 (TCPChecksumEnable | UDPChecksumEnable |
+                                IPChecksumEnable);
+       }
+#endif
+       if (np->vlan) {
+               txdesc->status |= cpu_to_le64 (VLANTagInsert |
+                                              cpu_to_le64 (vlan) << 32 |
+                                              cpu_to_le64 (skb->
+                                                           priority) << 45);
+       }
+
+       /* Send one packet each time at 10Mbps mode */
+       if (entry % 0x08 == 0 || np->speed == 10)
+               txdesc->status |= cpu_to_le64 (TxIndicate);
+       txdesc->fraginfo = virt_to_le64desc (skb->data);
+       txdesc->fraginfo |= cpu_to_le64 (skb->len) << 48;
+
+       /* Chain the last descriptor's pointer to this one */
+       if (np->last_tx)
+               np->last_tx->next_desc = virt_to_le64desc (txdesc);
+       np->last_tx = txdesc;
+
+       /* Clear TFDDone, then TxDMA start to send this descriptor */
+       txdesc->status &= ~cpu_to_le64 (TFDDone);
+
+       DEBUG_TFD_DUMP (np);
+
+       /* TxDMAPollNow */
+       writel (readl (ioaddr + DMACtrl) | 0x00001000, ioaddr + DMACtrl);
+       np->cur_tx++;
+
+       if (np->cur_tx - np->old_tx < TX_QUEUE_LEN - 1 && np->speed != 10) {
+               /* do nothing */
+       } else {
+               np->tx_full = 1;
+               netif_stop_queue (dev);
+       }
+
+       /* The first TFDListPtr */
+       if (readl (dev->base_addr + TFDListPtr0) == 0) {
+               writel (virt_to_bus (&np->tx_ring[entry]),
+                       dev->base_addr + TFDListPtr0);
+               writel (0, dev->base_addr + TFDListPtr1);
+       }
+
+       /* NETDEV WATCHDOG timer */
+       dev->trans_start = jiffies;
+       return 0;
+}
+
+static void
+rio_interrupt (int irq, void *dev_instance, struct pt_regs *rgs)
+{
+       struct net_device *dev = dev_instance;
+       struct netdev_private *np;
+       unsigned int_status;
+       long ioaddr;
+       int cnt = max_intrloop;
+
+       ioaddr = dev->base_addr;
+       np = dev->priv;
+       spin_lock (&np->lock);
+       while (1) {
+               int_status = readw (ioaddr + IntStatus);
+               writew (int_status & (HostError | TxComplete | RxComplete |
+                                     IntRequested | UpdateStats | LinkEvent |
+                                     TxDMAComplete | RxDMAComplete | RFDListEnd
+                                     | RxDMAPriority), ioaddr + IntStatus);
+               if (int_status == 0)
+                       break;
+               /* Processing received packets */
+               receive_packet (dev);
+               /* TxComplete interrupt */
+               if (int_status & TxComplete) {
+                       int cnt = 20;
+                       int tx_status = readl (ioaddr + TxStatus);
+                       while (tx_status & 0x80) {      /* TxComplete */
+                               /* Handle TxError */
+                               if (tx_status & 0x01)
+                                       tx_error (dev, tx_status);
+                               tx_status = readl (ioaddr + TxStatus);
+                               /* too much TxError */
+                               if (--cnt < 0)
+                                       break;
+                       }
+                       /* Send one packet each time at 10Mbps mode */
+                       if (np->speed == 10) {
+                               np->tx_full = 0;
+                               netif_wake_queue (dev);
+                       }
+               }
+               /* Free used tx skbuffs */
+               for (; np->cur_tx - np->old_tx > 0; np->old_tx++) {
+                       int entry = np->old_tx % TX_RING_SIZE;
+                       if (!(np->tx_ring[entry].status & TFDDone))
+                               break;
+                       dev_kfree_skb_irq (np->tx_skbuff[entry]);
+                       np->tx_skbuff[entry] = 0;
+               }
+               /* If the ring is no longer full, clear tx_full and 
+                  call netif_wake_queue() */
+               if (np->tx_full && np->cur_tx - np->old_tx < TX_QUEUE_LEN - 1) {
+                       np->tx_full = 0;
+                       netif_wake_queue (dev);
+               }
+
+               /* Handle uncommon events */
+               if (int_status &
+                   (IntRequested | HostError | LinkEvent | UpdateStats))
+                       rio_error (dev, int_status);
+               /* If too much interrupts here, disable all interrupts except 
+                  IntRequest. When CountDown down to 0, IntRequest will 
+                  be caught by rio_error() to recovery the interrupts */
+               if (--cnt < 0) {
+                       get_stats (dev);
+                       writel (1000, ioaddr + CountDown);
+                       writew (IntRequested, ioaddr + IntEnable);
+                       break;
+               }
+       }
+       spin_unlock (&np->lock);
+}
+
+static void
+tx_error (struct net_device *dev, int tx_status)
+{
+       struct netdev_private *np;
+       long ioaddr = dev->base_addr;
+       int frame_id;
+       int i;
+
+       np = dev->priv;
+
+       frame_id = (tx_status & 0xffff0000) >> 16;
+       printk (KERN_ERR "%s: Transmit error, TxStatus %4.4x, FrameId %d.\n",
+               dev->name, tx_status, frame_id);
+       np->stats.tx_errors++;
+       np->stats.tx_dropped++;
+       /* Ttransmit Underrun */
+       if (tx_status & 0x10) {
+               np->stats.tx_fifo_errors++;
+               /* Transmit Underrun need to set TxReset, DMARest, FIFOReset */
+               writew (TxReset | DMAReset | FIFOReset, ioaddr + ASICCtrl + 2);
+               /* Wait for ResetBusy bit clear */
+               for (i = 50; i > 0; i--) {
+                       if ((readw (ioaddr + ASICCtrl + 2) & ResetBusy) == 0)
+                               break;
+                       mdelay (1);
+               }
+               /* Reset TFDListPtr */
+               writel (virt_to_bus (&np->tx_ring[frame_id]),
+                       dev->base_addr + TFDListPtr0);
+               writel (0, dev->base_addr + TFDListPtr1);
+
+               /* Let TxStartThresh stay default value */
+       }
+       /* Late Collision */
+       if (tx_status & 0x04) {
+               np->stats.tx_fifo_errors++;
+               /* TxReset and clear FIFO */
+               writew (TxReset | FIFOReset, ioaddr + ASICCtrl + 2);
+               /* Wait reset done */
+               for (i = 50; i > 0; i--) {
+                       if ((readw (ioaddr + ASICCtrl + 2) & ResetBusy) == 0)
+                               break;
+                       mdelay (1);
+               }
+               /* Let TxStartThresh stay default value */
+       }
+       /* Maximum Collisions */
+#ifdef ETHER_STATS
+       if (tx_status & 0x08)
+               np->stats.collisions16++;
+#else
+       if (tx_status & 0x08)
+               np->stats.collisions++;
+#endif
+
+       /* Restart the Tx. */
+       writel (readw (dev->base_addr + MACCtrl) | TxEnable, ioaddr + MACCtrl);
+}
+
+/* Every interrupts go into here to see if any packet need to process, this
+   ensure Rx rings keep full in a critical cases of Rx rings ran out */
+static int
+receive_packet (struct net_device *dev)
+{
+       struct netdev_private *np = (struct netdev_private *) dev->priv;
+       int entry = np->cur_rx % RX_RING_SIZE;
+       int cnt = np->old_rx + RX_RING_SIZE - np->cur_rx;
+
+       DEBUG_RFD_DUMP (np, 1);
+       /* If RFDDone, FrameStart and FrameEnd set, there is a new packet in. */
+       while (np->rx_head_desc->status & RFDDone &&
+              np->rx_head_desc->status & FrameStart &&
+              np->rx_head_desc->status & FrameEnd) {
+               struct netdev_desc *desc = np->rx_head_desc;
+               u64 frame_status = le64_to_cpu (desc->status);
+               int pkt_len = le64_to_cpu (desc->status & 0xffff);      /* Chip omits the CRC. */
+
+               if (--cnt < 0)
+                       break;
+               DEBUG_PKT_DUMP (np, pkt_len);
+               /* Update rx error statistics, drop packet. */
+               if (frame_status & 0x003f0000) {
+                       np->stats.rx_errors++;
+                       if (frame_status & 0x00100000)
+                               np->stats.rx_length_errors++;
+                       if (frame_status & 0x00010000)
+                               np->stats.rx_fifo_errors++;
+                       if (frame_status & 0x00060000)
+                               np->stats.rx_frame_errors++;
+                       if (frame_status & 0x00080000)
+                               np->stats.rx_crc_errors++;
+               } else {
+                       struct sk_buff *skb;
+                       /* Small skbuffs for short packets */
+                       if (pkt_len > copy_thresh) {
+                               skb_put (skb = np->rx_skbuff[entry], pkt_len);
+                               np->rx_skbuff[entry] = NULL;
+                       } else if ((skb = dev_alloc_skb (pkt_len + 2)) != NULL) {
+                               skb->dev = dev;
+                               skb_reserve (skb, 2);   /* 16 byte align the IP header */
+                               eth_copy_and_sum (skb,
+                                                 np->rx_skbuff[entry]->tail,
+                                                 pkt_len, 0);
+                               skb_put (skb, pkt_len);
+                       }
+                       skb->protocol = eth_type_trans (skb, dev);
+#ifdef RX_HW_CHECKSUM
+                       /* Checksum done by hw, but csum value unavailable. */
+                       if (!(frame_status & (TCPError | UDPError | IPError))) {
+                               skb->ip_summed = CHECKSUM_UNNECESSARY;
+                       }
+#endif
+                       netif_rx (skb);
+                       dev->last_rx = jiffies;
+               }
+               entry = (++np->cur_rx) % RX_RING_SIZE;
+               np->rx_head_desc = &np->rx_ring[entry];
+       }
+
+       /* Re-allocate skbuffs to fill the descriptor ring */
+       for (; np->cur_rx - np->old_rx > 0; np->old_rx++) {
+               struct sk_buff *skb;
+               entry = np->old_rx % RX_RING_SIZE;
+               /* Dropped packets don't need to re-allocate */
+               if (np->rx_skbuff[entry] == NULL) {
+                       skb = dev_alloc_skb (np->rx_buf_sz);
+                       if (skb == NULL) {
+                               np->rx_ring[entry].fraginfo = 0;
+                               printk (KERN_ERR
+                                       "%s: Allocate Rx buffer error!",
+                                       dev->name);
+                               break;
+                       }
+                       np->rx_skbuff[entry] = skb;
+                       skb->dev = dev;
+                       skb_reserve (skb, 2);   /* 16 byte align the IP header */
+                       np->rx_ring[entry].fraginfo =
+                           virt_to_le64desc (skb->tail);
+               }
+               np->rx_ring[entry].fraginfo |=
+                   cpu_to_le64 (np->rx_buf_sz) << 48;
+               np->rx_ring[entry].status = 0;
+       }
+       /* RxDMAPollNow */
+       writel (readl (dev->base_addr + DMACtrl) | 0x00000010,
+               dev->base_addr + DMACtrl);
+
+       DEBUG_RFD_DUMP (np, 2);
+       return 0;
+}
+
+static void
+rio_error (struct net_device *dev, int int_status)
+{
+       long ioaddr = dev->base_addr;
+       struct netdev_private *np = dev->priv;
+
+       /* Stop the down counter and recovery the interrupt */
+       if (int_status & IntRequested) {
+
+               writew (0, ioaddr + IntEnable);
+               writel (0, ioaddr + CountDown);
+               /* Enable default interrupts */
+               EnableInt ();
+       }
+
+       /* Link change event */
+       if (int_status & LinkEvent) {
+               if (mii_wait_link (dev, 10) == 0) {
+                       printk (KERN_INFO "%s: Link up\n", dev->name);
+                       if (np->an_enable) {
+                               /* Auto-Negotiation mode */
+                               mii_get_media (dev);
+                               if (np->full_duplex) {
+                                       writew (readw (dev->base_addr + MACCtrl)
+                                               | DuplexSelect,
+                                               ioaddr + MACCtrl);
+                               }
+                       }
+               } else {
+                       printk (KERN_INFO "%s: Link off\n", dev->name);
+               }
+       }
+
+       /* UpdateStats statistics registers */
+       if (int_status & UpdateStats) {
+               get_stats (dev);
+       }
+
+       /* PCI Error, a catastronphic error related to the bus interface 
+          occurs, set GlobalReset and HostReset to reset. */
+       if (int_status & HostError) {
+               printk (KERN_ERR "%s: PCI Error! IntStatus %4.4x.\n",
+                       dev->name, int_status);
+               writew (GlobalReset | HostReset, ioaddr + ASICCtrl + 2);
+               mdelay (500);
+       }
+}
+
+static struct net_device_stats *
+get_stats (struct net_device *dev)
+{
+       long ioaddr = dev->base_addr;
+       struct netdev_private *np = dev->priv;
+       u16 temp1;
+       u16 temp2;
+       int i;
+       /* All statistics registers need to acknowledge,
+          else overflow could cause some problem */
+       np->stats.rx_packets += readl (ioaddr + FramesRcvOk);
+       np->stats.tx_packets += readl (ioaddr + FramesXmtOk);
+       np->stats.rx_bytes += readl (ioaddr + OctetRcvOk);
+       np->stats.tx_bytes += readl (ioaddr + OctetXmtOk);
+       temp1 = readw (ioaddr + FrameLostRxError);
+       np->stats.rx_errors += temp1;
+       np->stats.rx_missed_errors += temp1;
+       np->stats.tx_dropped += readw (ioaddr + FramesAbortXSColls);
+       temp1 = readl (ioaddr + SingleColFrames) +
+           readl (ioaddr + MultiColFrames) + readl (ioaddr + LateCollisions);
+       temp2 = readw (ioaddr + CarrierSenseErrors);
+       np->stats.tx_carrier_errors += temp2;
+       np->stats.tx_errors += readw (ioaddr + FramesWEXDeferal) +
+           readl (ioaddr + FramesWDeferredXmt) + temp2;
+
+       /* detailed rx_error */
+       np->stats.rx_length_errors += readw (ioaddr + InRangeLengthErrors) +
+           readw (ioaddr + FrameTooLongErrors);
+       np->stats.rx_crc_errors += readw (ioaddr + FrameCheckSeqError);
+
+       /* Clear all other statistic register. */
+       readw (ioaddr + MacControlFramesXmtd);
+       readw (ioaddr + BcstFramesXmtdOk);
+       readl (ioaddr + McstFramesXmtdOk);
+       readl (ioaddr + BcstOctetXmtOk);
+       readl (ioaddr + McstOctetXmtOk);
+       readw (ioaddr + MacControlFramesRcvd);
+       readw (ioaddr + BcstFramesRcvOk);
+       readl (ioaddr + McstFramesRcvOk);
+       readl (ioaddr + BcstOctetRcvOk);
+
+       for (i = 0x100; i <= 0x150; i += 4)
+               readl (ioaddr + i);
+       readw (ioaddr + TxJumboFrames);
+       readw (ioaddr + RxJumboFrames);
+       readw (ioaddr + TCPCheckSumErrors);
+       readw (ioaddr + UDPCheckSumErrors);
+       readw (ioaddr + IPCheckSumErrors);
+       return &np->stats;
+}
+
+int
+change_mtu (struct net_device *dev, int new_mtu)
+{
+       int max = (jumbo) ? 9000 : 1536;
+
+       if ((new_mtu < 68) || (new_mtu > max)) {
+               return -EINVAL;
+       }
+
+       dev->mtu = new_mtu;
+
+       return 0;
+}
+
+#define CRC_POLY 0xedb88320
+static unsigned
+get_crc (unsigned char *p, int len)
+{
+       int bit;
+       unsigned char byte;
+       unsigned crc = 0xffffffff;
+
+       while (--len >= 0) {
+               byte = *p++;
+               for (bit = 0; bit < 8; bit++, byte >>= 1) {
+                       crc = (crc >> 1) ^ (((crc ^ byte) & 1) ? CRC_POLY : 0);
+               }
+       }
+       return crc;
+}
+
+static void
+set_multicast (struct net_device *dev)
+{
+       long ioaddr = dev->base_addr;
+       u32 hash_table[2];
+       u16 rx_mode = 0;
+       int i;
+       struct dev_mc_list *mclist;
+       struct netdev_private *np = dev->priv;
+
+       /* Default: receive broadcast and unicast */
+       rx_mode = ReceiveBroadcast | ReceiveUnicast;
+       if (dev->flags & IFF_PROMISC) {
+               /* Receive all frames promiscuously. */
+               rx_mode |= ReceiveAllFrames;
+       } else
+           if (((dev->flags & IFF_MULTICAST)
+                && (dev->mc_count > multicast_filter_limit))
+               || (dev->flags & IFF_ALLMULTI)) {
+               /* Receive broadcast and multicast frames */
+               rx_mode |= ReceiveBroadcast | ReceiveMulticast | ReceiveUnicast;
+       } else if ((dev->flags & IFF_MULTICAST) & (dev->mc_count > 0)) {
+               /* Receive broadcast frames and multicast frames filtering by Hashtable */
+               rx_mode |=
+                   ReceiveBroadcast | ReceiveMulticastHash | ReceiveUnicast;
+       }
+       if (np->vlan) {
+               /* ReceiveVLANMatch field in ReceiveMode */
+               rx_mode |= ReceiveVLANMatch;
+       }
+       hash_table[0] = 0x00000000;
+       hash_table[1] = 0x00000000;
+
+       for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
+            i++, mclist = mclist->next) {
+               set_bit (get_crc (mclist->dmi_addr, ETH_ALEN) & 0x3f,
+                        hash_table);
+       }
+       writel (hash_table[0], ioaddr + HashTable0);
+       writel (hash_table[1], ioaddr + HashTable1);
+       writew (rx_mode, ioaddr + ReceiveMode);
+}
+
+static int
+rio_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
+{
+       int phy_addr;
+       struct netdev_private *np = dev->priv;
+       struct mii_data *miidata = (struct mii_data *) &rq->ifr_data;
+#ifdef RIO_DEBUG
+       struct ioctl_data *iodata = (struct ioctl_data *) (rq->ifr_data);
+#endif
+       u16 *data = (u16 *) & rq->ifr_data;
+       struct netdev_desc *desc;
+       int i;
+
+       phy_addr = np->phy_addr;
+       switch (cmd) {
+       case SIOCDEVPRIVATE:
+#ifdef RIO_DEBUG
+               if (rio_ioctl_ext (dev, iodata) != 0)
+                       return -EOPNOTSUPP;
+               break;
+#else
+               return -EOPNOTSUPP;
+#endif
+       case SIOCDEVPRIVATE + 1:
+               miidata->out_value = mii_read (dev, phy_addr, miidata->reg_num);
+               break;
+       case SIOCDEVPRIVATE + 2:
+               mii_write (dev, phy_addr, miidata->reg_num, miidata->in_value);
+               break;
+       case SIOCDEVPRIVATE + 3:
+               np->rx_debug = (data[0] <= 7) ? data[0] : 0;
+               printk ("rx_debug = %d\n", np->rx_debug);
+               break;
+       case SIOCDEVPRIVATE + 4:
+               np->tx_debug = (data[0] <= 7) ? data[0] : 0;
+               printk ("tx_debug = %d\n", np->tx_debug);
+               break;
+       case SIOCDEVPRIVATE + 5:
+               np->tx_full = 1;
+               netif_stop_queue (dev);
+               break;
+       case SIOCDEVPRIVATE + 6:
+               np->tx_full = 0;
+               netif_wake_queue (dev);
+               break;
+       case SIOCDEVPRIVATE + 7:
+               printk ("tx_full=%x cur_tx=%x old_tx=%x cur_rx=%x old_rx=%x\n",
+                       (u32) np->tx_full, (u32) np->cur_tx, (u32) np->old_tx,
+                       (u32) np->cur_rx, (u32) np->old_rx);
+               break;
+       case SIOCDEVPRIVATE + 8:
+               for (i = 0; i < TX_RING_SIZE; i++) {
+                       desc = &np->tx_ring[i];
+                       printk
+                           ("cur:%08x next:%08x status:%08x frag1:%08x frag0:%08x",
+                            (u32) virt_to_bus (desc), (u32) desc->next_desc,
+                            (u32) desc->status, (u32) (desc->fraginfo >> 32),
+                            (u32) desc->fraginfo);
+                       printk ("\n");
+               }
+               printk ("\n");
+               break;
+       default:
+               return -EOPNOTSUPP;
+       }
+       return 0;
+}
+
+#ifdef RIO_DEBUG
+int
+rio_ioctl_ext (struct net_device *dev, struct ioctl_data *iodata)
+{
+       struct netdev_private *np = dev->priv;
+       int phy_addr = np->phy_addr;
+       u32 hi, lo;
+       int i;
+       BMCR_t bmcr;
+       BMSR_t bmsr;
+
+       if (iodata == NULL)
+               goto invalid_cmd;
+       if (strcmp (iodata->signature, "rio") != 0)
+               goto invalid_cmd;
+
+       switch (iodata->cmd) {
+       case 0:
+               for (i = 0; i < TX_RING_SIZE; i++) {
+                       hi = np->tx_ring[i].status >> 32;
+                       lo = np->tx_ring[i].status;
+                       printk ("TFC=%08x %08x \n", hi, lo);
+
+               }
+               break;
+       case 1:
+               for (i = 0; i < RX_RING_SIZE; i++) {
+                       hi = np->rx_ring[i].status >> 32;
+                       lo = np->rx_ring[i].status;
+                       printk ("RFS=%08x %08x \n", hi, lo);
+               }
+               break;
+       case 2:
+               break;
+       case 3:
+               if (iodata->data != NULL)
+                       np->tx_debug = iodata->data[0];
+               break;
+       case 4:
+               /* Soft reset PHY */
+               mii_write (dev, phy_addr, MII_BMCR, MII_BMCR_RESET);
+               bmcr.image = 0;
+               bmcr.bits.an_enable = 1;
+               bmcr.bits.reset = 1;
+               mii_write (dev, phy_addr, MII_BMCR, bmcr.image);
+               break;
+       case 5:
+               mii_write (dev, phy_addr, MII_BMCR, 0x1940);
+               mdelay (10);
+               mii_write (dev, phy_addr, MII_BMCR, 0x1940);
+               mdelay (100);   /* wait a certain time */
+               break;
+       case 6:
+               /* 5) Set media and Power Up */
+               bmcr.image = 0;
+               bmcr.bits.power_down = 1;
+               if (np->an_enable) {
+                       bmcr.bits.an_enable = 1;
+               } else {
+                       if (np->speed == 100) {
+                               bmcr.bits.speed100 = 1;
+                               bmcr.bits.speed1000 = 0;
+                               printk ("Manual 100 Mbps, ");
+                       } else if (np->speed == 10) {
+                               bmcr.bits.speed100 = 0;
+                               bmcr.bits.speed1000 = 0;
+                               printk ("Manual 10 Mbps, ");
+                       }
+                       if (np->full_duplex) {
+                               bmcr.bits.duplex_mode = 1;
+                               printk ("Full duplex. \n");
+                       } else {
+                               bmcr.bits.duplex_mode = 0;
+                               printk ("Half duplex.\n");
+                       }
+               }
+               mii_write (dev, phy_addr, MII_BMCR, bmcr.image);
+               break;
+       case 7:
+               bmcr.image = mii_read (dev, phy_addr, MII_BMCR);
+               bmsr.image = mii_read (dev, phy_addr, MII_BMSR);
+               printk ("BMCR=%x BMSR=%x LinkUp=%d\n",
+                       bmcr.image, bmsr.image, bmsr.bits.link_status);
+               break;
+
+       default:
+               return -EOPNOTSUPP;
+       }
+       return 0;
+
+invalid_cmd:
+       return -1;
+}
+#endif
+#define EEP_READ 0x0200
+#define EEP_BUSY 0x8000
+/* Read the EEPROM word */
+int
+read_eeprom (long ioaddr, int eep_addr)
+{
+       int i = 1000;
+       writew (EEP_READ | (eep_addr & 0xff), ioaddr + EepromCtrl);
+       while (i-- > 0) {
+               if (!(readw (ioaddr + EepromCtrl) & EEP_BUSY)) {
+                       return readw (ioaddr + EepromData);
+               }
+       }
+       return 0;
+}
+
+enum phy_ctrl_bits {
+       MII_READ = 0x00, MII_CLK = 0x01, MII_DATA1 = 0x02, MII_WRITE = 0x04,
+       MII_DUPLEX = 0x08,
+};
+
+#define mii_delay() readb(ioaddr)
+static void
+mii_sendbit (struct net_device *dev, u32 data)
+{
+       int ioaddr = dev->base_addr + PhyCtrl;
+       data = (data) ? MII_DATA1 : 0;
+       data |= MII_WRITE;
+       data |= (readb (ioaddr) & 0xf8) | MII_WRITE;
+       writeb (data, ioaddr);
+       mii_delay ();
+       writeb (data | MII_CLK, ioaddr);
+       mii_delay ();
+}
+
+static int
+mii_getbit (struct net_device *dev)
+{
+       int ioaddr = dev->base_addr + PhyCtrl;
+       u8 data;
+
+       data = (readb (ioaddr) & 0xf8) | MII_READ;
+       writeb (data, ioaddr);
+       mii_delay ();
+       writeb (data | MII_CLK, ioaddr);
+       mii_delay ();
+       return ((readb (ioaddr) >> 1) & 1);
+}
+
+static void
+mii_send_bits (struct net_device *dev, u32 data, int len)
+{
+       int i;
+       for (i = len - 1; i >= 0; i--) {
+               mii_sendbit (dev, data & (1 << i));
+       }
+}
+
+static int
+mii_read (struct net_device *dev, int phy_addr, int reg_num)
+{
+       u32 cmd;
+       int i;
+       u32 retval = 0;
+
+       /* Preamble */
+       mii_send_bits (dev, 0xffffffff, 32);
+       /* ST(2), OP(2), ADDR(5), REG#(5), TA(2), Data(16) total 32 bits */
+       /* ST,OP = 0110'b for read operation */
+       cmd = (0x06 << 10 | phy_addr << 5 | reg_num);
+       mii_send_bits (dev, cmd, 14);
+       /* Turnaround */
+       if (mii_getbit (dev))
+               goto err_out;
+       /* Read data */
+       for (i = 0; i < 16; i++) {
+               retval |= mii_getbit (dev);
+               retval <<= 1;
+       }
+       /* End cycle */
+       mii_getbit (dev);
+       return (retval >> 1) & 0xffff;
+
+err_out:
+       return 0;
+}
+static int
+mii_write (struct net_device *dev, int phy_addr, int reg_num, u16 data)
+{
+       u32 cmd;
+
+       /* Preamble */
+       mii_send_bits (dev, 0xffffffff, 32);
+       /* ST(2), OP(2), ADDR(5), REG#(5), TA(2), Data(16) total 32 bits */
+       /* ST,OP,AAAAA,RRRRR,TA = 0101xxxxxxxxxx10'b = 0x0502 for write */
+       cmd = (0x5002 << 16) | (phy_addr << 23) | (reg_num << 18) | data;
+       mii_send_bits (dev, cmd, 32);
+       /* End cycle */
+       mii_getbit (dev);
+       return 0;
+}
+static int
+mii_wait_link (struct net_device *dev, int wait)
+{
+       BMSR_t bmsr;
+       int phy_addr;
+       struct netdev_private *np;
+
+       np = dev->priv;
+       phy_addr = np->phy_addr;
+
+       do {
+               bmsr.image = mii_read (dev, phy_addr, MII_BMSR);
+               if (bmsr.bits.link_status)
+                       return 0;
+               mdelay (1);
+       } while (--wait > 0);
+       return -1;
+}
+static int
+mii_get_media (struct net_device *dev)
+{
+       ANAR_t negotiate;
+       BMSR_t bmsr;
+       BMCR_t bmcr;
+       MSCR_t mscr;
+       MSSR_t mssr;
+       int phy_addr;
+       struct netdev_private *np;
+
+       np = dev->priv;
+       phy_addr = np->phy_addr;
+
+       bmsr.image = mii_read (dev, phy_addr, MII_BMSR);
+       if (np->an_enable) {
+               if (!bmsr.bits.an_complete) {
+                       /* Auto-Negotiation not completed */
+                       return -1;
+               }
+               negotiate.image = mii_read (dev, phy_addr, MII_ANAR) &
+                   mii_read (dev, phy_addr, MII_ANLPAR);
+               mscr.image = mii_read (dev, phy_addr, MII_MSCR);
+               mssr.image = mii_read (dev, phy_addr, MII_MSSR);
+               if (mscr.bits.media_1000BT_FD & mssr.bits.lp_1000BT_FD) {
+                       np->speed = 1000;
+                       np->full_duplex = 1;
+                       printk (KERN_INFO "Auto 1000BaseT, Full duplex.\n");
+               } else if (mscr.bits.media_1000BT_HD & mssr.bits.lp_1000BT_HD) {
+                       np->speed = 1000;
+                       np->full_duplex = 0;
+                       printk (KERN_INFO "Auto 1000BaseT, Half duplex.\n");
+               } else if (negotiate.bits.media_100BX_FD) {
+                       np->speed = 100;
+                       np->full_duplex = 1;
+                       printk (KERN_INFO "Auto 100BaseT, Full duplex.\n");
+               } else if (negotiate.bits.media_100BX_HD) {
+                       np->speed = 100;
+                       np->full_duplex = 0;
+                       printk (KERN_INFO "Auto 100BaseT, Half duplex.\n");
+               } else if (negotiate.bits.media_10BT_FD) {
+                       np->speed = 10;
+                       np->full_duplex = 1;
+                       printk (KERN_INFO "Auto 10BaseT, Full duplex.\n");
+               } else if (negotiate.bits.media_10BT_HD) {
+                       np->speed = 10;
+                       np->full_duplex = 0;
+                       printk (KERN_INFO "Auto 10BaseT, Half duplex.\n");
+               }
+       } else {
+               bmcr.image = mii_read (dev, phy_addr, MII_BMCR);
+               if (bmcr.bits.speed100 == 1 && bmcr.bits.speed1000 == 0) {
+                       printk (KERN_INFO "Operating at 100 Mbps, ");
+               } else if (bmcr.bits.speed100 == 0 && bmcr.bits.speed1000 == 0) {
+                       printk (KERN_INFO "Operating at 10 Mbps, ");
+               } else if (bmcr.bits.speed100 == 0 && bmcr.bits.speed1000 == 1) {
+                       printk (KERN_INFO "Operating at 1000 Mbps, ");
+               }
+               if (bmcr.bits.duplex_mode) {
+                       printk ("Full duplex.\n");
+               } else {
+                       printk ("Half duplex.\n");
+               }
+       }
+       return 0;
+}
+
+static int
+mii_set_media (struct net_device *dev)
+{
+       PHY_SCR_t pscr;
+       BMCR_t bmcr;
+       BMSR_t bmsr;
+       ANAR_t anar;
+       int phy_addr;
+       struct netdev_private *np;
+       np = dev->priv;
+       phy_addr = np->phy_addr;
+
+       /* Does user set speed? */
+       if (np->an_enable) {
+               /* Reset to enable Auto-Negotiation */
+               bmsr.image = mii_read (dev, phy_addr, MII_BMSR);
+               anar.image = mii_read (dev, phy_addr, MII_ANAR);
+               anar.bits.media_100BX_FD = bmsr.bits.media_100BX_FD;
+               anar.bits.media_100BX_HD = bmsr.bits.media_100BX_HD;
+               anar.bits.media_100BT4 = bmsr.bits.media_100BT4;
+               anar.bits.media_10BT_FD = bmsr.bits.media_10BT_FD;
+               anar.bits.media_10BT_HD = bmsr.bits.media_10BT_HD;
+               mii_write (dev, phy_addr, MII_ANAR, anar.image);
+
+               /* Enable Auto crossover */
+               pscr.image = mii_read (dev, phy_addr, MII_PHY_SCR);
+               pscr.bits.mdi_crossover_mode = 3;       /* 11'b */
+               mii_write (dev, phy_addr, MII_PHY_SCR, pscr.image);
+               /* Soft reset PHY */
+               mii_write (dev, phy_addr, MII_BMCR, MII_BMCR_RESET);
+               bmcr.image = 0;
+               bmcr.bits.an_enable = 1;
+               bmcr.bits.reset = 1;
+               mii_write (dev, phy_addr, MII_BMCR, bmcr.image);
+               /* Wait for Link up, link up need a certain time */
+               if (mii_wait_link (dev, 3200) != 0) {
+                       printk (KERN_INFO "Link time out\n");
+               }
+               mdelay (1);
+               mii_get_media (dev);
+       } else {
+               /* Force speed setting */
+               /* 1) Disable Auto crossover */
+               pscr.image = mii_read (dev, phy_addr, MII_PHY_SCR);
+               pscr.bits.mdi_crossover_mode = 0;
+               mii_write (dev, phy_addr, MII_PHY_SCR, pscr.image);
+
+               /* 2) PHY Reset */
+               bmcr.image = mii_read (dev, phy_addr, MII_BMCR);
+               bmcr.bits.reset = 1;
+               mii_write (dev, phy_addr, MII_BMCR, bmcr.image);
+
+               /* 3) Power Down */
+               bmcr.image = 0x1940;    /* must be 0x1940 */
+               mii_write (dev, phy_addr, MII_BMCR, bmcr.image);
+               mdelay (10);    /* wait a certain time */
+
+               /* 4) Advertise nothing */
+               mii_write (dev, phy_addr, MII_ANAR, 0);
+
+               /* 5) Set media and Power Up */
+               bmcr.image = 0;
+               bmcr.bits.power_down = 1;
+               if (np->speed == 100) {
+                       bmcr.bits.speed100 = 1;
+                       bmcr.bits.speed1000 = 0;
+                       printk (KERN_INFO "Manual 100 Mbps, ");
+               } else if (np->speed == 10) {
+                       bmcr.bits.speed100 = 0;
+                       bmcr.bits.speed1000 = 0;
+                       printk (KERN_INFO "Manual 10 Mbps, ");
+               }
+               if (np->full_duplex) {
+                       bmcr.bits.duplex_mode = 1;
+                       printk ("Full duplex. \n");
+               } else {
+                       bmcr.bits.duplex_mode = 0;
+                       printk ("Half duplex.\n");
+               }
+#if 0
+               /* Set 1000BaseT Master/Slave setting */
+               mscr.image = mii_read (dev, phy_addr, MII_MSCR);
+               mscr.bits.cfg_enable = 1;
+               mscr.bits.cfg_value = 0;
+#endif
+               mii_write (dev, phy_addr, MII_BMCR, bmcr.image);
+
+               /* Wait for Link up, link up need a certain time */
+               if (mii_wait_link (dev, 3200) != 0) {
+                       printk (KERN_INFO "Link time out\n");
+               }
+               mii_get_media (dev);
+       }
+       return 0;
+}
+
+static int
+rio_close (struct net_device *dev)
+{
+       long ioaddr = dev->base_addr;
+       struct netdev_private *np = dev->priv;
+       int i;
+
+       netif_stop_queue (dev);
+
+       /* Disable interrupts */
+       writew (0, ioaddr + IntEnable);
+
+       /* Stop Tx and Rx logics */
+       writel (TxDisable | RxDisable | StatsDisable, ioaddr + MACCtrl);
+       synchronize_irq ();
+       free_irq (dev->irq, dev);
+
+       /* Free all the skbuffs in the queue. */
+       for (i = 0; i < RX_RING_SIZE; i++) {
+               np->rx_ring[i].status = 0;
+               np->rx_ring[i].fraginfo = 0;
+               if (np->rx_skbuff[i]) {
+                       dev_kfree_skb (np->rx_skbuff[i]);
+               }
+               np->rx_skbuff[i] = 0;
+       }
+       for (i = 0; i < TX_RING_SIZE; i++) {
+               if (np->tx_skbuff[i])
+                       dev_kfree_skb (np->tx_skbuff[i]);
+               np->tx_skbuff[i] = 0;
+       }
+       return 0;
+}
+
+static void __devexit
+rio_remove1 (struct pci_dev *pdev)
+{
+       struct net_device *dev = pci_get_drvdata (pdev);
+       if (dev) {
+               unregister_netdev (dev);
+#ifndef USE_IO_OPS
+               iounmap ((char *) (dev->base_addr));
+#endif
+               kfree (dev);
+               pci_release_regions (pdev);
+               pci_disable_device (pdev);
+       }
+       pci_set_drvdata (pdev, NULL);
+}
+
+static struct pci_driver rio_driver = {
+       name:           "dl2k",
+       id_table:       rio_pci_tbl,
+       probe:          rio_probe1,
+       remove:         rio_remove1,
+};
+
+static int __init
+rio_init (void)
+{
+#ifdef MODULE
+       printk ("%s", version);
+#endif
+
+       return pci_module_init (&rio_driver);
+}
+
+static void __exit
+rio_exit (void)
+{
+       pci_unregister_driver (&rio_driver);
+}
+
+module_init (rio_init);
+module_exit (rio_exit);
+
+/*
+Compile command: 
+gcc -D__KERNEL__ -DMODULE -I/usr/src/linux/include -Wall -Wstrict-prototypes -O2 -c dl2x.c
+
+*/
diff --git a/drivers/net/dl2k.h b/drivers/net/dl2k.h
new file mode 100644 (file)
index 0000000..1482072
--- /dev/null
@@ -0,0 +1,729 @@
+/*  D-Link DL2000-based Gigabit Ethernet Adapter Linux driver */
+/*  
+    Copyright (c) 2001 by D-Link Corporation
+    Written by Edward Peng.<edward_peng@dlink.com.tw>
+    Created 03-May-2001, base on Linux' sundance.c.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+*/
+
+#ifndef __DL2K_H__
+#define __DL2K_H__
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/init.h>
+#include <asm/processor.h>     /* Processor type for cache alignment. */
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+
+#define TX_RING_SIZE   16
+#define TX_QUEUE_LEN   10      /* Limit ring entries actually used.  */
+#define RX_RING_SIZE   16
+
+#define virt_to_le64desc(addr)  cpu_to_le64(virt_to_bus(addr))
+#define le64desc_to_virt(addr)  bus_to_virt(le64_to_cpu(addr))
+/* This driver was written to use PCI memory space, however x86-oriented
+   hardware often uses I/O space accesses. */
+#ifdef USE_IO_OPS
+#undef readb
+#undef readw
+#undef readl
+#undef writeb
+#undef writew
+#undef writel
+#define readb inb
+#define readw inw
+#define readl inl
+#define writeb outb
+#define writew outw
+#define writel outl
+#endif
+
+/* Offsets to the device registers.
+   Unlike software-only systems, device drivers interact with complex hardware.
+   It's not useful to define symbolic names for every register bit in the
+   device.  The name can only partially document the semantics and make
+   the driver longer and more difficult to read.
+   In general, only the important configuration values or bits changed
+   multiple times should be defined symbolically.
+*/
+enum dl2x_offsets {
+       /* I/O register offsets */
+       DMACtrl = 0x00,
+       RxDMAStatus = 0x08,
+       TFDListPtr0 = 0x10,
+       TFDListPtr1 = 0x14,
+       TxDMABurstThresh = 0x18,
+       TxDMAUrgentThresh = 0x19,
+       TxDMAPollPeriod = 0x1a,
+       RFDListPtr0 = 0x1c,
+       RFDListPtr1 = 0x20,
+       RxDMABurstThresh = 0x24,
+       RxDMAUrgentThresh = 0x25,
+       RxDMAPollPeriod = 0x26,
+       RxDMAIntCtrl = 0x28,
+       DebugCtrl = 0x2c,
+       ASICCtrl = 0x30,
+       FifoCtrl = 0x38,
+       RxEarlyThresh = 0x3a,
+       FlowOffThresh = 0x3c,
+       FlowOnThresh = 0x3e,
+       TxStartThresh = 0x44,
+       EepromData = 0x48,
+       EepromCtrl = 0x4a,
+       ExpromAddr = 0x4c,
+       Exprodata = 0x50,
+       WakeEvent0x51,
+       CountDown = 0x54,
+       IntStatusAck = 0x5a,
+       IntEnable = 0x5c,
+       IntStatus = 0x5e,
+       TxStatus = 0x60,
+       MACCtrl = 0x6c,
+       VLANTag = 0x70,
+       PhyCtrl = 0x76,
+       StationAddr0 = 0x78,
+       StationAddr1 = 0x7a,
+       StationAddr2 = 0x7c,
+       VLANId = 0x80,
+       MaxFrameSize = 0x86,
+       ReceiveMode = 0x88,
+       HashTable0 = 0x8c,
+       HashTable1 = 0x90,
+       RmonStatMask = 0x98,
+       StatMask = 0x9c,
+       RxJumboFrames = 0xbc,
+       TCPCheckSumErrors = 0xc0,
+       IPCheckSumErrors = 0xc2,
+       UDPCheckSumErrors = 0xc4,
+       TxJumboFrames = 0xf4,
+       /* Ethernet MIB statistic register offsets */
+       OctetRcvOk = 0xa8,
+       McstOctetRcvOk = 0xac,
+       BcstOctetRcvOk = 0xb0,
+       FramesRcvOk = 0xb4,
+       McstFramesRcvOk = 0xb8,
+       BcstFramesRcvOk = 0xbe,
+       MacControlFramesRcvd = 0xc6,
+       FrameTooLongErrors = 0xc8,
+       InRangeLengthErrors = 0xca,
+       FrameCheckSeqError = 0xcc,
+       FrameLostRxError = 0xce,
+       OctetXmtOk = 0xd0,
+       McstOctetXmtOk = 0xd4,
+       BcstOctetXmtOk = 0xd8,
+       FramesXmtOk = 0xdc,
+       McstFramesXmtdOk = 0xe0,
+       FramesWDeferredXmt = 0xe4,
+       LateCollisions = 0xe8,
+       MultiColFrames = 0xec,
+       SingleColFrames = 0xf0,
+       BcstFramesXmtdOk = 0xf6,
+       CarrierSenseErrors = 0xf8,
+       MacControlFramesXmtd = 0xfa,
+       FramesAbortXSColls = 0xfc,
+       FramesWEXDeferal = 0xfe,
+       /* RMON statistic register offsets */
+       EtherStatsCollisions = 0x100,
+       EtherStatsOctetsTransmit = 0x104,
+       EtherStatsPktsTransmit = 0x108,
+       EtherStatsPkts64OctetTransmit = 0x10c,
+       EtherStats65to127OctetsTransmit = 0x110,
+       EtherStatsPkts128to255OctetsTransmit = 0x114,
+       EtherStatsPkts256to511OctetsTransmit = 0x118,
+       EtherStatsPkts512to1023OctetsTransmit = 0x11c,
+       EtherStatsPkts1024to1518OctetsTransmit = 0x120,
+       EtherStatsCRCAlignErrors = 0x124,
+       EtherStatsUndersizePkts = 0x128,
+       EtherStatsFragments = 0x12c,
+       EtherStatsJabbers = 0x130,
+       EtherStatsOctets = 0x134,
+       EtherStatsPkts = 0x138,
+       EtherStats64Octets = 0x13c,
+       EtherStatsPkts65to127Octets = 0x140,
+       EtherStatsPkts128to255Octets = 0x144,
+       EtherStatsPkts256to511Octets = 0x148,
+       EtherStatsPkts512to1023Octets = 0x14c,
+       EtherStatsPkts1024to1518Octets = 0x150,
+};
+
+/* Bits in the interrupt status/mask registers. */
+enum IntStatus_bits {
+       InterruptStatus = 0x0001,
+       HostError = 0x0002,
+       MACCtrlFrame = 0x0008,
+       TxComplete = 0x0004,
+       RxComplete = 0x0010,
+       RxEarly = 0x0020,
+       IntRequested = 0x0040,
+       UpdateStats = 0x0080,
+       LinkEvent = 0x0100,
+       TxDMAComplete = 0x0200,
+       RxDMAComplete = 0x0400,
+       RFDListEnd = 0x0800,
+       RxDMAPriority = 0x1000,
+};
+
+/* Bits in the ReceiveMode register. */
+enum ReceiveMode_bits {
+       ReceiveIPMulticast = 0x0020,
+       ReceiveMulticastHash = 0x0010,
+       ReceiveAllFrames = 0x0008,
+       ReceiveBroadcast = 0x0004,
+       ReceiveMulticast = 0x0002,
+       ReceiveUnicast = 0x0001,
+       ReceiveVLANMatch = 0x0100,
+       ReceiveVLANHash = 0x0200,
+};
+/* Bits in MACCtrl. */
+enum MACCtrl_bits {
+       DuplexSelect = 0x20,
+       RcvFCS = 0x200,
+       AutoVLANtagging = 0x1000,
+       AutoVLANuntagging = 0x2000,
+       StatsEnable = 0x00200000,
+       StatsDisable = 0x00400000,
+       StatsEnabled = 0x00800000,
+       TxEnable = 0x01000000,
+       TxDisable = 0x02000000,
+       TxEnabled = 0x04000000,
+       RxEnable = 0x08000000,
+       RxDisable = 0x10000000,
+       RxEnabled = 0x20000000,
+};
+enum ASICCtrl_HiWord_bits {
+       GlobalReset = 0x0001,
+       RxReset = 0x0002,
+       TxReset = 0x0004,
+       DMAReset = 0x0008,
+       FIFOReset = 0x0010,
+       NetworkReset = 0x0020,
+       HostReset = 0x0040,
+       ResetBusy = 0x0400,
+};
+
+/* Transmit Frame Control bits */
+enum TFC_bits {
+       DwordAlign = 0x00000000,
+       WordAlignDisable = 0x00030000,
+       WordAlign = 0x00020000,
+       TCPChecksumEnable = 0x00040000,
+       UDPChecksumEnable = 0x00080000,
+       IPChecksumEnable = 0x00100000,
+       FCSAppendDisable = 0x00200000,
+       TxIndicate = 0x00400000,
+       TxDMAIndicate = 0x00800000,
+       FragCountShift = 24,
+       VLANTagInsert = 0x0000000010000000,
+       TFDDone = 0x80000000,
+       VIDShift = 32,
+       CFI = 0x0000100000000000,
+       UsePriorityShift = 48,
+};
+
+/* Receive Frames Status bits */
+enum RFS_bits {
+       RxFIFOOverrun = 0x00010000,
+       RxRuntFrame = 0x00020000,
+       RxAlignmentError = 0x00040000,
+       RxFCSError = 0x00080000,
+       RxOverSizedFrame = 0x00100000,
+       RxLengthError = 0x00200000,
+       VLANDetected = 0x00400000,
+       TCPDetected = 0x00800000,
+       TCPError = 0x01000000,
+       UDPDetected = 0x02000000,
+       UDPError = 0x04000000,
+       IPDetected = 0x08000000,
+       IPError = 0x10000000,
+       FrameStart = 0x20000000,
+       FrameEnd = 0x40000000,
+       RFDDone = 0x80000000,
+       TCIShift = 32,
+};
+
+#define MII_RESET_TIME_OUT             10000
+/* MII register */
+enum _mii_reg {
+       MII_BMCR = 0,
+       MII_BMSR = 1,
+       MII_PHY_ID1 = 2,
+       MII_PHY_ID2 = 3,
+       MII_ANAR = 4,
+       MII_ANLPAR = 5,
+       MII_ANER = 6,
+       MII_ANNPT = 7,
+       MII_ANLPRNP = 8,
+       MII_MSCR = 9,
+       MII_MSSR = 10,
+       MII_ESR = 15,
+       MII_PHY_SCR = 16,
+};
+
+/* Basic Mode Control Register */
+typedef union t_MII_BMCR {
+       u16 image;
+       struct {
+               u16 _bit_5_0:6; // bit 5:0
+               u16 speed1000:1;        // bit 6
+               u16 col_test_enable:1;  // bit 7
+               u16 duplex_mode:1;      // bit 8
+               u16 restart_an:1;       // bit 9
+               u16 isolate:1;  // bit 10
+               u16 power_down:1;       // bit 11
+               u16 an_enable:1;        // bit 12
+               u16 speed100:1; // bit 13
+               u16 loopback:1; // bit 14
+               u16 reset:1;    // bit 15
+       } bits;
+} BMCR_t, *PBMCR_t;
+
+enum _mii_bmcr {
+       MII_BMCR_RESET = 0x8000,
+       MII_BMCR_LOOP_BACK = 0x4000,
+       MII_BMCR_SPEED_LSB = 0x2000,
+       MII_BMCR_AN_ENABLE = 0x1000,
+       MII_BMCR_POWER_DOWN = 0x0800,
+       MII_BMCR_ISOLATE = 0x0400,
+       MII_BMCR_RESTART_AN = 0x0200,
+       MII_BMCR_DUPLEX_MODE = 0x0100,
+       MII_BMCR_COL_TEST = 0x0080,
+       MII_BMCR_SPEED_MSB = 0x0040,
+       MII_BMCR_SPEED_RESERVED = 0x003f,
+       MII_BMCR_SPEED_10 = 0,
+       MII_BMCR_SPEED_100 = MII_BMCR_SPEED_LSB,
+       MII_BMCR_SPEED_1000 = MII_BMCR_SPEED_MSB,
+};
+
+/* Basic Mode Status Register */
+typedef union t_MII_BMSR {
+       u16 image;
+       struct {
+               u16 ext_capability:1;   // bit 0
+               u16 japper_detect:1;    // bit 1
+               u16 link_status:1;      // bit 2
+               u16 an_ability:1;       // bit 3
+               u16 remote_fault:1;     // bit 4
+               u16 an_complete:1;      // bit 5
+               u16 preamble_supp:1;    // bit 6
+               u16 _bit_7:1;   // bit 7
+               u16 ext_status:1;       // bit 8
+               u16 media_100BT2_HD:1;  // bit 9
+               u16 media_100BT2_FD:1;  // bit 10
+               u16 media_10BT_HD:1;    // bit 11
+               u16 media_10BT_FD:1;    // bit 12
+               u16 media_100BX_HD:1;   // bit 13
+               u16 media_100BX_FD:1;   // bit 14
+               u16 media_100BT4:1;     // bit 15
+       } bits;
+} BMSR_t, *PBMSR_t;
+
+enum _mii_bmsr {
+       MII_BMSR_100BT4 = 0x8000,
+       MII_BMSR_100BX_FD = 0x4000,
+       MII_BMSR_100BX_HD = 0x2000,
+       MII_BMSR_10BT_FD = 0x1000,
+       MII_BMSR_10BT_HD = 0x0800,
+       MII_BMSR_100BT2_FD = 0x0400,
+       MII_BMSR_100BT2_HD = 0x0200,
+       MII_BMSR_EXT_STATUS = 0x0100,
+       MII_BMSR_PREAMBLE_SUPP = 0x0040,
+       MII_BMSR_AN_COMPLETE = 0x0020,
+       MII_BMSR_REMOTE_FAULT = 0x0010,
+       MII_BMSR_AN_ABILITY = 0x0008,
+       MII_BMSR_LINK_STATUS = 0x0004,
+       MII_BMSR_JABBER_DETECT = 0x0002,
+       MII_BMSR_EXT_CAP = 0x0001,
+};
+
+/* ANAR */
+typedef union t_MII_ANAR {
+       u16 image;
+       struct {
+               u16 selector:5; // bit 4:0
+               u16 media_10BT_HD:1;    // bit 5
+               u16 media_10BT_FD:1;    // bit 6
+               u16 media_100BX_HD:1;   // bit 7
+               u16 media_100BX_FD:1;   // bit 8
+               u16 media_100BT4:1;     // bit 9
+               u16 pause:1;    // bit 10
+               u16 asymmetric:1;       // bit 11
+               u16 _bit12:1;   // bit 12
+               u16 remote_fault:1;     // bit 13
+               u16 _bit14:1;   // bit 14
+               u16 next_page:1;        // bit 15
+       } bits;
+} ANAR_t, *PANAR_t;
+
+enum _mii_anar {
+       MII_ANAR_NEXT_PAGE = 0x8000,
+       MII_ANAR_REMOTE_FAULT = 0x4000,
+       MII_ANAR_ASYMMETRIC = 0x0800,
+       MII_ANAR_PAUSE = 0x0400,
+       MII_ANAR_100BT4 = 0x0200,
+       MII_ANAR_100BX_FD = 0x0100,
+       MII_ANAR_100BX_HD = 0x0080,
+       MII_ANAR_10BT_FD = 0x0020,
+       MII_ANAR_10BT_HD = 0x0010,
+       MII_ANAR_SELECTOR = 0x001f,
+       MII_IEEE8023_CSMACD = 0x0001,
+};
+
+/* ANLPAR */
+typedef union t_MII_ANLPAR {
+       u16 image;
+       struct {
+               u16 selector:5; // bit 4:0
+               u16 media_10BT_HD:1;    // bit 5
+               u16 media_10BT_FD:1;    // bit 6
+               u16 media_100BX_HD:1;   // bit 7
+               u16 media_100BX_FD:1;   // bit 8
+               u16 media_100BT4:1;     // bit 9
+               u16 pause:1;    // bit 10
+               u16 asymmetric:1;       // bit 11
+               u16 _bit12:1;   // bit 12
+               u16 remote_fault:1;     // bit 13
+               u16 _bit14:1;   // bit 14
+               u16 next_page:1;        // bit 15
+       } bits;
+} ANLPAR_t, *PANLPAR_t;
+
+enum _mii_anlpar {
+       MII_ANLPAR_NEXT_PAGE = MII_ANAR_NEXT_PAGE,
+       MII_ANLPAR_REMOTE_FAULT = MII_ANAR_REMOTE_FAULT,
+       MII_ANLPAR_ASYMMETRIC = MII_ANAR_ASYMMETRIC,
+       MII_ANLPAR_PAUSE = MII_ANAR_PAUSE,
+       MII_ANLPAR_100BT4 = MII_ANAR_100BT4,
+       MII_ANLPAR_100BX_FD = MII_ANAR_100BX_FD,
+       MII_ANLPAR_100BX_HD = MII_ANAR_100BX_HD,
+       MII_ANLPAR_10BT_FD = MII_ANAR_10BT_FD,
+       MII_ANLPAR_10BT_HD = MII_ANAR_10BT_HD,
+       MII_ANLPAR_SELECTOR = MII_ANAR_SELECTOR,
+};
+
+/* Auto-Negotiation Expansion Register */
+typedef union t_MII_ANER {
+       u16 image;
+       struct {
+               u16 lp_negotiable:1;    // bit 0
+               u16 page_received:1;    // bit 1
+               u16 nextpagable:1;      // bit 2
+               u16 lp_nextpagable:1;   // bit 3
+               u16 pdetect_fault:1;    // bit 4
+               u16 _bit15_5:11;        // bit 15:5
+       } bits;
+} ANER_t, *PANER_t;
+
+enum _mii_aner {
+       MII_ANER_PAR_DETECT_FAULT = 0x0010,
+       MII_ANER_LP_NEXTPAGABLE = 0x0008,
+       MII_ANER_NETXTPAGABLE = 0x0004,
+       MII_ANER_PAGE_RECEIVED = 0x0002,
+       MII_ANER_LP_NEGOTIABLE = 0x0001,
+};
+
+/* MASTER-SLAVE Control Register */
+typedef union t_MII_MSCR {
+       u16 image;
+       struct {
+               u16 _bit_7_0:8; // bit 7:0
+               u16 media_1000BT_HD:1;  // bit 8
+               u16 media_1000BT_FD:1;  // bit 9
+               u16 port_type:1;        // bit 10
+               u16 cfg_value:1;        // bit 11
+               u16 cfg_enable:1;       // bit 12
+               u16 test_mode:3;        // bit 15:13
+       } bits;
+} MSCR_t, *PMSCR_t;
+
+enum _mii_mscr {
+       MII_MSCR_TEST_MODE = 0xe000,
+       MII_MSCR_CFG_ENABLE = 0x1000,
+       MII_MSCR_CFG_VALUE = 0x0800,
+       MII_MSCR_PORT_VALUE = 0x0400,
+       MII_MSCR_1000BT_FD = 0x0200,
+       MII_MSCR_1000BT_HD = 0X0100,
+};
+
+/* MASTER-SLAVE Status Register */
+typedef union t_MII_MSSR {
+       u16 image;
+       struct {
+               u16 idle_err_count:8;   // bit 7:0
+               u16 _bit_9_8:2; // bit 9:8
+               u16 lp_1000BT_HD:1;     // bit 10
+               u16 lp_1000BT_FD:1;     // bit 11
+               u16 remote_rcv_status:1;        // bit 12
+               u16 local_rcv_status:1; // bit 13
+               u16 cfg_resolution:1;   // bit 14
+               u16 cfg_fault:1;        // bit 15
+       } bits;
+} MSSR_t, *PMSSR_t;
+
+enum _mii_mssr {
+       MII_MSSR_CFG_FAULT = 0x8000,
+       MII_MSSR_CFG_RES = 0x4000,
+       MII_MSSR_LOCAL_RCV_STATUS = 0x2000,
+       MII_MSSR_REMOTE_RCVR = 0x1000,
+       MII_MSSR_LP_1000BT_HD = 0x0800,
+       MII_MSSR_LP_1000BT_FD = 0x0400,
+       MII_MSSR_IDLE_ERR_COUNT = 0x00ff,
+};
+
+/* IEEE Extened Status Register */
+typedef union t_MII_ESR {
+       u16 image;
+       struct {
+               u16 _bit_11_0:12;       // bit 11:0
+               u16 media_1000BT_HD:2;  // bit 12
+               u16 media_1000BT_FD:1;  // bit 13
+               u16 media_1000BX_HD:1;  // bit 14
+               u16 media_1000BX_FD:1;  // bit 15
+       } bits;
+} ESR_t, *PESR_t;
+
+enum _mii_esr {
+       MII_ESR_1000BX_FD = 0x8000,
+       MII_ESR_1000BX_HD = 0x4000,
+       MII_ESR_1000BT_FD = 0x2000,
+       MII_ESR_1000BT_HD = 0x1000,
+};
+/* PHY Specific Control Register */
+typedef union t_MII_PHY_SCR {
+       u16 image;
+       struct {
+               u16 disable_jabber:1;   // bit 0
+               u16 polarity_reversal:1;        // bit 1
+               u16 SEQ_test:1; // bit 2
+               u16 _bit_3:1;   // bit 3
+               u16 disable_CLK125:1;   // bit 4
+               u16 mdi_crossover_mode:2;       // bit 6:5
+               u16 enable_ext_dist:1;  // bit 7
+               u16 _bit_8_9:2; // bit 9:8
+               u16 force_link:1;       // bit 10
+               u16 assert_CRS:1;       // bit 11
+               u16 rcv_fifo_depth:2;   // bit 13:12
+               u16 xmit_fifo_depth:2;  // bit 15:14
+       } bits;
+} PHY_SCR_t, *PPHY_SCR_t;
+
+typedef enum t_MII_ADMIN_STATUS {
+       adm_reset,
+       adm_operational,
+       adm_loopback,
+       adm_power_down,
+       adm_isolate
+} MII_ADMIN_t, *PMII_ADMIN_t;
+
+typedef struct t_SROM {
+       u16 config_param;       /* 0x00 */
+       u16 asic_ctrl;          /* 0x02 */
+       u16 sub_vendor_id;      /* 0x04 */
+       u16 sub_system_id;      /* 0x06 */
+       u16 reserved1[12];      /* 0x08-0x1f */
+       u8 mac_addr[6];         /* 0x20-0x25 */
+       u8 reserved2[10];       /* 0x26-0x2f */
+       u8 sib[204];            /* 0x30-0xfb */
+       u32 crc;                /* 0xfc-0xff */
+} SROM_t, *PSROM_t;
+
+/* Ioctl custom data */
+struct ioctl_data {
+       char signature[10];
+       int cmd;
+       int len;
+       char *data;
+};
+
+struct mii_data {
+       __u16 reserved;
+       __u16 reg_num;
+       __u16 in_value;
+       __u16 out_value;
+};
+
+/* The Rx and Tx buffer descriptors. */
+struct netdev_desc {
+       u64 next_desc;
+       u64 status;
+       u64 fraginfo;
+};
+
+#define PRIV_ALIGN     15      /* Required alignment mask */
+/* Use  __attribute__((aligned (L1_CACHE_BYTES)))  to maintain alignment
+   within the structure. */
+struct netdev_private {
+       /* Descriptor rings first for alignment. */
+       struct netdev_desc rx_ring[RX_RING_SIZE];
+       struct netdev_desc tx_ring[TX_RING_SIZE];
+       /* The addresses of receive-in-place skbuffs. */
+       struct sk_buff *rx_skbuff[RX_RING_SIZE];
+       /* The saved address of a sent-in-place packet/buffer, for later free(). */
+       struct sk_buff *tx_skbuff[TX_RING_SIZE];
+       struct net_device_stats stats;
+       spinlock_t lock;
+       struct netdev_desc *rx_head_desc;
+       unsigned int rx_buf_sz; /* Based on MTU+slack. */
+       unsigned int tx_full:1; /* The Tx queue is full. */
+       unsigned int full_duplex:1;     /* Full-duplex operation requested. */
+       unsigned int speed;     /* Operating speed */
+       unsigned int vlan;      /* VLAN Id */
+       unsigned int an_enable; /* Auto-Negotiated Enable */
+       unsigned int chip_id;   /* PCI table chip id */
+       unsigned int jumbo;
+       struct netdev_desc *last_tx;    /* Last Tx descriptor used. */
+       u64 cur_rx, old_rx;     /* Producer/consumer ring indices */
+       u64 cur_tx, old_tx;
+       int wake_polarity;
+       char name[256];         /* net device description */
+       u8 duplex_polarity;
+       u16 mcast_filter[4];
+       u16 advertising;        /* NWay media advertisement */
+       u16 negotiate;          /* Negotiated media */
+       int phy_addr;           /* PHY addresses. */
+       int tx_debug;
+       int rx_debug;
+};
+
+/* The station address location in the EEPROM. */
+#ifdef USE_IO_OPS
+#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_IO  | PCI_ADDR0)
+#else
+#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_MEM | PCI_ADDR1)
+#endif
+/* The struct pci_device_id consist of:
+        vendor, device          Vendor and device ID to match (or PCI_ANY_ID)
+        subvendor, subdevice    Subsystem vendor and device ID to match (or PCI_ANY_ID)
+        class                   Device class to match. The class_mask tells which bits
+        class_mask              of the class are honored during the comparison.
+        driver_data             Data private to the driver.
+*/
+static struct pci_device_id rio_pci_tbl[] __devinitdata = {
+       {0x1186, 0x4000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+       {0,}
+};
+MODULE_DEVICE_TABLE (pci, rio_pci_tbl);
+#define TX_TIMEOUT  (4*HZ)
+#define PACKET_SIZE            1536
+#define RIO_IO_SIZE             340
+#ifdef RIO_DEBUG
+#define DEBUG_TFD_DUMP(x) debug_tfd_dump(x)
+#define DEBUG_RFD_DUMP(x,flag) debug_rfd_dump(x,flag)
+#define DEBUG_PKT_DUMP(x,len) debug_pkt_dump(x,len)
+#define DEBUG_PRINT printk
+
+static inline void
+debug_tfd_dump (struct netdev_private *np)
+{
+       int i;
+       struct netdev_desc *desc;
+
+       if (np->tx_debug == 6) {
+               printk ("TFDone Dump: ");
+               for (i = 0; i < TX_RING_SIZE; i++) {
+                       desc = &np->tx_ring[i];
+                       if ((desc->fraginfo & 0xffffffffff) == 0)
+                               printk ("X");
+                       else
+                               printk ("%d", (desc->status & TFDDone) ? 1 : 0);
+               }
+               printk ("\n");
+       }
+       if (np->tx_debug == 5) {
+               for (i = 0; i < TX_RING_SIZE; i++) {
+                       desc = &np->tx_ring[i];
+                       printk
+                           ("cur:%08x next:%08x status:%08x frag1:%08x frag0:%08x",
+                            (u32) virt_to_bus (desc), (u32) desc->next_desc,
+                            (u32) desc->status, (u32) (desc->fraginfo >> 32),
+                            (u32) desc->fraginfo);
+                       printk ("\n");
+               }
+               printk ("\n");
+       }
+}
+static inline void
+debug_rfd_dump (struct netdev_private *np, int flag)
+{
+       int i;
+       struct netdev_desc *desc;
+       int entry = np->cur_rx % RX_RING_SIZE;
+
+       if (np->rx_debug == 5) {
+               for (i = 0; i < RX_RING_SIZE; i++) {
+                       desc = &np->rx_ring[i];
+                       printk
+                           ("cur:%08x next:%08x status:%08x frag1:%08x frag0:%08x",
+                            (u32) virt_to_bus (desc), (u32) desc->next_desc,
+                            (u32) desc->status, (u32) (desc->fraginfo >> 32),
+                            (u32) desc->fraginfo);
+                       printk ("\n");
+               }
+               printk ("\n");
+       }
+
+       if (np->rx_debug == 6) {
+               if (flag == 1)
+                       printk ("RFDone Dump: ");
+               else if (flag == 2)
+                       printk ("Re-Filling:  ");
+               for (i = 0; i < RX_RING_SIZE; i++) {
+                       desc = &np->rx_ring[i];
+                       printk ("%d", (desc->status & RFDDone) ? 1 : 0);
+               }
+               printk ("\n");
+       }
+       if (np->rx_debug == 7) {
+               printk (" In rcv_pkt(), entry %d status %4.4x %4.4x.\n",
+                       entry, (u32) (np->rx_ring[entry].status >> 32),
+                       (u32) np->rx_ring[entry].status);
+       }
+
+}
+
+static inline void
+debug_pkt_dump (struct netdev_private *np, int pkt_len)
+{
+       int i;
+       struct netdev_desc *desc = np->rx_head_desc;
+       unsigned char *pchar;
+       unsigned char *phead;
+       u64 frame_status = le64_to_cpu (desc->status);
+
+       if (np->rx_debug == 4) {
+               printk ("  rcv_pkt: status was %4.4x %4.4x.\n",
+                       (u32) (frame_status >> 32), (u32) frame_status);
+       }
+       if (np->rx_debug == 7) {
+               phead = le64desc_to_virt ((desc->fraginfo & 0xffffffffff));
+               for (pchar = phead, i = 0; i < pkt_len; i++, pchar++) {
+                       printk ("%02x ", *pchar);
+                       if ((i + 1) % 20 == 0)
+                               printk ("\n");
+               }
+       }
+}
+#else
+#define DEBUG_TFD_DUMP(x) {}
+#define DEBUG_RFD_DUMP(x,flag) {}
+#define DEBUG_PKT_DUMP(x,len) {}
+#define DEBUG_PRINT() {}
+#endif
+
+#endif /* __DL2K_H__ */
index e9cab7c10399e7a779fe3a7ba1a89ebde35355db..e581850c3696fe0eb6899d95104c3606293c48e9 100644 (file)
@@ -1174,8 +1174,6 @@ static int epic_rx(struct net_device *dev)
 
                        pci_dma_sync_single(ep->pci_dev, ep->rx_ring[entry].bufaddr, 
                                            ep->rx_buf_sz, PCI_DMA_FROMDEVICE);
-                       pci_unmap_single(ep->pci_dev, ep->rx_ring[entry].bufaddr, 
-                                        ep->rx_buf_sz, PCI_DMA_FROMDEVICE);
                        if (pkt_len > PKT_BUF_SZ - 4) {
                                printk(KERN_ERR "%s: Oversized Ethernet frame, status %x "
                                           "%d bytes.\n",
@@ -1196,6 +1194,9 @@ static int epic_rx(struct net_device *dev)
                                           pkt_len);
 #endif
                        } else {
+                               pci_unmap_single(ep->pci_dev, 
+                                       ep->rx_ring[entry].bufaddr, 
+                                       ep->rx_buf_sz, PCI_DMA_FROMDEVICE);
                                skb_put(skb = ep->rx_skbuff[entry], pkt_len);
                                ep->rx_skbuff[entry] = NULL;
                        }
index ed9abb541e51c40f2ec4168c9c2e0f49508f9a51..fc73604f3f8b7078303b52afc631008cbd6aefe7 100644 (file)
@@ -1,4 +1,4 @@
-/*     $Id: aurora.c,v 1.13 2001/05/10 01:45:38 davem Exp $
+/*     $Id: aurora.c,v 1.14 2001/06/29 23:07:37 davem Exp $
  *     linux/drivers/sbus/char/aurora.c -- Aurora multiport driver
  *
  *     Copyright (c) 1999 by Oliver Aldulea (oli@bv.ro)
@@ -1851,7 +1851,6 @@ static int aurora_get_modem_info(struct Aurora_port * port, unsigned int *value)
 static int aurora_set_modem_info(struct Aurora_port * port, unsigned int cmd,
                                 unsigned int *value)
 {
-       int error;
        unsigned int arg;
        unsigned long flags;
        struct Aurora_board *bp = port_Board(port);
@@ -1860,9 +1859,8 @@ static int aurora_set_modem_info(struct Aurora_port * port, unsigned int cmd,
 #ifdef AURORA_DEBUG
        printk("aurora_set_modem_info: start\n");
 #endif
-       error = get_user(arg, value);
-       if (error) 
-               return error;
+       if (get_user(arg, value))
+               return -EFAULT;
        chip = AURORA_CD180(port_No(port));
        switch (cmd) {
         case TIOCMBIS: 
@@ -1940,16 +1938,12 @@ static int aurora_set_serial_info(struct Aurora_port * port,
        struct Aurora_board *bp = port_Board(port);
        int change_speed;
        unsigned long flags;
-       int error;
 
 #ifdef AURORA_DEBUG
        printk("aurora_set_serial_info: start\n");
 #endif
-       error = verify_area(VERIFY_READ, (void *) newinfo, sizeof(tmp));
-       if (error)
-               return error;
-       copy_from_user(&tmp, newinfo, sizeof(tmp));
-       
+       if (copy_from_user(&tmp, newinfo, sizeof(tmp)))
+               return -EFAULT;
 #if 0  
        if ((tmp.irq != bp->irq) ||
            (tmp.port != bp->base) ||
@@ -2025,7 +2019,6 @@ static int aurora_ioctl(struct tty_struct * tty, struct file * filp,
                    
 {
        struct Aurora_port *port = (struct Aurora_port *) tty->driver_data;
-       int error;
        int retval;
 
 #ifdef AURORA_DEBUG
@@ -2051,25 +2044,19 @@ static int aurora_ioctl(struct tty_struct * tty, struct file * filp,
                aurora_send_break(port, arg ? arg*(HZ/10) : HZ/4);
                return 0;
        case TIOCGSOFTCAR:
-               error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(long));
-               if (error)
-                       return error;
-               put_user(C_CLOCAL(tty) ? 1 : 0,
-                        (unsigned long *) arg);
-               return 0;
+               return put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long *)arg);
        case TIOCSSOFTCAR:
-               retval = get_user(arg,(unsigned long *) arg);
-               if (retval)
-                       return retval;
+               if (get_user(arg,(unsigned long *)arg))
+                       return -EFAULT;
                tty->termios->c_cflag =
                        ((tty->termios->c_cflag & ~CLOCAL) |
                         (arg ? CLOCAL : 0));
                return 0;
        case TIOCMGET:
-               error = verify_area(VERIFY_WRITE, (void *) arg,
+               retval = verify_area(VERIFY_WRITE, (void *) arg,
                                    sizeof(unsigned int));
-               if (error)
-                       return error;
+               if (retval)
+                       return retval;
                return aurora_get_modem_info(port, (unsigned int *) arg);
        case TIOCMBIS:
        case TIOCMBIC:
index 80b9b15bd0901bc46b6734c97493a53b167a87ec..d552c56affa48650f226c19250a4e00370760716 100644 (file)
@@ -19,6 +19,7 @@
  *     v0.6 - never time out
  *     v0.7 - fixed bulk-IN read and poll (David Paschal, paschal@rcsis.com)
  *     v0.8 - add devfs support
+ *     v0.9 - fix unplug-while-open paths
  */
 
 /*
@@ -88,6 +89,7 @@ MFG:HEWLETT-PACKARD;MDL:DESKJET 970C;CMD:MLC,PCL,PML;CLASS:PRINTER;DESCRIPTION:H
 struct usblp {
        struct usb_device       *dev;                   /* USB device */
        devfs_handle_t          devfs;                  /* devfs device */
+       struct semaphore        sem;                    /* locks this struct, especially "dev" */
        struct urb              readurb, writeurb;      /* The urbs */
        wait_queue_head_t       wait;                   /* Zzzzz ... */
        int                     readcount;              /* Counter for reads */
@@ -172,9 +174,12 @@ static char *usblp_messages[] = { "ok", "out of paper", "off-line", "on fire" };
 static int usblp_check_status(struct usblp *usblp, int err)
 {
        unsigned char status, newerr = 0;
+       int error;
 
-       if (usblp_read_status(usblp, &status)) {
-               err("usblp%d: failed reading printer status", usblp->minor);
+       error = usblp_read_status (usblp, &status);
+       if (error < 0) {
+               err("usblp%d: error %d reading printer status",
+                       usblp->minor, error);
                return 0;
        }
 
@@ -244,24 +249,30 @@ out:
        return retval;
 }
 
+static void usblp_cleanup (struct usblp *usblp)
+{
+       devfs_unregister (usblp->devfs);
+       usblp_table [usblp->minor] = NULL;
+       info ("usblp%d: removed", usblp->minor);
+
+       kfree (usblp->writeurb.transfer_buffer);
+       kfree (usblp->device_id_string);
+       kfree (usblp);
+}
+
 static int usblp_release(struct inode *inode, struct file *file)
 {
        struct usblp *usblp = file->private_data;
 
+       down (&usblp->sem);
        usblp->used = 0;
-
        if (usblp->dev) {
                if (usblp->bidir)
                        usb_unlink_urb(&usblp->readurb);
                usb_unlink_urb(&usblp->writeurb);
-               return 0;
-       }
-
-       devfs_unregister(usblp->devfs);
-       usblp_table[usblp->minor] = NULL;
-       kfree(usblp->device_id_string);
-       kfree(usblp);
-
+               up(&usblp->sem);
+       } else          /* finish cleanup from disconnect */
+               usblp_cleanup (usblp);
        return 0;
 }
 
@@ -279,21 +290,31 @@ static int usblp_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
        struct usblp *usblp = file->private_data;
        int length, err;
        unsigned char status;
+       int retval = 0;
+
+       down (&usblp->sem);
+       if (!usblp->dev) {
+               retval = -ENODEV;
+               goto done;
+       }
 
        if (_IOC_TYPE(cmd) == 'P')      /* new-style ioctl number */
        
                switch (_IOC_NR(cmd)) {
 
                        case IOCNR_GET_DEVICE_ID: /* get the DEVICE_ID string */
-                               if (_IOC_DIR(cmd) != _IOC_READ)
-                                       return -EINVAL;
+                               if (_IOC_DIR(cmd) != _IOC_READ) {
+                                       retval = -EINVAL;
+                                       goto done;
+                               }
 
                                err = usblp_get_id(usblp, 0, usblp->device_id_string, DEVICE_ID_SIZE - 1);
                                if (err < 0) {
                                        dbg ("usblp%d: error = %d reading IEEE-1284 Device ID string",
                                                usblp->minor, err);
                                        usblp->device_id_string[0] = usblp->device_id_string[1] = '\0';
-                                       return -EIO;
+                                       retval = -EIO;
+                                       goto done;
                                }
 
                                length = (usblp->device_id_string[0] << 8) + usblp->device_id_string[1]; /* big-endian */
@@ -307,13 +328,16 @@ static int usblp_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
 
                                if (length > _IOC_SIZE(cmd)) length = _IOC_SIZE(cmd); /* truncate */
 
-                               if (copy_to_user((unsigned char *) arg, usblp->device_id_string, (unsigned long) length))
-                                       return -EFAULT;
+                               if (copy_to_user((unsigned char *) arg,
+                                               usblp->device_id_string, (unsigned long) length)) {
+                                       retval = -EFAULT;
+                                       goto done;
+                               }
 
                                break;
 
                        default:
-                               return -EINVAL;
+                               retval = -EINVAL;
                }
        else    /* old-style ioctl value */
                switch (cmd) {
@@ -321,17 +345,20 @@ static int usblp_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
                        case LPGETSTATUS:
                                if (usblp_read_status(usblp, &status)) {
                                        err("usblp%d: failed reading printer status", usblp->minor);
-                                       return -EIO;
+                                       retval = -EIO;
+                                       goto done;
                                }
                                if (copy_to_user ((unsigned char *)arg, &status, 1))
-                                       return -EFAULT;
+                                       retval = -EFAULT;
                                break;
 
                        default:
-                               return -EINVAL;
+                               retval = -EINVAL;
                }
 
-       return 0;
+done:
+       up (&usblp->sem);
+       return retval;
 }
 
 static ssize_t usblp_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
@@ -341,6 +368,8 @@ static ssize_t usblp_write(struct file *file, const char *buffer, size_t count,
 
        while (writecount < count) {
 
+               // FIXME:  only use urb->status inside completion
+               // callbacks; this way is racey...
                if (usblp->writeurb.status == -EINPROGRESS) {
 
                        if (file->f_flags & O_NONBLOCK)
@@ -356,28 +385,36 @@ static ssize_t usblp_write(struct file *file, const char *buffer, size_t count,
                        }
                }
 
-               if (!usblp->dev)
+               down (&usblp->sem);
+               if (!usblp->dev) {
+                       up (&usblp->sem);
                        return -ENODEV;
+               }
 
-               if (usblp->writeurb.status) {
+               if (usblp->writeurb.status != 0) {
                        if (usblp->quirks & USBLP_QUIRK_BIDIR) {
                                if (usblp->writeurb.status != -EINPROGRESS)
                                        err("usblp%d: error %d writing to printer",
                                                usblp->minor, usblp->writeurb.status);
                                err = usblp->writeurb.status;
-                               continue;
-                       }
-                       else {
+                       } else
                                err = usblp_check_status(usblp, err);
-                               continue;
-                       }
+                       up (&usblp->sem);
+
+                       /* if the fault was due to disconnect, let khubd's
+                        * call to usblp_disconnect() grab usblp->sem ...
+                        */
+                       schedule ();
+                       continue;
                }
 
                writecount += usblp->writeurb.transfer_buffer_length;
                usblp->writeurb.transfer_buffer_length = 0;
 
-               if (writecount == count)
-                       continue;
+               if (writecount == count) {
+                       up (&usblp->sem);
+                       break;
+               }
 
                usblp->writeurb.transfer_buffer_length = (count - writecount) < USBLP_BUF_SIZE ?
                                                         (count - writecount) : USBLP_BUF_SIZE;
@@ -387,6 +424,7 @@ static ssize_t usblp_write(struct file *file, const char *buffer, size_t count,
 
                usblp->writeurb.dev = usblp->dev;
                usb_submit_urb(&usblp->writeurb);
+               up (&usblp->sem);
        }
 
        return count;
@@ -399,20 +437,36 @@ static ssize_t usblp_read(struct file *file, char *buffer, size_t count, loff_t
        if (!usblp->bidir)
                return -EINVAL;
 
+       down (&usblp->sem);
+       if (!usblp->dev) {
+               count = -ENODEV;
+               goto done;
+       }
+
        if (usblp->readurb.status == -EINPROGRESS) {
 
-               if (file->f_flags & O_NONBLOCK)
-                       return -EAGAIN;
+               if (file->f_flags & O_NONBLOCK) {
+                       count = -EAGAIN;
+                       goto done;
+               }
 
+               // FIXME:  only use urb->status inside completion
+               // callbacks; this way is racey...
                while (usblp->readurb.status == -EINPROGRESS) {
-                       if (signal_pending(current))
-                               return -EINTR;
+                       if (signal_pending(current)) {
+                               count = -EINTR;
+                               goto done;
+                       }
+                       up (&usblp->sem);
                        interruptible_sleep_on(&usblp->wait);
+                       down (&usblp->sem);
                }
        }
 
-       if (!usblp->dev)
-               return -ENODEV;
+       if (!usblp->dev) {
+               count = -ENODEV;
+               goto done;
+       }
 
        if (usblp->readurb.status) {
                err("usblp%d: error %d reading from printer",
@@ -420,14 +474,17 @@ static ssize_t usblp_read(struct file *file, char *buffer, size_t count, loff_t
                usblp->readurb.dev = usblp->dev;
                usblp->readcount = 0;
                usb_submit_urb(&usblp->readurb);
-               return -EIO;
+               count = -EIO;
+               goto done;
        }
 
        count = count < usblp->readurb.actual_length - usblp->readcount ?
                count : usblp->readurb.actual_length - usblp->readcount;
 
-       if (copy_to_user(buffer, usblp->readurb.transfer_buffer + usblp->readcount, count))
-               return -EFAULT;
+       if (copy_to_user(buffer, usblp->readurb.transfer_buffer + usblp->readcount, count)) {
+               count = -EFAULT;
+               goto done;
+       }
 
        if ((usblp->readcount += count) == usblp->readurb.actual_length) {
                usblp->readcount = 0;
@@ -435,6 +492,8 @@ static ssize_t usblp_read(struct file *file, char *buffer, size_t count, loff_t
                usb_submit_urb(&usblp->readurb);
        }
 
+done:
+       up (&usblp->sem);
        return count;
 }
 
@@ -537,6 +596,7 @@ static void *usblp_probe(struct usb_device *dev, unsigned int ifnum,
                return NULL;
        }
        memset(usblp, 0, sizeof(struct usblp));
+       init_MUTEX (&usblp->sem);
 
        /* lookup quirks for this printer */
        quirks = usblp_quirks(dev->descriptor.idVendor, dev->descriptor.idProduct);
@@ -599,14 +659,12 @@ static void *usblp_probe(struct usb_device *dev, unsigned int ifnum,
 
        sprintf(name, "lp%d", minor);
        
-       /* Create with perms=664 */
+       /* if we have devfs, create with perms=660 */
        usblp->devfs = devfs_register(usb_devfs_handle, name,
                                      DEVFS_FL_DEFAULT, USB_MAJOR,
                                      USBLP_MINOR_BASE + minor,
                                      S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP |
                                      S_IWGRP, &usblp_fops, NULL);
-       if (usblp->devfs == NULL)
-               err("usblp%d: device node registration failed", minor);
 
        info("usblp%d: USB %sdirectional printer dev %d if %d alt %d",
                minor, bidir ? "Bi" : "Uni", dev->devnum, ifnum, alts);
@@ -619,25 +677,21 @@ static void usblp_disconnect(struct usb_device *dev, void *ptr)
        struct usblp *usblp = ptr;
 
        if (!usblp || !usblp->dev) {
-               err("disconnect on nonexisting interface");
-               return;
+               err("bogus disconnect");
+               BUG ();
        }
 
+       down (&usblp->sem);
        usblp->dev = NULL;
 
        usb_unlink_urb(&usblp->writeurb);
        if (usblp->bidir)
                usb_unlink_urb(&usblp->readurb);
 
-       kfree(usblp->writeurb.transfer_buffer);
-
-       if (usblp->used) return;
-
-       kfree(usblp->device_id_string);
-
-       devfs_unregister(usblp->devfs);
-       usblp_table[usblp->minor] = NULL;
-       kfree(usblp);
+       if (!usblp->used)
+               usblp_cleanup (usblp);
+       else    /* cleanup later, on close */
+               up (&usblp->sem);
 }
 
 static struct usb_device_id usblp_ids [] = {
index bafcbeb869b5d66b57456a42c3a5abd1252c0820..95f36da88159ae0c0b46dcc42ae2224ae144488a 100644 (file)
@@ -909,7 +909,7 @@ ioctl_scanner(struct inode *inode, struct file *file,
                return result;
        }
        default:
-               return -ENOIOCTLCMD;
+               return -ENOTTY;
        }
        return 0;
 }
index 50fb149452fede765789b768570d503b799d45a4..de9c744d14f72eb1e28cf03af4b367aaebc0852f 100644 (file)
@@ -247,7 +247,6 @@ static int empeg_open (struct usb_serial_port *port, struct file *filp)
 static void empeg_close (struct usb_serial_port *port, struct file * filp)
 {
        struct usb_serial *serial;
-       unsigned char *transfer_buffer;
 
        if (port_paranoia_check (port, __FUNCTION__))
                return;
@@ -263,14 +262,6 @@ static void empeg_close (struct usb_serial_port *port, struct file * filp)
        --port->open_count;
 
        if (port->open_count <= 0) {
-               transfer_buffer =  kmalloc (0x12, GFP_KERNEL);
-
-               if (!transfer_buffer) {
-                       err(__FUNCTION__ " - kmalloc(%d) failed.", 0x12);
-               } else {
-                       kfree (transfer_buffer);
-               }
-
                /* shutdown our bulk read */
                usb_unlink_urb (port->read_urb);
                port->active = 0;
index 44794a9dc1ccd99433910795ef88ee40e0911dad..98bbd1e4654deb0e231871b577e6d361035d8777 100644 (file)
@@ -902,7 +902,8 @@ static int ftdi_sio_ioctl (struct usb_serial_port *port, struct file * file, uns
 
        case TIOCMSET: /* Turns on and off the lines as specified by the mask */
                dbg(__FUNCTION__ " TIOCMSET");
-               if ((ret = get_user(mask, (unsigned long *) arg))) return ret;
+               if (get_user(mask, (unsigned long *) arg))
+                       return -EFAULT;
                urb_value = ((mask & TIOCM_DTR) ? HIGH : LOW);
                if (set_dtr(serial->dev, usb_sndctrlpipe(serial->dev, 0),urb_value) < 0){
                        err("Error from DTR set urb (TIOCMSET)");
@@ -915,7 +916,8 @@ static int ftdi_sio_ioctl (struct usb_serial_port *port, struct file * file, uns
                                        
        case TIOCMBIS: /* turns on (Sets) the lines as specified by the mask */
                dbg(__FUNCTION__ " TIOCMBIS");
-               if ((ret = get_user(mask, (unsigned long *) arg))) return ret;
+               if (get_user(mask, (unsigned long *) arg))
+                       return -EFAULT;
                if (mask & TIOCM_DTR){
                        if ((ret = set_dtr(serial->dev, 
                                           usb_sndctrlpipe(serial->dev, 0),
@@ -936,7 +938,8 @@ static int ftdi_sio_ioctl (struct usb_serial_port *port, struct file * file, uns
 
        case TIOCMBIC: /* turns off (Clears) the lines as specified by the mask */
                dbg(__FUNCTION__ " TIOCMBIC");
-               if ((ret = get_user(mask, (unsigned long *) arg))) return ret;
+               if (get_user(mask, (unsigned long *) arg))
+                       return -EFAULT;
                if (mask & TIOCM_DTR){
                        if ((ret = set_dtr(serial->dev, 
                                           usb_sndctrlpipe(serial->dev, 0),
index a22b0f7704086dab9a7906097ff3738c78eb7633..8fe8a374b3ecf95a8ca6597e04fd922f072fbe24 100644 (file)
  *
  * See Documentation/usb/usb-serial.txt for more information on using this driver
  * 
+ * (07/03/2001) gkh
+ *     Fixed module paramater size.  Thanks to John Brockmeyer for the pointer.
+ *     Fixed vendor and product getting defined through the MODULE_PARM macro
+ *     if the Generic driver wasn't compiled in.
+ *     Fixed problem with generic_shutdown() not being called for drivers that
+ *     don't have a shutdown() function.
+ *
  * (06/06/2001) gkh
  *     added evil hack that is needed for the prolific pl2303 device due to the
  *     crazy way its endpoints are set up.
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v1.2"
+#define DRIVER_VERSION "v1.3"
 #define DRIVER_AUTHOR "Greg Kroah-Hartman, greg@kroah.com, http://www.kroah.com/linux-usb/"
 #define DRIVER_DESC "USB Serial Driver core"
 
@@ -347,6 +354,7 @@ static void serial_throttle (struct tty_struct * tty);
 static void serial_unthrottle (struct tty_struct * tty);
 static int  serial_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg);
 static void serial_set_termios (struct tty_struct *tty, struct termios * old);
+static void serial_shutdown (struct usb_serial *serial);
 
 static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum,
                               const struct usb_device_id *id);
@@ -736,6 +744,16 @@ static void serial_break (struct tty_struct *tty, int break_state)
 }
 
 
+static void serial_shutdown (struct usb_serial *serial)
+{
+       if (serial->type->shutdown) {
+               serial->type->shutdown(serial);
+       } else {
+               generic_shutdown(serial);
+       }
+}
+
+
 
 /*****************************************************************************
  * generic devices specific driver functions
@@ -1311,8 +1329,7 @@ static void usb_serial_disconnect(struct usb_device *dev, void *ptr)
                                serial->port[i].tty->driver_data = NULL;
                }
 
-               if (serial->type->shutdown)
-                       serial->type->shutdown(serial);
+               serial_shutdown (serial);
 
                for (i = 0; i < serial->num_ports; ++i)
                        serial->port[i].active = 0;
@@ -1426,7 +1443,7 @@ int usb_serial_init(void)
                return -1;
        }
 
-       info(DRIVER_VERSION ":" DRIVER_DESC);
+       info(DRIVER_DESC " " DRIVER_VERSION);
 
        return 0;
 }
@@ -1500,9 +1517,11 @@ MODULE_DESCRIPTION( DRIVER_DESC );
 MODULE_PARM(debug, "i");
 MODULE_PARM_DESC(debug, "Debug enabled or not");
 
-MODULE_PARM(vendor, "i");
+#ifdef CONFIG_USB_SERIAL_GENERIC
+MODULE_PARM(vendor, "h");
 MODULE_PARM_DESC(vendor, "User specified USB idVendor");
 
-MODULE_PARM(product, "i");
+MODULE_PARM(product, "h");
 MODULE_PARM_DESC(product, "User specified USB idProduct");
+#endif
 
index 7d1cd90f2d405598e732f0c2e0b31f9ac335e25e..76576dae0dbfb6542f9b79a1ca23a4532d46867c 100644 (file)
@@ -2749,7 +2749,7 @@ static int ohci_sleep_notify (struct pmu_sleep_notifier * self, int when)
 
                switch (when) {
                case PBOOK_SLEEP_NOW:
-                       ohci_pci_suspend (ohci->ohci_dev);
+                       ohci_pci_suspend (ohci->ohci_dev, 3);
                        break;
                case PBOOK_WAKE:
                        ohci_pci_resume (ohci->ohci_dev);
index 5bcdf0d8aeb1a264045252a1851579463af66707..4f41cc9c678dd13d5f54002c371ff0fd87c547df 100644 (file)
@@ -49,7 +49,7 @@
 
 #ifdef MODULE
 
-#define INCLUDE_LINUX_LOGOBW
+#define INCLUDE_LINUX_LOGO_DATA
 #include <linux/linux_logo.h>
 
 #endif /* MODULE */
index 3604e88d7f073716393bf1e2dee5ce77cbbc206e..8dbfd1b705897723aed36cfbd8916fc721270f7e 100644 (file)
@@ -1278,10 +1278,11 @@ imsttfb_setcolreg (u_int regno, u_int red, u_int green, u_int blue,
                                break;
 #endif
 #ifdef FBCON_HAS_CFB32
-                       case 32:
-                               i = (regno << 8) | regno;
+                       case 32: {
+                               int i = (regno << 8) | regno;
                                p->fbcon_cmap.cfb32[regno] = (i << 16) | i;
                                break;
+                       }
 #endif
                }
 
index 89c3c6d9d60d0f4153c80dd66234909e67e21a9f..264babd758e089507ed7be947548b7af69882ba3 100644 (file)
@@ -71,6 +71,9 @@ static char buffersize_index[65] =
 
 #define BH_ENTRY(list) list_entry((list), struct buffer_head, b_inode_buffers)
 
+#define get_bh(bh)     atomic_inc(&(bh)->b_count)
+#define put_bh(bh)     atomic_dec(&(bh)->b_count)
+
 /*
  * Hash table gook..
  */
@@ -133,6 +136,21 @@ union bdflush_param {
 int bdflush_min[N_PARAM] = {  0,  10,    5,   25,  0,   1*HZ,   0, 0, 0};
 int bdflush_max[N_PARAM] = {100,50000, 20000, 20000,600*HZ, 6000*HZ, 100, 0, 0};
 
+static inline void __unlock_buffer(struct buffer_head *bh)
+{
+       clear_bit(BH_Lock, &bh->b_state);
+       smp_mb__after_clear_bit();
+       if (waitqueue_active(&bh->b_wait))
+               wake_up(&bh->b_wait);
+}
+
+void unlock_buffer(struct buffer_head *bh)
+{
+       get_bh(bh);
+       __unlock_buffer(bh);
+       put_bh(bh);
+}
+
 /*
  * Rewrote the wait-routines to use the "new" wait-queue functionality,
  * and getting rid of the cli-sti pairs. The wait-queue routines still
@@ -147,7 +165,7 @@ void __wait_on_buffer(struct buffer_head * bh)
        struct task_struct *tsk = current;
        DECLARE_WAITQUEUE(wait, tsk);
 
-       atomic_inc(&bh->b_count);
+       get_bh(bh);
        add_wait_queue(&bh->b_wait, &wait);
        do {
                run_task_queue(&tq_disk);
@@ -158,14 +176,15 @@ void __wait_on_buffer(struct buffer_head * bh)
        } while (buffer_locked(bh));
        tsk->state = TASK_RUNNING;
        remove_wait_queue(&bh->b_wait, &wait);
-       atomic_dec(&bh->b_count);
+       put_bh(bh);
 }
 
 /* End-of-write handler.. Just mark it up-to-date and unlock the buffer. */
 static void end_buffer_write(struct buffer_head *bh, int uptodate)
 {
        mark_buffer_uptodate(bh, uptodate);
-       unlock_buffer(bh);
+       __unlock_buffer(bh);
+       put_bh(bh);
 }
 
 /*
@@ -179,14 +198,14 @@ static void end_buffer_write(struct buffer_head *bh, int uptodate)
 static void write_locked_buffers(struct buffer_head **array, unsigned int count)
 {
        struct buffer_head *wait = *array;
-       atomic_inc(&wait->b_count);
+       get_bh(wait);
        do {
                struct buffer_head * bh = *array++;
                bh->b_end_io = end_buffer_write;
                submit_bh(WRITE, bh);
        } while (--count);
        wait_on_buffer(wait);
-       atomic_dec(&wait->b_count);
+       put_bh(wait);
 }
 
 #define NRSYNC (32)
@@ -210,6 +229,7 @@ repeat:
                        continue;
                if (test_and_set_bit(BH_Lock, &bh->b_state))
                        continue;
+               get_bh(bh);
                if (atomic_set_buffer_clean(bh)) {
                        __refile_buffer(bh);
                        array[count++] = bh;
@@ -220,7 +240,8 @@ repeat:
                        write_locked_buffers(array, count);
                        goto repeat;
                }
-               unlock_buffer(bh);
+               __unlock_buffer(bh);
+               put_bh(bh);
        }
        spin_unlock(&lru_list_lock);
 
@@ -249,10 +270,10 @@ repeat:
                if (dev && bh->b_dev != dev)
                        continue;
 
-               atomic_inc(&bh->b_count);
+               get_bh(bh);
                spin_unlock(&lru_list_lock);
                wait_on_buffer (bh);
-               atomic_dec(&bh->b_count);
+               put_bh(bh);
                goto repeat;
        }
        spin_unlock(&lru_list_lock);
@@ -552,7 +573,7 @@ static inline struct buffer_head * __get_hash_table(kdev_t dev, int block, int s
                    bh->b_dev     == dev)
                        break;
        if (bh)
-               atomic_inc(&bh->b_count);
+               get_bh(bh);
 
        return bh;
 }
@@ -646,12 +667,12 @@ void __invalidate_buffers(kdev_t dev, int destroy_dirty_buffers)
                        if (!bh->b_pprev)
                                continue;
                        if (buffer_locked(bh)) {
-                               atomic_inc(&bh->b_count);
+                               get_bh(bh);
                                spin_unlock(&lru_list_lock);
                                wait_on_buffer(bh);
                                slept = 1;
                                spin_lock(&lru_list_lock);
-                               atomic_dec(&bh->b_count);
+                               put_bh(bh);
                        }
 
                        write_lock(&hash_table_lock);
@@ -711,12 +732,12 @@ void set_blocksize(kdev_t dev, int size)
                        if (!bh->b_pprev)
                                continue;
                        if (buffer_locked(bh)) {
-                               atomic_inc(&bh->b_count);
+                               get_bh(bh);
                                spin_unlock(&lru_list_lock);
                                wait_on_buffer(bh);
                                slept = 1;
                                spin_lock(&lru_list_lock);
-                               atomic_dec(&bh->b_count);
+                               put_bh(bh);
                        }
 
                        write_lock(&hash_table_lock);
@@ -802,8 +823,7 @@ static void end_buffer_io_async(struct buffer_head * bh, int uptodate)
         * that unlock the page..
         */
        spin_lock_irqsave(&page_uptodate_lock, flags);
-       unlock_buffer(bh);
-       atomic_dec(&bh->b_count);
+       __unlock_buffer(bh);
        tmp = bh->b_this_page;
        while (tmp != bh) {
                if (tmp->b_end_io == end_buffer_io_async && buffer_locked(tmp))
@@ -813,6 +833,7 @@ static void end_buffer_io_async(struct buffer_head * bh, int uptodate)
 
        /* OK, the async IO on this page is complete. */
        spin_unlock_irqrestore(&page_uptodate_lock, flags);
+       put_bh(bh);
 
        /*
         * if none of the buffers had errors then we can set the
@@ -832,6 +853,7 @@ static void end_buffer_io_async(struct buffer_head * bh, int uptodate)
        return;
 
 still_busy:
+       put_bh(bh);
        spin_unlock_irqrestore(&page_uptodate_lock, flags);
        return;
 }
@@ -879,7 +901,7 @@ int fsync_inode_buffers(struct inode *inode)
                        bh->b_inode = &tmp;
                        list_add(&bh->b_inode_buffers, &tmp.i_dirty_buffers);
                        if (buffer_dirty(bh)) {
-                               atomic_inc(&bh->b_count);
+                               get_bh(bh);
                                spin_unlock(&lru_list_lock);
                                ll_rw_block(WRITE, 1, &bh);
                                brelse(bh);
@@ -891,7 +913,7 @@ int fsync_inode_buffers(struct inode *inode)
        while (!list_empty(&tmp.i_dirty_buffers)) {
                bh = BH_ENTRY(tmp.i_dirty_buffers.prev);
                remove_inode_queue(bh);
-               atomic_inc(&bh->b_count);
+               get_bh(bh);
                spin_unlock(&lru_list_lock);
                wait_on_buffer(bh);
                if (!buffer_uptodate(bh))
@@ -935,7 +957,7 @@ int osync_inode_buffers(struct inode *inode)
             bh = BH_ENTRY(list), list != &inode->i_dirty_buffers;
             list = bh->b_inode_buffers.prev) {
                if (buffer_locked(bh)) {
-                       atomic_inc(&bh->b_count);
+                       get_bh(bh);
                        spin_unlock(&lru_list_lock);
                        wait_on_buffer(bh);
                        if (!buffer_uptodate(bh))
@@ -1130,7 +1152,7 @@ void refile_buffer(struct buffer_head *bh)
 void __brelse(struct buffer_head * buf)
 {
        if (atomic_read(&buf->b_count)) {
-               atomic_dec(&buf->b_count);
+               put_bh(buf);
                return;
        }
        printk("VFS: brelse: Trying to free free buffer\n");
@@ -1528,7 +1550,7 @@ static int __block_write_full_page(struct inode *inode, struct page *page, get_b
        do {
                lock_buffer(bh);
                bh->b_end_io = end_buffer_io_async;
-               atomic_inc(&bh->b_count);
+               get_bh(bh);
                set_bit(BH_Uptodate, &bh->b_state);
                clear_bit(BH_Dirty, &bh->b_state);
                bh = bh->b_this_page;
@@ -1536,8 +1558,9 @@ static int __block_write_full_page(struct inode *inode, struct page *page, get_b
 
        /* Stage 3: submit the IO */
        do {
+               struct buffer_head *next = bh->b_this_page;
                submit_bh(WRITE, bh);
-               bh = bh->b_this_page;           
+               bh = next;
        } while (bh != head);
 
        /* Done - end_buffer_io_async will unlock */
@@ -1729,7 +1752,7 @@ int block_read_full_page(struct page *page, get_block_t *get_block)
                struct buffer_head * bh = arr[i];
                lock_buffer(bh);
                bh->b_end_io = end_buffer_io_async;
-               atomic_inc(&bh->b_count);
+               get_bh(bh);
        }
 
        /* Stage 3: start the IO */
@@ -1982,7 +2005,8 @@ static void end_buffer_io_kiobuf(struct buffer_head *bh, int uptodate)
        mark_buffer_uptodate(bh, uptodate);
 
        kiobuf = bh->b_private;
-       unlock_buffer(bh);
+       __unlock_buffer(bh);
+       put_bh(bh);
        end_kio_request(kiobuf, uptodate);
 }
 
@@ -2107,7 +2131,7 @@ int brw_kiovec(int rw, int nr, struct kiobuf *iovec[],
                                offset += size;
 
                                atomic_inc(&iobuf->io_count);
-
+                               get_bh(tmp);
                                submit_bh(rw, tmp);
                                /* 
                                 * Wait for IO if we have got too much 
@@ -2175,14 +2199,15 @@ int brw_page(int rw, struct page *page, kdev_t dev, int b[], int size)
                bh->b_blocknr = *(b++);
                set_bit(BH_Mapped, &bh->b_state);
                bh->b_end_io = end_buffer_io_async;
-               atomic_inc(&bh->b_count);
+               get_bh(bh);
                bh = bh->b_this_page;
        } while (bh != head);
 
        /* Stage 2: start the IO */
        do {
+               struct buffer_head *next = bh->b_this_page;
                submit_bh(rw, bh);
-               bh = bh->b_this_page;
+               bh = next;
        } while (bh != head);
        return 0;
 }
@@ -2554,10 +2579,10 @@ static int flush_dirty_buffers(int check_flushtime)
                }
 
                /* OK, now we are committed to write it out. */
-               atomic_inc(&bh->b_count);
+               get_bh(bh);
                spin_unlock(&lru_list_lock);
                ll_rw_block(WRITE, 1, &bh);
-               atomic_dec(&bh->b_count);
+               put_bh(bh);
 
                if (current->need_resched)
                        schedule();
index d61d6b9df29cbc7f61042c8a58c38a8faa582e05..b067f3f1bfdfdf13d09e7ef277d49de8453d0cdc 100644 (file)
@@ -146,51 +146,53 @@ static int meminfo_read_proc(char *page, char **start, off_t off,
  */
 #define K(x) ((x) << (PAGE_SHIFT - 10))
 #define B(x) ((x) << PAGE_SHIFT)
-        si_meminfo(&i);
-        si_swapinfo(&i);
-        len = sprintf(page, "        total:    used:    free:  shared: buffers:  cached:\n"
-                "Mem:  %8lu %8lu %8lu %8lu %8lu %8u\n"
-                "Swap: %8lu %8lu %8lu\n",
-                B(i.totalram), B(i.totalram-i.freeram), B(i.freeram),
-                B(i.sharedram), B(i.bufferram),
-                B(atomic_read(&page_cache_size)), B(i.totalswap),
-                B(i.totalswap-i.freeswap), B(i.freeswap));
-        /*
-         * Tagged format, for easy grepping and expansion.
-         * The above will go away eventually, once the tools
-         * have been updated.
-         */
-        len += sprintf(page+len,
-                "MemTotal:     %8lu kB\n"
-                "MemFree:      %8lu kB\n"
-                "MemShared:    %8lu kB\n"
-                "Buffers:      %8lu kB\n"
-                "Cached:       %8u kB\n"
+       si_meminfo(&i);
+       si_swapinfo(&i);
+       len = sprintf(page, "        total:    used:    free:  shared: buffers:  cached:\n"
+               "Mem:  %8lu %8lu %8lu %8lu %8lu %8u\n"
+               "Swap: %8lu %8lu %8lu\n",
+               B(i.totalram), B(i.totalram-i.freeram), B(i.freeram),
+               B(i.sharedram), B(i.bufferram),
+               B(atomic_read(&page_cache_size)), B(i.totalswap),
+               B(i.totalswap-i.freeswap), B(i.freeswap));
+       /*
+        * Tagged format, for easy grepping and expansion.
+        * The above will go away eventually, once the tools
+        * have been updated.
+        */
+       len += sprintf(page+len,
+               "MemTotal:     %8lu kB\n"
+               "MemFree:      %8lu kB\n"
+               "MemShared:    %8lu kB\n"
+               "Buffers:      %8lu kB\n"
+               "Cached:       %8lu kB\n"
+               "SwapCached:   %8lu kB\n"
                "Active:       %8u kB\n"
                "Inact_dirty:  %8u kB\n"
                "Inact_clean:  %8u kB\n"
                "Inact_target: %8lu kB\n"
-                "HighTotal:    %8lu kB\n"
-                "HighFree:     %8lu kB\n"
-                "LowTotal:     %8lu kB\n"
-                "LowFree:      %8lu kB\n"
-                "SwapTotal:    %8lu kB\n"
-                "SwapFree:     %8lu kB\n",
-                K(i.totalram),
-                K(i.freeram),
-                K(i.sharedram),
-                K(i.bufferram),
-                K(atomic_read(&page_cache_size)),
+               "HighTotal:    %8lu kB\n"
+               "HighFree:     %8lu kB\n"
+               "LowTotal:     %8lu kB\n"
+               "LowFree:      %8lu kB\n"
+               "SwapTotal:    %8lu kB\n"
+               "SwapFree:     %8lu kB\n",
+               K(i.totalram),
+               K(i.freeram),
+               K(i.sharedram),
+               K(i.bufferram),
+               K(atomic_read(&page_cache_size) - swapper_space.nrpages),
+               K(swapper_space.nrpages),
                K(nr_active_pages),
                K(nr_inactive_dirty_pages),
                K(nr_inactive_clean_pages()),
                K(inactive_target),
-                K(i.totalhigh),
-                K(i.freehigh),
-                K(i.totalram-i.totalhigh),
-                K(i.freeram-i.freehigh),
-                K(i.totalswap),
-                K(i.freeswap));
+               K(i.totalhigh),
+               K(i.freehigh),
+               K(i.totalram-i.totalhigh),
+               K(i.freeram-i.freehigh),
+               K(i.totalswap),
+               K(i.freeswap));
 
        return proc_calc_metrics(page, start, off, count, eof, len);
 #undef B
@@ -289,11 +291,11 @@ static int kstat_read_proc(char *page, char **start, off_t off,
                        kstat.per_cpu_nice[cpu_logical_map(i)],
                        kstat.per_cpu_system[cpu_logical_map(i)],
                        jif - (  kstat.per_cpu_user[cpu_logical_map(i)] \
-                                  + kstat.per_cpu_nice[cpu_logical_map(i)] \
-                                  + kstat.per_cpu_system[cpu_logical_map(i)]));
+                                  + kstat.per_cpu_nice[cpu_logical_map(i)] \
+                                  + kstat.per_cpu_system[cpu_logical_map(i)]));
        len += sprintf(page + len,
                "page %u %u\n"
-                "swap %u %u\n"
+               "swap %u %u\n"
                "intr %u",
                        kstat.pgpgin >> 1,
                        kstat.pgpgout >> 1,
index 5bff91f6c83b065793a9d5fc343a01a7522e4f19..3265d150be1a16bc721f56a6cef568f5c9dfce59 100644 (file)
@@ -211,7 +211,7 @@ got_it:
        if (err)
                goto out_unlock;
        memcpy (de->name, name, namelen);
-       memset (de->name + namelen, 0, SYSV_DIRSIZE - namelen);
+       memset (de->name + namelen, 0, SYSV_DIRSIZE - namelen - 2);
        de->inode = cpu_to_fs16(inode->i_sb, inode->i_ino);
        err = dir_commit_chunk(page, from, to);
        dir->i_mtime = dir->i_ctime = CURRENT_TIME;
index e2f6fbe91fc8f6188d13b1159b5165ca43c8366b..0470ea55e6a98a96df34f136e14392e7bc8dd31c 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: vaddrs.h,v 1.26 2000/08/01 04:53:58 anton Exp $ */
+/* $Id: vaddrs.h,v 1.27 2001/07/04 00:18:18 davem Exp $ */
 #ifndef _SPARC_VADDRS_H
 #define _SPARC_VADDRS_H
 
index a738fb363a40063a5ff95ed3064855751deecd89..b606cb2b32a89536e6f55f38cd5e37bd9e709e34 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: starfire.h,v 1.1 2000/09/21 06:18:53 anton Exp $
+/* $Id: starfire.h,v 1.2 2001/07/04 00:18:18 davem Exp $
  * starfire.h: Group all starfire specific code together.
  *
  * Copyright (C) 2000 Anton Blanchard (anton@samba.org)
index b43c299448df458064613725efafaeec7738c027..9843b91077d201c3dc18f9107435efaffb365f83 100644 (file)
@@ -35,6 +35,7 @@
 #define        ARPHRD_IEEE802  6               /* IEEE 802.2 Ethernet/TR/TB    */
 #define        ARPHRD_ARCNET   7               /* ARCnet                       */
 #define        ARPHRD_APPLETLK 8               /* APPLEtalk                    */
+#define        ARPHRD_IEEE1394 9               /* IEEE 1394 IPv4 - RFC 2734    */
 #define ARPHRD_DLCI    15              /* Frame Relay DLCI             */
 #define ARPHRD_ATM     19              /* ATM                          */
 #define ARPHRD_METRICOM        23              /* Metricom STRIP (new IANA id) */
index cca81b6b50a50151508a5a6e1f6005fc40165048..e09c9cccee026389dcca3692253a2a11362191a0 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: isdnif.h,v 1.37.6.4 2001/06/09 15:14:19 kai Exp $
+/* $Id: isdnif.h,v 1.37.6.5 2001/06/11 22:08:38 kai Exp $
 
  * Linux ISDN subsystem
  *
index 1c1f2bbb19ebfe2146e99a50ad1c9648684dbd1f..1c3fa10b92709f08d37f5c45d599cec5ae31c35f 100644 (file)
@@ -26,13 +26,7 @@ extern inline void lock_buffer(struct buffer_head * bh)
                __wait_on_buffer(bh);
 }
 
-extern inline void unlock_buffer(struct buffer_head *bh)
-{
-       clear_bit(BH_Lock, &bh->b_state);
-       smp_mb__after_clear_bit();
-       if (waitqueue_active(&bh->b_wait))
-               wake_up(&bh->b_wait);
-}
+extern void unlock_buffer(struct buffer_head *bh);
 
 /*
  * super-block locking. Again, interrupts may only unlock
index c79ab58b0d553127fcd72a869cf4d47277f0a616..9702fda030d5b36a8d34a723874296652e87af2c 100644 (file)
@@ -194,6 +194,7 @@ EXPORT_SYMBOL(__brelse);
 EXPORT_SYMBOL(__bforget);
 EXPORT_SYMBOL(ll_rw_block);
 EXPORT_SYMBOL(submit_bh);
+EXPORT_SYMBOL(unlock_buffer);
 EXPORT_SYMBOL(__wait_on_buffer);
 EXPORT_SYMBOL(___wait_on_page);
 EXPORT_SYMBOL(block_write_full_page);
index 86b9354a2424d7133ce64ea64fa73d602f07f63c..d7794cff771646e6ab4bf2c72e9150c5fc575dbd 100644 (file)
@@ -1649,10 +1649,13 @@ static inline int filemap_sync_pte(pte_t * ptep, struct vm_area_struct *vma,
 {
        pte_t pte = *ptep;
 
-       if (pte_present(pte) && ptep_test_and_clear_dirty(ptep)) {
+       if (pte_present(pte)) {
                struct page *page = pte_page(pte);
-               flush_tlb_page(vma, address);
-               set_page_dirty(page);
+               if (VALID_PAGE(page) && !PageReserved(page) && ptep_test_and_clear_dirty(ptep)) {
+                       flush_tlb_page(vma, address);
+                       if (page->mapping)
+                               set_page_dirty(page);
+               }
        }
        return 0;
 }
index cd6d4896522e347f3243831262ea1ab1ef2a2e65..f99c7367ab2c3aae1bf9b916b4a7c17ffd825a08 100644 (file)
@@ -1108,9 +1108,6 @@ static int do_swap_page(struct mm_struct * mm,
                        spin_lock(&mm->page_table_lock);
                        return -1;
                }
-               wait_on_page(page);
-               flush_page_to_ram(page);
-               flush_icache_page(vma, page);
        }
 
        /*
@@ -1140,6 +1137,8 @@ static int do_swap_page(struct mm_struct * mm,
                pte = pte_mkwrite(pte_mkdirty(pte));
        UnlockPage(page);
 
+       flush_page_to_ram(page);
+       flush_icache_page(vma, page);
        set_pte(page_table, pte);
 
        /* No need to invalidate - it was non-present before */
index 3617a5585af408cd18f033244fc535942f3453e8..74b7121ddf1c69897a0bf0ca47b1398637da97d4 100644 (file)
@@ -191,6 +191,8 @@ void oom_kill(void)
  */
 int out_of_memory(void)
 {
+       long cache_mem, limit;
+
        /* Enough free memory?  Not OOM. */
        if (nr_free_pages() > freepages.min)
                return 0;
@@ -198,6 +200,21 @@ int out_of_memory(void)
        if (nr_free_pages() + nr_inactive_clean_pages() > freepages.low)
                return 0;
 
+       /*
+        * If the buffer and page cache (excluding swap cache) are over
+        * their (/proc tunable) minimum, we're still not OOM.  We test
+        * this to make sure we don't return OOM when the system simply
+        * has a hard time with the cache.
+        */
+       cache_mem = atomic_read(&page_cache_size);
+       cache_mem += atomic_read(&buffermem_pages);
+       cache_mem -= swapper_space.nrpages;
+       limit = (page_cache.min_percent + buffer_mem.min_percent);
+       limit *= num_physpages / 100;
+
+       if (cache_mem > limit)
+               return 0;
+
        /* Enough swap space left?  Not OOM. */
        if (nr_swap_pages > 0)
                return 0;
index 71f868e3cc4cebbff653cf5b67a274c273a1ff10..d19bf7e794cc9c0a1378abea93d7409de0b750c8 100644 (file)
@@ -223,7 +223,7 @@ static void shmem_delete_inode(struct inode * inode)
  */
 static int shmem_writepage(struct page * page)
 {
-       int error = 0;
+       int error;
        struct shmem_inode_info *info;
        swp_entry_t *entry, swap;
        struct inode *inode;
@@ -231,17 +231,14 @@ static int shmem_writepage(struct page * page)
        if (!PageLocked(page))
                BUG();
        
-       /* Only move to the swap cache if there are no other users of
-        * the page. */
-       if (atomic_read(&page->count) > 2)
-               goto out;
-       
        inode = page->mapping->host;
        info = &inode->u.shmem_i;
        swap = __get_swap_page(2);
        error = -ENOMEM;
-       if (!swap.val)
+       if (!swap.val) {
+               activate_page(page);
                goto out;
+       }
 
        spin_lock(&info->lock);
        entry = shmem_swp_entry(info, page->index);
index 142c7df7c121f9d6e2a31fd05d5a6c3e95a0a741..c5ae51446c576febfc405e110b73f6e5c6ded0ea 100644 (file)
@@ -81,6 +81,7 @@ void add_to_swap_cache(struct page *page, swp_entry_t entry)
                BUG();
        flags = page->flags & ~((1 << PG_error) | (1 << PG_arch_1));
        page->flags = flags | (1 << PG_uptodate);
+       page->age = PAGE_AGE_START;
        add_to_page_cache_locked(page, &swapper_space, entry.val);
 }
 
index 056eaa043b642a7aa52c2b620b72cc8ddb3c7de2..4d96bf2d9fd5cdb2d9b19b0837362280244ab47e 100644 (file)
@@ -68,106 +68,77 @@ static void dn_send_ptp_hello(struct net_device *dev);
 
 static struct dn_dev_parms dn_dev_list[] =  {
 {
-       ARPHRD_ETHER, /* Ethernet */
-       DN_DEV_BCAST,
-       DN_DEV_S_RU,
-       0,
-       1498,
-       1,
-       10,
-       0,
-       "ethernet",
-       NET_DECNET_CONF_ETHER,
-       dn_eth_up,
-       NULL,
-       dn_send_brd_hello,
-       NULL
+       type:           ARPHRD_ETHER, /* Ethernet */
+       mode:           DN_DEV_BCAST,
+       state:          DN_DEV_S_RU,
+       blksize:        1498,
+       t2:             1,
+       t3:             10,
+       name:           "ethernet",
+       ctl_name:       NET_DECNET_CONF_ETHER,
+       up:             dn_eth_up,
+       timer3:         dn_send_brd_hello,
 },
 {
-       ARPHRD_IPGRE, /* DECnet tunneled over GRE in IP */
-       DN_DEV_BCAST,
-       DN_DEV_S_RU,
-       0,
-       1400,
-       1,
-       10,
-       0,
-       "ipgre",
-       NET_DECNET_CONF_GRE,
-       NULL,
-       NULL,
-       dn_send_brd_hello,
-       NULL
+       type:           ARPHRD_IPGRE, /* DECnet tunneled over GRE in IP */
+       mode:           DN_DEV_BCAST,
+       state:          DN_DEV_S_RU,
+       blksize:        1400,
+       t2:             1,
+       t3:             10,
+       name:           "ipgre",
+       ctl_name:       NET_DECNET_CONF_GRE,
+       timer3:         dn_send_brd_hello,
 },
 #if 0
 {
-       ARPHRD_X25, /* Bog standard X.25 */
-       DN_DEV_UCAST,
-       DN_DEV_S_DS,
-       0,
-       230,
-       1,
-       120,
-       0,
-       "x25",
-       NET_DECNET_CONF_X25,
-       NULL,
-       NULL,
-       dn_send_ptp_hello,
-       NULL
+       type:           ARPHRD_X25, /* Bog standard X.25 */
+       mode:           DN_DEV_UCAST,
+       state:          DN_DEV_S_DS,
+       blksize:        230,
+       t2:             1,
+       t3:             120,
+       name:           "x25",
+       ctl_name:       NET_DECNET_CONF_X25,
+       timer3:         dn_send_ptp_hello,
 },
 #endif
 #if 0
 {
-       ARPHRD_PPP, /* DECnet over PPP */
-       DN_DEV_BCAST,
-       DN_DEV_S_RU,
-       0,
-       230,
-       1,
-       10,
-       0,
-       "ppp",
-       NET_DECNET_CONF_PPP,
-       NULL,
-       NULL,
-       dn_send_brd_hello,
-       NULL
+       type:           ARPHRD_PPP, /* DECnet over PPP */
+       mode:           DN_DEV_BCAST,
+       state:          DN_DEV_S_RU,
+       blksize:        230,
+       t2:             1,
+       t3:             10,
+       name:           "ppp",
+       ctl_name:       NET_DECNET_CONF_PPP,
+       timer3:         dn_send_brd_hello,
 },
 #endif
 #if 0
 {
-       ARPHRD_DDCMP, /* DECnet over DDCMP */
-       DN_DEV_UCAST,
-       DN_DEV_S_DS,
-       0,
-       230,
-       1,
-       120,
-       0,
-       "ddcmp",
-       NET_DECNET_CONF_DDCMP,
-       NULL,
-       NULL,
-       dn_send_ptp_hello,
-       NULL
+       type:           ARPHRD_DDCMP, /* DECnet over DDCMP */
+       mode:           DN_DEV_UCAST,
+       state:          DN_DEV_S_DS,
+       blksize:        230,
+       t2:             1,
+       t3:             120,
+       name:           "ddcmp",
+       ctl_name:       NET_DECNET_CONF_DDCMP,
+       timer3:         dn_send_ptp_hello,
 },
 #endif
 {
-       ARPHRD_LOOPBACK, /* Loopback interface - always last */
-       DN_DEV_BCAST,
-       DN_DEV_S_RU,
-       0,
-       1498,
-       1,
-       10,
-       0,
-       "loopback",
-       NET_DECNET_CONF_LOOPBACK,
-       NULL,
-       NULL,
-       dn_send_brd_hello,
-       NULL
+       type:           ARPHRD_LOOPBACK, /* Loopback interface - always last */
+       mode:           DN_DEV_BCAST,
+       state:          DN_DEV_S_RU,
+       blksize:        1498,
+       t2:             1,
+       t3:             10,
+       name:           "loopback",
+       ctl_name:       NET_DECNET_CONF_LOOPBACK,
+       timer3:         dn_send_brd_hello,
 }
 };
 
@@ -182,7 +153,7 @@ static int max_t2[] = { 60 }; /* No max specified, but this seems sensible */
 static int min_t3[] = { 1 };
 static int max_t3[] = { 8191 }; /* Must fit in 16 bits when multiplied by BCT3MULT or T3MULT */
 
-static int min_priority[] = { 0 };
+static int min_priority[1];
 static int max_priority[] = { 127 }; /* From DECnet spec */
 
 static int dn_forwarding_proc(ctl_table *, int, struct file *,
@@ -344,7 +315,8 @@ static int dn_forwarding_sysctl(ctl_table *table, int *name, int nlen,
                if (newlen != sizeof(int))
                        return -EINVAL;
 
-               get_user(value, (int *)newval);
+               if (get_user(value, (int *)newval))
+                       return -EFAULT;
                if (value < 0)
                        return -EINVAL;
                if (value > 2)
index 9c8d493b59172c52edcf03cf19738f178f365779..9fee820f6d0e5c03beed692614864ec72a7fa23f 100644 (file)
 #include <linux/sysctl.h>
 #include <linux/proc_fs.h>
 #include <net/sock.h>
+#include <net/route.h>
 
 #include <linux/netfilter_ipv4/ip_queue.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
 
 #define IPQ_QMAX_DEFAULT 1024
 #define IPQ_PROC_FS_NAME "ip_queue"
 #define NET_IPQ_QMAX 2088
 #define NET_IPQ_QMAX_NAME "ip_queue_maxlen"
 
+typedef struct ipq_rt_info {
+       __u8 tos;
+       __u32 daddr;
+       __u32 saddr;
+} ipq_rt_info_t;
+
 typedef struct ipq_queue_element {
        struct list_head list;          /* Links element into queue */
        int verdict;                    /* Current verdict */
        struct nf_info *info;           /* Extra info from netfilter */
        struct sk_buff *skb;            /* Packet inside */
+       ipq_rt_info_t rt_info;          /* May need post-mangle routing */
 } ipq_queue_element_t;
 
 typedef int (*ipq_send_cb_t)(ipq_queue_element_t *e);
@@ -64,7 +73,6 @@ typedef struct ipq_queue {
  * Packet queue
  *
  ****************************************************************************/
-
 /* Dequeue a packet if matched by cmp, or the next available if cmp is NULL */
 static ipq_queue_element_t *
 ipq_dequeue(ipq_queue_t *q,
@@ -150,9 +158,19 @@ static int ipq_enqueue(ipq_queue_t *q,
                printk(KERN_ERR "ip_queue: OOM in enqueue\n");
                return -ENOMEM;
        }
+
        e->verdict = NF_DROP;
        e->info = info;
        e->skb = skb;
+
+       if (e->info->hook == NF_IP_LOCAL_OUT) {
+               struct iphdr *iph = skb->nh.iph;
+
+               e->rt_info.tos = iph->tos;
+               e->rt_info.daddr = iph->daddr;
+               e->rt_info.saddr = iph->saddr;
+       }
+
        spin_lock_bh(&q->lock);
        if (q->len >= *q->maxlen) {
                spin_unlock_bh(&q->lock);
@@ -198,6 +216,32 @@ static void ipq_destroy_queue(ipq_queue_t *q)
        kfree(q);
 }
 
+/* With a chainsaw... */
+static int route_me_harder(struct sk_buff *skb)
+{
+       struct iphdr *iph = skb->nh.iph;
+       struct rtable *rt;
+
+       struct rt_key key = {
+                               dst:iph->daddr, src:iph->saddr,
+                               oif:skb->sk ? skb->sk->bound_dev_if : 0,
+                               tos:RT_TOS(iph->tos)|RTO_CONN,
+#ifdef CONFIG_IP_ROUTE_FWMARK
+                               fwmark:skb->nfmark
+#endif
+                       };
+
+       if (ip_route_output_key(&rt, &key) != 0) {
+               printk("route_me_harder: No more route.\n");
+               return -EINVAL;
+       }
+
+       /* Drop old route. */
+       dst_release(skb->dst);
+       skb->dst = &rt->u.dst;
+       return 0;
+}
+
 static int ipq_mangle_ipv4(ipq_verdict_msg_t *v, ipq_queue_element_t *e)
 {
        int diff;
@@ -223,6 +267,8 @@ static int ipq_mangle_ipv4(ipq_verdict_msg_t *v, ipq_queue_element_t *e)
                                      "in mangle, dropping packet\n");
                                return -ENOMEM;
                        }
+                       if (e->skb->sk)
+                               skb_set_owner_w(newskb, e->skb->sk);
                        kfree_skb(e->skb);
                        e->skb = newskb;
                }
@@ -230,6 +276,19 @@ static int ipq_mangle_ipv4(ipq_verdict_msg_t *v, ipq_queue_element_t *e)
        }
        memcpy(e->skb->data, v->payload, v->data_len);
        e->skb->nfcache |= NFC_ALTERED;
+
+       /*
+        * Extra routing may needed on local out, as the QUEUE target never
+        * returns control to the table.
+        */
+       if (e->info->hook == NF_IP_LOCAL_OUT) {
+               struct iphdr *iph = e->skb->nh.iph;
+
+               if (!(iph->tos == e->rt_info.tos
+                     && iph->daddr == e->rt_info.daddr
+                     && iph->saddr == e->rt_info.saddr))
+                       return route_me_harder(e->skb);
+       }
        return 0;
 }
 
@@ -400,6 +459,13 @@ static struct sk_buff *netlink_build_message(ipq_queue_element_t *e, int *errp)
        if (e->info->outdev) strcpy(pm->outdev_name, e->info->outdev->name);
        else pm->outdev_name[0] = '\0';
        pm->hw_protocol = e->skb->protocol;
+       if (e->info->indev && e->skb->dev) {
+               pm->hw_type = e->skb->dev->type;
+               if (e->skb->dev->hard_header_parse)
+                       pm->hw_addrlen =
+                               e->skb->dev->hard_header_parse(e->skb,
+                                                              pm->hw_addr);
+       }
        if (data_len)
                memcpy(pm->payload, e->skb->data, data_len);
        nlh->nlmsg_len = skb->tail - old_tail;
@@ -431,10 +497,15 @@ extern __inline__ void netlink_receive_user_skb(struct sk_buff *skb)
        int status, type;
        struct nlmsghdr *nlh;
 
+       if (skb->len < sizeof(struct nlmsghdr))
+               return;
+
        nlh = (struct nlmsghdr *)skb->data;
-       if (nlh->nlmsg_len < sizeof(*nlh)
-           || skb->len < nlh->nlmsg_len
-           || nlh->nlmsg_pid <= 0
+       if (nlh->nlmsg_len < sizeof(struct nlmsghdr)
+           || skb->len < nlh->nlmsg_len)
+               return;
+
+       if(nlh->nlmsg_pid <= 0
            || !(nlh->nlmsg_flags & NLM_F_REQUEST)
            || nlh->nlmsg_flags & NLM_F_MULTI)
                RCV_SKB_FAIL(-EINVAL);
index 8779c6bb9ede77fdf60eb800cbb08ba9279a7259..69d18834df3b8b5bf2bb112cd452f62a4611436e 100644 (file)
@@ -268,6 +268,7 @@ check_tcp(const struct iphdr *iph,
          int embedded)
 {
        u_int8_t *opt = (u_int8_t *)tcph;
+       u_int8_t *endhdr = (u_int8_t *)tcph + tcph->doff * 4;
        u_int8_t tcpflags;
        int end_of_options = 0;
        size_t i;
@@ -373,7 +374,7 @@ check_tcp(const struct iphdr *iph,
                                return 0;
                        }
                        /* CHECK: oversize options. */
-                       else if (opt[i+1] + i >= tcph->doff * 4) {
+                       else if (&opt[i] + opt[i+1] > endhdr) {
                                limpk("TCP option %u at %Zu too long\n",
                                      (unsigned int) opt[i], i);
                                return 0;
@@ -392,6 +393,7 @@ static int
 check_ip(struct iphdr *iph, size_t length, int embedded)
 {
        u_int8_t *opt = (u_int8_t *)iph;
+       u_int8_t *endhdr = (u_int8_t *)iph + iph->ihl * 4;
        int end_of_options = 0;
        void *protoh;
        size_t datalen;
@@ -444,7 +446,7 @@ check_ip(struct iphdr *iph, size_t length, int embedded)
                                return 0;
                        }
                        /* CHECK: oversize options. */
-                       else if (opt[i+1] + i > iph->ihl * 4) {
+                       else if (&opt[i] + opt[i+1] > endhdr) {
                                limpk("IP option %u at %u too long\n",
                                      opt[i], i);
                                return 0;
index 60d4698fb74e0751186d9c9894cfc0ed290a4774..cefcd79e6f0d73333ceb3ad2d95948c8add48b09 100644 (file)
@@ -148,7 +148,7 @@ ipt_local_out_hook(unsigned int hook,
 
        ret = ipt_do_table(pskb, hook, in, out, &packet_mangler, NULL);
        /* Reroute for ANY change. */
-       if (ret != NF_DROP && ret != NF_STOLEN
+       if (ret != NF_DROP && ret != NF_STOLEN && ret != NF_QUEUE
            && ((*pskb)->nh.iph->saddr != saddr
                || (*pskb)->nh.iph->daddr != daddr
                || (*pskb)->nfmark != nfmark