]> git.hungrycats.org Git - linux/commitdiff
[PATCH] Fusion driver update
authorPam Delaney <pdelaney@lsil.com>
Thu, 20 Jun 2002 05:08:20 +0000 (22:08 -0700)
committerLinus Torvalds <torvalds@home.transmeta.com>
Thu, 20 Jun 2002 05:08:20 +0000 (22:08 -0700)
This upgrades the fusion driver

 - Provides support for the Ultra320 1030/1020 parts
 - Provides support for the PCI-X FC parts (919X/929X)
 - Provides proper support for high memory cases
 - Provides IA64 support
 - Adds kernels calls (pci_enable_device, pci_set_dma_mask,
   scsi_set_pci_device) for proper registration of PCI devics.
 - Adds New Error Handling support

23 files changed:
drivers/block/genhd.c
drivers/message/fusion/Config.in
drivers/message/fusion/isense.c
drivers/message/fusion/linux_compat.h
drivers/message/fusion/lsi/fc_log.h
drivers/message/fusion/lsi/mpi.h
drivers/message/fusion/lsi/mpi_cnfg.h
drivers/message/fusion/lsi/mpi_fc.h
drivers/message/fusion/lsi/mpi_init.h
drivers/message/fusion/lsi/mpi_ioc.h
drivers/message/fusion/lsi/mpi_lan.h
drivers/message/fusion/lsi/mpi_raid.h [new file with mode: 0644]
drivers/message/fusion/lsi/mpi_targ.h
drivers/message/fusion/lsi/mpi_type.h
drivers/message/fusion/mptbase.c
drivers/message/fusion/mptbase.h
drivers/message/fusion/mptctl.c
drivers/message/fusion/mptctl.h [new file with mode: 0644]
drivers/message/fusion/mptlan.c
drivers/message/fusion/mptlan.h
drivers/message/fusion/mptscsih.c
drivers/message/fusion/mptscsih.h
drivers/message/fusion/scsi3.h

index 9cd5ab4d6573154854d953d787c82118a0a6b638..7c30fbe37c164126d33ab1779f07bc5a294a4607 100644 (file)
@@ -200,9 +200,6 @@ struct seq_operations partitions_op = {
 
 
 extern int blk_dev_init(void);
-#ifdef CONFIG_FUSION
-extern int fusion_init(void);
-#endif
 extern int soc_probe(void);
 extern int atmdev_init(void);
 extern int i2o_init(void);
@@ -216,9 +213,6 @@ int __init device_init(void)
 #ifdef CONFIG_I2O
        i2o_init();
 #endif
-#ifdef CONFIG_FUSION
-       fusion_init();
-#endif
 #ifdef CONFIG_FC4_SOC
        /* This has to be done before scsi_dev_init */
        soc_probe();
index 5d865a19579619836b5aecfe604dd1e2e8eea863..9eb787ce0eacd54c49c6f390dfe61a2f07412ab1 100644 (file)
@@ -5,21 +5,33 @@ dep_tristate "Fusion MPT (base + ScsiHost) drivers" CONFIG_FUSION $CONFIG_SCSI $
 
 if [ "$CONFIG_FUSION" = "y" -o "$CONFIG_FUSION" = "m" ]; then
 
-  if [ "$CONFIG_FUSION" = "y" ]; then
-    comment "(ability to boot linux kernel from Fusion device is ENABLED!)"
+  if [ "$CONFIG_BLK_DEV_SD" = "y" -a "$CONFIG_FUSION" = "y" ]; then
+    define_bool CONFIG_FUSION_BOOT y
   else
-    comment "(ability to boot linux kernel from Fusion device is DISABLED!)"
+    define_bool CONFIG_FUSION_BOOT n
   fi
 
-  # Modular only
-  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
+  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
index 524157014b4c89e3bfb8079f518db231987cf7c0..c186865fe5b4955c70b8a94062ee6f29ce818511 100644 (file)
@@ -5,12 +5,13 @@
  *      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
+ *  Copyright (c) 1991-2002 Steven J. Ralston
  *  Written By: Steven J. Ralston
  *  (yes I wrote some of the orig. code back in 1991!)
- *  (mailto:Steve.Ralston@lsil.com)
+ *  (mailto:sjralston1@netscape.net)
+ *  (mailto:Pam.Delaney@lsil.com)
  *
- *  $Id: isense.c,v 1.28.14.1 2001/08/24 20:07:04 sralston Exp $
+ *  $Id: isense.c,v 1.33 2002/02/27 18:44:19 sralston Exp $
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
 */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 
-#include <linux/module.h>
+#include <linux/version.h>
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/init.h>
-#include <linux/version.h>
+#include <asm/io.h>
+#if defined (__sparc__)
+#include <linux/timer.h>
+#endif
 
 /* Hmmm, avoid undefined spinlock_t on lk-2.2.14-5.0 */
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
@@ -61,7 +66,7 @@
 #endif
 
 #define MODULEAUTHOR "Steven J. Ralston"
-#define COPYRIGHT "Copyright (c) 2001 " MODULEAUTHOR
+#define COPYRIGHT "Copyright (c) 2001-2002 " MODULEAUTHOR
 #include "mptbase.h"
 
 #include "isense.h"
@@ -84,9 +89,9 @@
 #define my_VERSION     MPT_LINUX_VERSION_COMMON
 #define MYNAM          "isense"
 
+EXPORT_NO_SYMBOLS;
 MODULE_AUTHOR(MODULEAUTHOR);
 MODULE_DESCRIPTION(my_NAME);
-MODULE_LICENSE("GPL");
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 int __init isense_init(void)
index 21d651007d7dd45ff8d3766005a847148d625318..3b58245d608ddf1b90a527e58b57d76970dbb904 100644 (file)
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 
+#ifndef rwlock_init
+#define rwlock_init(x) do { *(x) = RW_LOCK_UNLOCKED; } while(0)
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+#define SET_NICE(current,x)    do {(current)->nice = (x);} while (0)
+#else
+#define SET_NICE(current,x)
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
+#define pci_enable_device(pdev)        (0)
+#define SCSI_DATA_UNKNOWN      0
+#define SCSI_DATA_WRITE                1
+#define SCSI_DATA_READ         2
+#define SCSI_DATA_NONE         3
+#endif
+
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4)
+#define pci_set_dma_mask(pdev, mask)   (0)
+#define scsi_set_pci_device(sh, pdev)  (0)
+#endif
+
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
 #      if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18)
                typedef unsigned int dma_addr_t;
@@ -58,12 +82,33 @@ typedef void (*__cleanup_module_func_t)(void);
        extern inline __cleanup_module_func_t __cleanup_module_inline(void) \
        { return x; }
 
-#else 
+#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 */
 
+/* This block snipped from lk-2.2.18/include/linux/sched.h { */
+/*
+ * Used prior to schedule_timeout calls..
+ */
+#define __set_current_state(state_value)       do { current->state = state_value; } while (0)
+#ifdef __SMP__
+#define set_current_state(state_value)         do { __set_current_state(state_value); mb(); } while (0)
+#else
+#define set_current_state(state_value)         __set_current_state(state_value)
+#endif
+/* } block snipped from lk-2.2.18/include/linux/sched.h */
+
+/* procfs compat stuff... */
+#define proc_mkdir(x,y)                        create_proc_entry(x, S_IFDIR, y)
+
+/* MUTEX compat stuff... */
+#define DECLARE_MUTEX(name)            struct semaphore name=MUTEX
+#define DECLARE_MUTEX_LOCKED(name)     struct semaphore name=MUTEX_LOCKED
+#define init_MUTEX(x)                  *(x)=MUTEX
+#define init_MUTEX_LOCKED(x)           *(x)=MUTEX_LOCKED
+
 /* Wait queues. */
 #define DECLARE_WAIT_QUEUE_HEAD(name)  \
        struct wait_queue * (name) = NULL
@@ -90,6 +135,17 @@ typedef void (*__cleanup_module_func_t)(void);
 #endif         /* LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18) */
 
 
+/*
+ * Inclined to use:
+ *   #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,10)
+ * here, but MODULE_LICENSE defined in 2.4.9-6 and 2.4.9-13
+ * breaks the rule:-(
+ */
+#ifndef MODULE_LICENSE
+#define MODULE_LICENSE(license)
+#endif
+
+
 /* PCI/driver subsystem { */
 #ifndef pci_for_each_dev
 #define pci_for_each_dev(dev)          for((dev)=pci_devices; (dev)!=NULL; (dev)=(dev)->next)
@@ -120,26 +176,6 @@ typedef void (*__cleanup_module_func_t)(void);
 #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
 /*{-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -194,6 +230,28 @@ static __inline__ int __get_order(unsigned long size)
 /*}-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 #endif /* PCI_DMA_BIDIRECTIONAL */
 
+/*
+ *  With the new command queuing code in the SCSI mid-layer we no longer have
+ *  to hold the io_request_lock spin lock when calling the scsi_done routine.
+ *  For now we only do this with the 2.5.1 kernel or newer.
+ */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,1)
+        #define MPT_HOST_LOCK(flags)
+        #define MPT_HOST_UNLOCK(flags)
+#else
+        #define MPT_HOST_LOCK(flags) \
+                spin_lock_irqsave(&io_request_lock, flags)
+        #define MPT_HOST_UNLOCK(flags) \
+                spin_unlock_irqrestore(&io_request_lock, flags)
+#endif
+
+/*
+ *  We use our new error handling code if the kernel version is 2.5.1 or newer.
+ */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,1)
+        #define MPT_SCSI_USE_NEW_EH
+#endif
+
 /*}-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 #endif /* _LINUX_COMPAT_H */
 
index 82166de4a2c4965bed3fb9de1621edc167285479..dc98d46f9071159d0af811f20c05a7127a857fb6 100644 (file)
@@ -7,7 +7,7 @@
  *                  in the IOCLogInfo field of a MPI Default Reply Message.
  *
  *  CREATION DATE:  6/02/2000
- *  ID:             $Id: fc_log.h,v 4.5 2001/06/07 19:18:00 sschremm Exp $
+ *  ID:             $Id: fc_log.h,v 4.6 2001/07/26 14:41:33 sschremm Exp $
  */
 
 
@@ -62,7 +62,7 @@ typedef enum _MpiIocLogInfoFc
     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_FROM_OUTBOUND          = 0x2100000e, /* cleared from the outbound queue 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,
index 9aba9138bbf9513c452b57a234a5eb0ef57bb0fd..a9f24c87fd3c3434fd9a868486cc8cd74c97f275 100644 (file)
@@ -6,7 +6,7 @@
  *          Title:  MPI Message independent structures and definitions
  *  Creation Date:  July 27, 2000
  *
- *    MPI Version:  01.01.07
+ *    MPI Version:  01.02.03
  *
  *  Version History
  *  ---------------
  *                      Added function codes for RAID.
  *  04-09-01  01.01.07  Added alternate define for MPI_DOORBELL_ACTIVE,
  *                      MPI_DOORBELL_USED, to better match the spec.
+ *  08-08-01  01.02.01  Original release for v1.2 work.
+ *                      Changed MPI_VERSION_MINOR from 0x01 to 0x02.
+ *                      Added define MPI_FUNCTION_TOOLBOX.
+ *  09-28-01  01.02.02  New function code MPI_SCSI_ENCLOSURE_PROCESSOR.
+ *  11-01-01  01.02.03  Changed name to MPI_FUNCTION_SCSI_ENCLOSURE_PROCESSOR.
  *  --------------------------------------------------------------------------
  */
 
@@ -53,7 +58,7 @@
 *****************************************************************************/
 
 #define MPI_VERSION_MAJOR                   (0x01)
-#define MPI_VERSION_MINOR                   (0x01)
+#define MPI_VERSION_MINOR                   (0x02)
 #define MPI_VERSION            ((MPI_VERSION_MAJOR << 8) | MPI_VERSION_MINOR)
 
 /* Note: The major versions of 0xe0 through 0xff are reserved */
 #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_ACTION                    (0x15)
 #define MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH       (0x16)
 
+#define MPI_FUNCTION_TOOLBOX                        (0x17)
+
+#define MPI_FUNCTION_SCSI_ENCLOSURE_PROCESSOR       (0x18)
+
 #define MPI_FUNCTION_LAN_SEND                       (0x20)
 #define MPI_FUNCTION_LAN_RECEIVE                    (0x21)
 #define MPI_FUNCTION_LAN_RESET                      (0x22)
index 573cc277b46b4fbc1e24868082e0cd5c0212467a..e7446764fe4c7dbbea76f401b846986fbb9e76c2 100644 (file)
@@ -6,7 +6,7 @@
  *          Title:  MPI Config message, structures, and Pages
  *  Creation Date:  July 27, 2000
  *
- *    MPI Version:  01.01.11
+ *    MPI Version:  01.02.05
  *
  *  Version History
  *  ---------------
  *                      Added IO Unit Page 3.
  *                      Modified defines for Scsi Port Page 2.
  *                      Modified RAID Volume Pages.
+ *  08-08-01  01.02.01  Original release for v1.2 work.
+ *                      Added SepID and SepBus to RVP2 IMPhysicalDisk struct.
+ *                      Added defines for the SEP bits in RVP2 VolumeSettings.
+ *                      Modified the DeviceSettings field in RVP2 to use the
+ *                      proper structure.
+ *                      Added defines for SES, SAF-TE, and cross channel for
+ *                      IOCPage2 CapabilitiesFlags.
+ *                      Removed define for MPI_IOUNITPAGE2_FLAGS_RAID_DISABLE.
+ *                      Removed define for
+ *                      MPI_SCSIPORTPAGE2_PORT_FLAGS_PARITY_ENABLE.
+ *                      Added define for MPI_CONFIG_PAGEATTR_RO_PERSISTENT.
+ *  08-29-01 01.02.02   Fixed value for MPI_MANUFACTPAGE_DEVID_53C1035.
+ *                      Added defines for MPI_FCPORTPAGE1_FLAGS_HARD_ALPA_ONLY
+ *                      and MPI_FCPORTPAGE1_FLAGS_IMMEDIATE_ERROR_REPLY.
+ *                      Removed MPI_SCSIPORTPAGE0_CAP_PACING_TRANSFERS,
+ *                      MPI_SCSIDEVPAGE0_NP_PACING_TRANSFERS, and
+ *                      MPI_SCSIDEVPAGE1_RP_PACING_TRANSFERS, and
+ *                      MPI_SCSIDEVPAGE1_CONF_PPR_ALLOWED.
+ *                      Added defines for MPI_SCSIDEVPAGE1_CONF_WDTR_DISALLOWED
+ *                      and MPI_SCSIDEVPAGE1_CONF_SDTR_DISALLOWED.
+ *                      Added OnBusTimerValue to CONFIG_PAGE_SCSI_PORT_1.
+ *                      Added rejected bits to SCSI Device Page 0 Information.
+ *                      Increased size of ALPA array in FC Port Page 2 by one
+ *                      and removed a one byte reserved field.
+ *  09-28-01 01.02.03   Swapped NegWireSpeedLow and NegWireSpeedLow in
+ *                      CONFIG_PAGE_LAN_1 to match preferred 64-bit ordering.
+ *                      Added structures for Manufacturing Page 4, IO Unit
+ *                      Page 3, IOC Page 3, IOC Page 4, RAID Volume Page 0, and
+ *                      RAID PhysDisk Page 0.
+ *  10-04-01 01.02.04   Added define for MPI_CONFIG_PAGETYPE_RAID_PHYSDISK.
+ *                      Modified some of the new defines to make them 32
+ *                      character unique.
+ *                      Modified how variable length pages (arrays) are defined.
+ *                      Added generic defines for hot spare pools and RAID
+ *                      volume types.
+ *  11-01-01 01.02.05   Added define for MPI_IOUNITPAGE1_DISABLE_IR.
  *  --------------------------------------------------------------------------
  */
 
@@ -104,12 +140,13 @@ typedef union _CONFIG_PAGE_HEADER_UNION
   fCONFIG_PAGE_HEADER_UNION, MPI_POINTER PTR_CONFIG_PAGE_HEADER_UNION;
 
 
-/****************************************************************************/
-/*  PageType field values                                                   */
-/****************************************************************************/
+/****************************************************************************
+*   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_RO_PERSISTENT           (0x30)
 #define MPI_CONFIG_PAGEATTR_MASK                    (0xF0)
 
 #define MPI_CONFIG_PAGETYPE_IO_UNIT                 (0x00)
@@ -122,29 +159,21 @@ typedef union _CONFIG_PAGE_HEADER_UNION
 #define MPI_CONFIG_PAGETYPE_LAN                     (0x07)
 #define MPI_CONFIG_PAGETYPE_RAID_VOLUME             (0x08)
 #define MPI_CONFIG_PAGETYPE_MANUFACTURING           (0x09)
+#define MPI_CONFIG_PAGETYPE_RAID_PHYSDISK           (0x0A)
 #define MPI_CONFIG_PAGETYPE_MASK                    (0x0F)
 
 #define MPI_CONFIG_TYPENUM_MASK                     (0x0FFF)
 
 
 /****************************************************************************
- *  PageAddres field values
- ****************************************************************************/
+*   PageAddress field values
+****************************************************************************/
 #define MPI_SCSI_PORT_PGAD_PORT_MASK                (0x000000FF)
 
-#define MPI_SCSI_DEVICE_FORM_MASK                   (0xF0000000)
-#define MPI_SCSI_DEVICE_FORM_TARGETID               (0x00000000)
-#define MPI_SCSI_DEVICE_FORM_RAID_PHYS_DEV_NUM      (0x10000000)
 #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_DEVICE_VOLUME_TARG_ID_MASK         (0x000000FF)
-#define MPI_SCSI_DEVICE_VOLUME_TARG_ID_SHIFT        (0)
-#define MPI_SCSI_DEVICE_VOLUME_BUS_MASK             (0x0000FF00)
-#define MPI_SCSI_DEVICE_VOLUME_BUS_SHIFT            (8)
-#define MPI_SCSI_DEVICE_PHYS_DISK_NUM_MASK          (0x00FF0000)
-#define MPI_SCSI_DEVICE_PHYS_DISK_NUM_SHIFT         (16)
 
 #define MPI_FC_PORT_PGAD_PORT_MASK                  (0xF0000000)
 #define MPI_FC_PORT_PGAD_PORT_SHIFT                 (28)
@@ -167,10 +196,14 @@ typedef union _CONFIG_PAGE_HEADER_UNION
 #define MPI_FC_DEVICE_PGAD_BT_TID_MASK              (0x000000FF)
 #define MPI_FC_DEVICE_PGAD_BT_TID_SHIFT             (0)
 
+#define MPI_PHYSDISK_PGAD_PHYSDISKNUM_MASK          (0x000000FF)
+#define MPI_PHYSDISK_PGAD_PHYSDISKNUM_SHIFT         (0)
+
+
 
-/****************************************************************************/
-/*  Config Request Message                                                          */
-/****************************************************************************/
+/****************************************************************************
+*   Config Request Message
+****************************************************************************/
 typedef struct _MSG_CONFIG
 {
     U8                      Action;                     /* 00h */
@@ -181,16 +214,16 @@ typedef struct _MSG_CONFIG
     U8                      MsgFlags;                   /* 07h */
     U32                     MsgContext;                 /* 08h */
     U8                      Reserved2[8];               /* 0Ch */
-   fCONFIG_PAGE_HEADER      Header;                     /* 14h */
+    fCONFIG_PAGE_HEADER      Header;                     /* 14h */
     U32                     PageAddress;                /* 18h */
     SGE_IO_UNION            PageBufferSGE;              /* 1Ch */
 } MSG_CONFIG, MPI_POINTER PTR_MSG_CONFIG,
   Config_t, MPI_POINTER pConfig_t;
 
 
-/****************************************************************************/
-/*  Action field values                                                     */
-/****************************************************************************/
+/****************************************************************************
+*   Action field values
+****************************************************************************/
 #define MPI_CONFIG_ACTION_PAGE_HEADER               (0x00)
 #define MPI_CONFIG_ACTION_PAGE_READ_CURRENT         (0x01)
 #define MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT        (0x02)
@@ -213,7 +246,7 @@ typedef struct _MSG_CONFIG_REPLY
     U8                      Reserved2[2];               /* 0Ch */
     U16                     IOCStatus;                  /* 0Eh */
     U32                     IOCLogInfo;                 /* 10h */
-   fCONFIG_PAGE_HEADER      Header;                     /* 14h */
+    fCONFIG_PAGE_HEADER      Header;                     /* 14h */
 } MSG_CONFIG_REPLY, MPI_POINTER PTR_MSG_CONFIG_REPLY,
   ConfigReply_t, MPI_POINTER pConfigReply_t;
 
@@ -225,19 +258,24 @@ typedef struct _MSG_CONFIG_REPLY
 *
 *****************************************************************************/
 
-/****************************************************************************/
-/*  Manufacturing Config pages                                              */
-/****************************************************************************/
+/****************************************************************************
+*   Manufacturing Config pages
+****************************************************************************/
 #define MPI_MANUFACTPAGE_DEVICEID_FC909             (0x0621)
 #define MPI_MANUFACTPAGE_DEVICEID_FC919             (0x0624)
 #define MPI_MANUFACTPAGE_DEVICEID_FC929             (0x0622)
+#define MPI_MANUFACTPAGE_DEVICEID_FC919X            (0x0628)
+#define MPI_MANUFACTPAGE_DEVICEID_FC929X            (0x0626)
 #define MPI_MANUFACTPAGE_DEVID_53C1030              (0x0030)
 #define MPI_MANUFACTPAGE_DEVID_53C1030ZC            (0x0031)
-#define MPI_MANUFACTPAGE_DEVID_53C1035              (0x0035)
+#define MPI_MANUFACTPAGE_DEVID_1030_53C1035         (0x0032)
+#define MPI_MANUFACTPAGE_DEVID_1030ZC_53C1035       (0x0033)
+#define MPI_MANUFACTPAGE_DEVID_53C1035              (0x0040)
+#define MPI_MANUFACTPAGE_DEVID_53C1035ZC            (0x0041)
 
 typedef struct _CONFIG_PAGE_MANUFACTURING_0
 {
-   fCONFIG_PAGE_HEADER      Header;                     /* 00h */
+    fCONFIG_PAGE_HEADER      Header;                     /* 00h */
     U8                      ChipName[16];               /* 04h */
     U8                      ChipRevision[8];            /* 14h */
     U8                      BoardName[16];              /* 1Ch */
@@ -252,7 +290,7 @@ typedef struct _CONFIG_PAGE_MANUFACTURING_0
 
 typedef struct _CONFIG_PAGE_MANUFACTURING_1
 {
-   fCONFIG_PAGE_HEADER      Header;                     /* 00h */
+    fCONFIG_PAGE_HEADER      Header;                     /* 00h */
     U8                      VPD[256];                   /* 04h */
 } fCONFIG_PAGE_MANUFACTURING_1, MPI_POINTER PTR_CONFIG_PAGE_MANUFACTURING_1,
   ManufacturingPage1_t, MPI_POINTER pManufacturingPage1_t;
@@ -269,35 +307,72 @@ typedef struct _MPI_CHIP_REVISION_ID
   MpiChipRevisionId_t, MPI_POINTER pMpiChipRevisionId_t;
 
 
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check Header.PageLength at runtime.
+ */
+#ifndef MPI_MAN_PAGE_2_HW_SETTINGS_WORDS
+#define MPI_MAN_PAGE_2_HW_SETTINGS_WORDS    (1)
+#endif
+
 typedef struct _CONFIG_PAGE_MANUFACTURING_2
 {
-   fCONFIG_PAGE_HEADER                  Header;         /* 00h */
-    MPI_CHIP_REVISION_ID                ChipId;         /* 04h */
-    U32                                 HwSettings[1];  /* 08h */
+    fCONFIG_PAGE_HEADER      Header;                                 /* 00h */
+    MPI_CHIP_REVISION_ID    ChipId;                                 /* 04h */
+    U32                     HwSettings[MPI_MAN_PAGE_2_HW_SETTINGS_WORDS];/* 08h */
 } fCONFIG_PAGE_MANUFACTURING_2, MPI_POINTER PTR_CONFIG_PAGE_MANUFACTURING_2,
   ManufacturingPage2_t, MPI_POINTER pManufacturingPage2_t;
 
 #define MPI_MANUFACTURING2_PAGEVERSION                  (0x00)
 
 
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check Header.PageLength at runtime.
+ */
+#ifndef MPI_MAN_PAGE_3_INFO_WORDS
+#define MPI_MAN_PAGE_3_INFO_WORDS           (1)
+#endif
+
 typedef struct _CONFIG_PAGE_MANUFACTURING_3
 {
-   fCONFIG_PAGE_HEADER                  Header;         /* 00h */
-    MPI_CHIP_REVISION_ID                ChipId;         /* 04h */
-    U32                                 Info[1];        /* 08h */
+    fCONFIG_PAGE_HEADER                  Header;                     /* 00h */
+    MPI_CHIP_REVISION_ID                ChipId;                     /* 04h */
+    U32                                 Info[MPI_MAN_PAGE_3_INFO_WORDS];/* 08h */
 } 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_MANUFACTURING_4
+{
+    fCONFIG_PAGE_HEADER              Header;             /* 00h */
+    U32                             Reserved1;          /* 04h */
+    U8                              InfoOffset0;        /* 08h */
+    U8                              InfoSize0;          /* 09h */
+    U8                              InfoOffset1;        /* 0Ah */
+    U8                              InfoSize1;          /* 0Bh */
+    U8                              InquirySize;        /* 0Ch */
+    U8                              Reserved2;          /* 0Dh */
+    U16                             Reserved3;          /* 0Eh */
+    U8                              InquiryData[56];    /* 10h */
+    U32                             ISVolumeSettings;   /* 48h */
+    U32                             IMEVolumeSettings;  /* 4Ch */
+    U32                             IMVolumeSettings;   /* 50h */
+} fCONFIG_PAGE_MANUFACTURING_4, MPI_POINTER PTR_CONFIG_PAGE_MANUFACTURING_4,
+  ManufacturingPage4_t, MPI_POINTER pManufacturingPage4_t;
+
+#define MPI_MANUFACTURING4_PAGEVERSION                  (0x00)
+
+
+/****************************************************************************
+*   IO Unit Config Pages
+****************************************************************************/
 
 typedef struct _CONFIG_PAGE_IO_UNIT_0
 {
-   fCONFIG_PAGE_HEADER      Header;                     /* 00h */
+    fCONFIG_PAGE_HEADER      Header;                     /* 00h */
     U64                     UniqueValue;                /* 04h */
 } fCONFIG_PAGE_IO_UNIT_0, MPI_POINTER PTR_CONFIG_PAGE_IO_UNIT_0,
   IOUnitPage0_t, MPI_POINTER pIOUnitPage0_t;
@@ -307,18 +382,20 @@ typedef struct _CONFIG_PAGE_IO_UNIT_0
 
 typedef struct _CONFIG_PAGE_IO_UNIT_1
 {
-   fCONFIG_PAGE_HEADER      Header;                     /* 00h */
+    fCONFIG_PAGE_HEADER      Header;                     /* 00h */
     U32                     Flags;                      /* 04h */
 } fCONFIG_PAGE_IO_UNIT_1, MPI_POINTER PTR_CONFIG_PAGE_IO_UNIT_1,
   IOUnitPage1_t, MPI_POINTER pIOUnitPage1_t;
 
 #define MPI_IOUNITPAGE1_PAGEVERSION                     (0x00)
 
+/* IO Unit Page 1 Flags defines */
+
 #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_DISABLE_IR                      (0x00000040)
 #define MPI_IOUNITPAGE1_FORCE_32                        (0x00000080)
 
 
@@ -335,7 +412,7 @@ typedef struct _MPI_ADAPTER_INFO
 
 typedef struct _CONFIG_PAGE_IO_UNIT_2
 {
-   fCONFIG_PAGE_HEADER      Header;                     /* 00h */
+    fCONFIG_PAGE_HEADER      Header;                     /* 00h */
     U32                     Flags;                      /* 04h */
     U32                     BiosVersion;                /* 08h */
     MPI_ADAPTER_INFO        AdapterOrder[4];            /* 0Ch */
@@ -344,38 +421,45 @@ typedef struct _CONFIG_PAGE_IO_UNIT_2
 
 #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)
 
 
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check Header.PageLength at runtime.
+ */
+#ifndef MPI_IO_UNIT_PAGE_3_GPIO_VAL_MAX
+#define MPI_IO_UNIT_PAGE_3_GPIO_VAL_MAX     (1)
+#endif
+
 typedef struct _CONFIG_PAGE_IO_UNIT_3
 {
-   fCONFIG_PAGE_HEADER      Header;                     /* 00h */
-    U32                     VolumeSettings;             /* 04h */
-    U8                      InfoOffset0;                /* 08h */
-    U8                      InfoSize0;                  /* 09h */
-    U8                      InfoOffset1;                /* 0Ah */
-    U8                      InfoSize1;                  /* 0Bh */
-    U8                      InquirySize;                /* 0Ch */
-    U8                      Reserved;                   /* 0Dh */
-    U16                     Reserved2;                  /* 0Eh */
-    U8                      InquiryData[56];            /* 10h */
+    fCONFIG_PAGE_HEADER      Header;                                   /* 00h */
+    U8                      GPIOCount;                                /* 04h */
+    U8                      Reserved1;                                /* 05h */
+    U16                     Reserved2;                                /* 06h */
+    U16                     GPIOVal[MPI_IO_UNIT_PAGE_3_GPIO_VAL_MAX]; /* 08h */
 } fCONFIG_PAGE_IO_UNIT_3, MPI_POINTER PTR_CONFIG_PAGE_IO_UNIT_3,
   IOUnitPage3_t, MPI_POINTER pIOUnitPage3_t;
 
-#define MPI_IOUNITPAGE3_PAGEVERSION                     (0x00)
+#define MPI_IOUNITPAGE3_PAGEVERSION                     (0x01)
 
+#define MPI_IOUNITPAGE3_GPIO_FUNCTION_MASK              (0xFC)
+#define MPI_IOUNITPAGE3_GPIO_FUNCTION_SHIFT             (2)
+#define MPI_IOUNITPAGE3_GPIO_SETTING_OFF                (0x00)
+#define MPI_IOUNITPAGE3_GPIO_SETTING_ON                 (0x01)
 
-/****************************************************************************/
-/*  IOC Config Pages                                                        */
-/****************************************************************************/
+
+/****************************************************************************
+*   IOC Config Pages
+****************************************************************************/
 
 typedef struct _CONFIG_PAGE_IOC_0
 {
-   fCONFIG_PAGE_HEADER      Header;                     /* 00h */
+    fCONFIG_PAGE_HEADER      Header;                     /* 00h */
     U32                     TotalNVStore;               /* 04h */
     U32                     FreeNVStore;                /* 08h */
     U16                     VendorID;                   /* 0Ch */
@@ -393,7 +477,7 @@ typedef struct _CONFIG_PAGE_IOC_0
 
 typedef struct _CONFIG_PAGE_IOC_1
 {
-   fCONFIG_PAGE_HEADER      Header;                     /* 00h */
+    fCONFIG_PAGE_HEADER      Header;                     /* 00h */
     U32                     Flags;                      /* 04h */
     U32                     CoalescingTimeout;          /* 08h */
     U8                      CoalescingDepth;            /* 0Ch */
@@ -408,53 +492,120 @@ typedef struct _CONFIG_PAGE_IOC_1
 
 typedef struct _CONFIG_PAGE_IOC_2_RAID_VOL
 {
-    U8                      VolumeTargetID;             /* 00h */
-    U8                      VolumeBus;                  /* 01h */
-    U16                     Reserved;                   /* 02h */
-    U8                      VolumeVersionMinor;         /* 04h */
-    U8                      VolumeVersionMajor;         /* 05h */
-    U8                      VolumeRaidType;             /* 06h */
-    U8                      Reserved1;                  /* 07h */
+    U8                          VolumeID;               /* 00h */
+    U8                          VolumeBus;              /* 01h */
+    U8                          VolumeIOC;              /* 02h */
+    U8                          VolumePageNumber;       /* 03h */
+    U8                          VolumeType;             /* 04h */
+    U8                          Reserved2;              /* 05h */
+    U16                         Reserved3;              /* 06h */
 } fCONFIG_PAGE_IOC_2_RAID_VOL, MPI_POINTER PTR_CONFIG_PAGE_IOC_2_RAID_VOL,
   ConfigPageIoc2RaidVol_t, MPI_POINTER pConfigPageIoc2RaidVol_t;
 
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check Header.PageLength at runtime.
+ */
+#ifndef MPI_IOC_PAGE_2_RAID_VOLUME_MAX
+#define MPI_IOC_PAGE_2_RAID_VOLUME_MAX      (1)
+#endif
+
 typedef struct _CONFIG_PAGE_IOC_2
 {
-   fCONFIG_PAGE_HEADER          Header;                 /* 00h */
-    U32                         CapabilitiesFlags;      /* 04h */
-    U8                          NumActiveVolumes;       /* 08h */
-    U8                          MaxVolumes;             /* 09h */
-    U16                         Reserved;               /* 0Ah */
-   fCONFIG_PAGE_IOC_2_RAID_VOL  RaidVolume[1];          /* 0Ch */
+    fCONFIG_PAGE_HEADER          Header;                              /* 00h */
+    U32                         CapabilitiesFlags;                   /* 04h */
+    U8                          NumActiveVolumes;                    /* 08h */
+    U8                          MaxVolumes;                          /* 09h */
+    U8                          NumActivePhysDisks;                  /* 0Ah */
+    U8                          MaxPhysDisks;                        /* 0Bh */
+    fCONFIG_PAGE_IOC_2_RAID_VOL  RaidVolume[MPI_IOC_PAGE_2_RAID_VOLUME_MAX];/* 0Ch */
 } fCONFIG_PAGE_IOC_2, MPI_POINTER PTR_CONFIG_PAGE_IOC_2,
   IOCPage2_t, MPI_POINTER pIOCPage2_t;
 
-#define MPI_IOCPAGE2_PAGEVERSION                        (0x00)
+#define MPI_IOCPAGE2_PAGEVERSION                        (0x01)
 
 /* 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)
+#define MPI_IOCPAGE2_CAP_FLAGS_IS_SUPPORT               (0x00000001)
+#define MPI_IOCPAGE2_CAP_FLAGS_IME_SUPPORT              (0x00000002)
+#define MPI_IOCPAGE2_CAP_FLAGS_IM_SUPPORT               (0x00000004)
+#define MPI_IOCPAGE2_CAP_FLAGS_SES_SUPPORT              (0x20000000)
+#define MPI_IOCPAGE2_CAP_FLAGS_SAFTE_SUPPORT            (0x40000000)
+#define MPI_IOCPAGE2_CAP_FLAGS_CROSS_CHANNEL_SUPPORT    (0x80000000)
+
+/* IOC Page 2 Volume RAID Type values, also used in RAID Volume pages */
+
+#define MPI_RAID_VOL_TYPE_IS                        (0x00)
+#define MPI_RAID_VOL_TYPE_IME                       (0x01)
+#define MPI_RAID_VOL_TYPE_IM                        (0x02)
+
+
+typedef struct _IOC_3_PHYS_DISK
+{
+    U8                          PhysDiskID;             /* 00h */
+    U8                          PhysDiskBus;            /* 01h */
+    U8                          PhysDiskIOC;            /* 02h */
+    U8                          PhysDiskNum;            /* 03h */
+} IOC_3_PHYS_DISK, MPI_POINTER PTR_IOC_3_PHYS_DISK,
+  Ioc3PhysDisk_t, MPI_POINTER pIoc3PhysDisk_t;
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check Header.PageLength at runtime.
+ */
+#ifndef MPI_IOC_PAGE_3_PHYSDISK_MAX
+#define MPI_IOC_PAGE_3_PHYSDISK_MAX         (1)
+#endif
+
+typedef struct _CONFIG_PAGE_IOC_3
+{
+    fCONFIG_PAGE_HEADER          Header;                                /* 00h */
+    U8                          NumPhysDisks;                          /* 04h */
+    U8                          Reserved1;                             /* 05h */
+    U16                         Reserved2;                             /* 06h */
+    IOC_3_PHYS_DISK             PhysDisk[MPI_IOC_PAGE_3_PHYSDISK_MAX]; /* 08h */
+} fCONFIG_PAGE_IOC_3, MPI_POINTER PTR_CONFIG_PAGE_IOC_3,
+  IOCPage3_t, MPI_POINTER pIOCPage3_t;
+
+#define MPI_IOCPAGE3_PAGEVERSION                        (0x00)
 
-/* 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)
+typedef struct _IOC_4_SEP
+{
+    U8                          SEPTargetID;            /* 00h */
+    U8                          SEPBus;                 /* 01h */
+    U16                         Reserved;               /* 02h */
+} IOC_4_SEP, MPI_POINTER PTR_IOC_4_SEP,
+  Ioc4Sep_t, MPI_POINTER pIoc4Sep_t;
 
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check Header.PageLength at runtime.
+ */
+#ifndef MPI_IOC_PAGE_4_SEP_MAX
+#define MPI_IOC_PAGE_4_SEP_MAX              (1)
+#endif
 
-/****************************************************************************/
-/*  SCSI Port Config Pages                                                  */
-/****************************************************************************/
+typedef struct _CONFIG_PAGE_IOC_4
+{
+    fCONFIG_PAGE_HEADER          Header;                         /* 00h */
+    U8                          ActiveSEP;                      /* 04h */
+    U8                          MaxSEP;                         /* 05h */
+    U16                         Reserved1;                      /* 06h */
+    IOC_4_SEP                   SEP[MPI_IOC_PAGE_4_SEP_MAX];    /* 08h */
+} fCONFIG_PAGE_IOC_4, MPI_POINTER PTR_CONFIG_PAGE_IOC_4,
+  IOCPage4_t, MPI_POINTER pIOCPage4_t;
+
+#define MPI_IOCPAGE4_PAGEVERSION                        (0x00)
+
+
+/****************************************************************************
+*   SCSI Port Config Pages
+****************************************************************************/
 
 typedef struct _CONFIG_PAGE_SCSI_PORT_0
 {
-   fCONFIG_PAGE_HEADER      Header;                     /* 00h */
+    fCONFIG_PAGE_HEADER      Header;                     /* 00h */
     U32                     Capabilities;               /* 04h */
     U32                     PhysicalInterface;          /* 08h */
 } fCONFIG_PAGE_SCSI_PORT_0, MPI_POINTER PTR_CONFIG_PAGE_SCSI_PORT_0,
@@ -465,7 +616,6 @@ typedef struct _CONFIG_PAGE_SCSI_PORT_0
 #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)
@@ -479,12 +629,13 @@ typedef struct _CONFIG_PAGE_SCSI_PORT_0
 
 typedef struct _CONFIG_PAGE_SCSI_PORT_1
 {
-   fCONFIG_PAGE_HEADER      Header;                     /* 00h */
+    fCONFIG_PAGE_HEADER      Header;                     /* 00h */
     U32                     Configuration;              /* 04h */
+    U32                     OnBusTimerValue;            /* 08h */
 } 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_PAGEVERSION                   (0x02)
 
 #define MPI_SCSIPORTPAGE1_CFG_PORT_SCSI_ID_MASK         (0x000000FF)
 #define MPI_SCSIPORTPAGE1_CFG_PORT_RESPONSE_ID_MASK     (0xFFFF0000)
@@ -500,7 +651,7 @@ typedef struct _MPI_DEVICE_INFO
 
 typedef struct _CONFIG_PAGE_SCSI_PORT_2
 {
-   fCONFIG_PAGE_HEADER  Header;                         /* 00h */
+    fCONFIG_PAGE_HEADER  Header;                         /* 00h */
     U32                 PortFlags;                      /* 04h */
     U32                 PortSettings;                   /* 08h */
     MPI_DEVICE_INFO     DeviceSettings[16];             /* 0Ch */
@@ -510,7 +661,6 @@ typedef struct _CONFIG_PAGE_SCSI_PORT_2
 #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)
@@ -536,47 +686,48 @@ typedef struct _CONFIG_PAGE_SCSI_PORT_2
 #define MPI_SCSIPORTPAGE2_DEVICE_BOOT_CHOICE                (0x0020)
 
 
-/****************************************************************************/
-/*  SCSI Target Device Config Pages                                         */
-/****************************************************************************/
+/****************************************************************************
+*   SCSI Target Device Config Pages
+****************************************************************************/
 
 typedef struct _CONFIG_PAGE_SCSI_DEVICE_0
 {
-   fCONFIG_PAGE_HEADER      Header;                     /* 00h */
+    fCONFIG_PAGE_HEADER      Header;                     /* 00h */
     U32                     NegotiatedParameters;       /* 04h */
     U32                     Information;                /* 08h */
 } 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_PAGEVERSION                    (0x02)
 
 #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)
+#define MPI_SCSIDEVPAGE0_INFO_SDTR_REJECTED             (0x00000002)
+#define MPI_SCSIDEVPAGE0_INFO_WDTR_REJECTED             (0x00000004)
+#define MPI_SCSIDEVPAGE0_INFO_PPR_REJECTED              (0x00000008)
 
 
 typedef struct _CONFIG_PAGE_SCSI_DEVICE_1
 {
-   fCONFIG_PAGE_HEADER      Header;                     /* 00h */
+    fCONFIG_PAGE_HEADER      Header;                     /* 00h */
     U32                     RequestedParameters;        /* 04h */
     U32                     Reserved;                   /* 08h */
     U32                     Configuration;              /* 0Ch */
 } fCONFIG_PAGE_SCSI_DEVICE_1, MPI_POINTER PTR_CONFIG_PAGE_SCSI_DEVICE_1,
   SCSIDevicePage1_t, MPI_POINTER pSCSIDevicePage1_t;
 
-#define MPI_SCSIDEVPAGE1_PAGEVERSION                    (0x02)
+#define MPI_SCSIDEVPAGE1_PAGEVERSION                    (0x03)
 
 #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)
@@ -585,12 +736,13 @@ typedef struct _CONFIG_PAGE_SCSI_DEVICE_1
 #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)
+#define MPI_SCSIDEVPAGE1_CONF_WDTR_DISALLOWED           (0x00000002)
+#define MPI_SCSIDEVPAGE1_CONF_SDTR_DISALLOWED           (0x00000004)
 
 
 typedef struct _CONFIG_PAGE_SCSI_DEVICE_2
 {
-   fCONFIG_PAGE_HEADER      Header;                     /* 00h */
+    fCONFIG_PAGE_HEADER      Header;                     /* 00h */
     U32                     DomainValidation;           /* 04h */
     U32                     ParityPipeSelect;           /* 08h */
     U32                     DataPipeSelect;             /* 0Ch */
@@ -629,13 +781,13 @@ typedef struct _CONFIG_PAGE_SCSI_DEVICE_2
 #define MPI_SCSIDEVPAGE2_DPS_BIT_15_PL_SELECT_MASK      (0xC0000000)
 
 
-/****************************************************************************/
-/*  FC Port Config Pages                                                    */
-/****************************************************************************/
+/****************************************************************************
+*   FC Port Config Pages
+****************************************************************************/
 
 typedef struct _CONFIG_PAGE_FC_PORT_0
 {
-   fCONFIG_PAGE_HEADER      Header;                     /* 00h */
+    fCONFIG_PAGE_HEADER      Header;                     /* 00h */
     U32                     Flags;                      /* 04h */
     U8                      MPIPortNumber;              /* 08h */
     U8                      LinkType;                   /* 09h */
@@ -715,7 +867,7 @@ typedef struct _CONFIG_PAGE_FC_PORT_0
 
 typedef struct _CONFIG_PAGE_FC_PORT_1
 {
-   fCONFIG_PAGE_HEADER      Header;                     /* 00h */
+    fCONFIG_PAGE_HEADER      Header;                     /* 00h */
     U32                     Flags;                      /* 04h */
     U64                     NoSEEPROMWWNN;              /* 08h */
     U64                     NoSEEPROMWWPN;              /* 10h */
@@ -726,8 +878,10 @@ typedef struct _CONFIG_PAGE_FC_PORT_1
 } 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_PAGEVERSION                     (0x02)
 
+#define MPI_FCPORTPAGE1_FLAGS_EXT_FCP_STATUS_EN         (0x08000000)
+#define MPI_FCPORTPAGE1_FLAGS_IMMEDIATE_ERROR_REPLY     (0x04000000)
 #define MPI_FCPORTPAGE1_FLAGS_SORT_BY_DID               (0x00000001)
 #define MPI_FCPORTPAGE1_FLAGS_SORT_BY_WWN               (0x00000000)
 
@@ -747,22 +901,21 @@ typedef struct _CONFIG_PAGE_FC_PORT_1
 #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)
+#define MPI_FCPORTPAGE1_TOPOLOGY_MASK                   (0x0F)
+#define MPI_FCPORTPAGE1_TOPOLOGY_NLPORT                 (0x01)
+#define MPI_FCPORTPAGE1_TOPOLOGY_NPORT                  (0x02)
+#define MPI_FCPORTPAGE1_TOPOLOGY_AUTO                   (0x0F)
 
 
 typedef struct _CONFIG_PAGE_FC_PORT_2
 {
-   fCONFIG_PAGE_HEADER      Header;                     /* 00h */
+    fCONFIG_PAGE_HEADER      Header;                     /* 00h */
     U8                      NumberActive;               /* 04h */
-    U8                      ALPA[126];                  /* 05h */
-    U8                      Reserved;                   /* 83h */
+    U8                      ALPA[127];                  /* 05h */
 } fCONFIG_PAGE_FC_PORT_2, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_2,
   FCPortPage2_t, MPI_POINTER pFCPortPage2_t;
 
-#define MPI_FCPORTPAGE2_PAGEVERSION                     (0x00)
+#define MPI_FCPORTPAGE2_PAGEVERSION                     (0x01)
 
 
 typedef struct _WWN_FORMAT
@@ -795,10 +948,18 @@ typedef struct _FC_PORT_PERSISTENT
 #define MPI_PERSISTENT_FLAGS_BOOT_DEVICE                (0x0008)
 #define MPI_PERSISTENT_FLAGS_BY_DID                     (0x0080)
 
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check Header.PageLength at runtime.
+ */
+#ifndef MPI_FC_PORT_PAGE_3_ENTRY_MAX
+#define MPI_FC_PORT_PAGE_3_ENTRY_MAX        (1)
+#endif
+
 typedef struct _CONFIG_PAGE_FC_PORT_3
 {
-   fCONFIG_PAGE_HEADER      Header;                     /* 00h */
-    FC_PORT_PERSISTENT      Entry[1];                   /* 04h */
+    fCONFIG_PAGE_HEADER      Header;                                 /* 00h */
+    FC_PORT_PERSISTENT      Entry[MPI_FC_PORT_PAGE_3_ENTRY_MAX];    /* 04h */
 } fCONFIG_PAGE_FC_PORT_3, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_3,
   FCPortPage3_t, MPI_POINTER pFCPortPage3_t;
 
@@ -807,7 +968,7 @@ typedef struct _CONFIG_PAGE_FC_PORT_3
 
 typedef struct _CONFIG_PAGE_FC_PORT_4
 {
-   fCONFIG_PAGE_HEADER      Header;                     /* 00h */
+    fCONFIG_PAGE_HEADER      Header;                     /* 00h */
     U32                     PortFlags;                  /* 04h */
     U32                     PortSettings;               /* 08h */
 } fCONFIG_PAGE_FC_PORT_4, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_4,
@@ -833,13 +994,22 @@ typedef struct _CONFIG_PAGE_FC_PORT_5_ALIAS_INFO
     U16     Reserved;                                   /* 02h */
     U64     AliasWWNN;                                  /* 04h */
     U64     AliasWWPN;                                  /* 0Ch */
-} fCONFIG_PAGE_FC_PORT_5_ALIAS_INFO, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_5_ALIAS_INFO,
+} fCONFIG_PAGE_FC_PORT_5_ALIAS_INFO,
+  MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_5_ALIAS_INFO,
   FcPortPage5AliasInfo_t, MPI_POINTER pFcPortPage5AliasInfo_t;
 
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check Header.PageLength at runtime.
+ */
+#ifndef MPI_FC_PORT_PAGE_5_ALIAS_MAX
+#define MPI_FC_PORT_PAGE_5_ALIAS_MAX        (1)
+#endif
+
 typedef struct _CONFIG_PAGE_FC_PORT_5
 {
-   fCONFIG_PAGE_HEADER                  Header;         /* 00h */
-   fCONFIG_PAGE_FC_PORT_5_ALIAS_INFO    AliasInfo[1];   /* 04h */
+    fCONFIG_PAGE_HEADER                  Header;                     /* 00h */
+    fCONFIG_PAGE_FC_PORT_5_ALIAS_INFO    AliasInfo[MPI_FC_PORT_PAGE_5_ALIAS_MAX];/* 04h */
 } fCONFIG_PAGE_FC_PORT_5, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_5,
   FCPortPage5_t, MPI_POINTER pFCPortPage5_t;
 
@@ -851,7 +1021,7 @@ typedef struct _CONFIG_PAGE_FC_PORT_5
 
 typedef struct _CONFIG_PAGE_FC_PORT_6
 {
-   fCONFIG_PAGE_HEADER      Header;                     /* 00h */
+    fCONFIG_PAGE_HEADER      Header;                     /* 00h */
     U32                     Reserved;                   /* 04h */
     U64                     TimeSinceReset;             /* 08h */
     U64                     TxFrames;                   /* 10h */
@@ -877,7 +1047,7 @@ typedef struct _CONFIG_PAGE_FC_PORT_6
 
 typedef struct _CONFIG_PAGE_FC_PORT_7
 {
-   fCONFIG_PAGE_HEADER      Header;                     /* 00h */
+    fCONFIG_PAGE_HEADER      Header;                     /* 00h */
     U32                     Reserved;                   /* 04h */
     U8                      PortSymbolicName[256];      /* 08h */
 } fCONFIG_PAGE_FC_PORT_7, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_7,
@@ -888,7 +1058,7 @@ typedef struct _CONFIG_PAGE_FC_PORT_7
 
 typedef struct _CONFIG_PAGE_FC_PORT_8
 {
-   fCONFIG_PAGE_HEADER      Header;                     /* 00h */
+    fCONFIG_PAGE_HEADER      Header;                     /* 00h */
     U32                     BitVector[8];               /* 04h */
 } fCONFIG_PAGE_FC_PORT_8, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_8,
   FCPortPage8_t, MPI_POINTER pFCPortPage8_t;
@@ -898,7 +1068,7 @@ typedef struct _CONFIG_PAGE_FC_PORT_8
 
 typedef struct _CONFIG_PAGE_FC_PORT_9
 {
-   fCONFIG_PAGE_HEADER      Header;                     /* 00h */
+    fCONFIG_PAGE_HEADER      Header;                     /* 00h */
     U32                     Reserved;                   /* 04h */
     U64                     GlobalWWPN;                 /* 08h */
     U64                     GlobalWWNN;                 /* 10h */
@@ -916,13 +1086,13 @@ typedef struct _CONFIG_PAGE_FC_PORT_9
 #define MPI_FCPORTPAGE9_PAGEVERSION                     (0x00)
 
 
-/****************************************************************************/
-/*  FC Device Config Pages                                                  */
-/****************************************************************************/
+/****************************************************************************
+*   FC Device Config Pages
+****************************************************************************/
 
 typedef struct _CONFIG_PAGE_FC_DEVICE_0
 {
-   fCONFIG_PAGE_HEADER      Header;                     /* 00h */
+    fCONFIG_PAGE_HEADER      Header;                     /* 00h */
     U64                     WWNN;                       /* 04h */
     U64                     WWPN;                       /* 0Ch */
     U32                     PortIdentifier;             /* 14h */
@@ -947,112 +1117,191 @@ typedef struct _CONFIG_PAGE_FC_DEVICE_0
 #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)
+#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                                                  */
-/****************************************************************************/
+/****************************************************************************
+*   RAID Volume Config Pages
+****************************************************************************/
 
-typedef struct _RAIDVOL2_IM_PHYS_ID
+typedef struct _RAID_VOL0_PHYS_DISK
 {
-    U8                      TargetID;                   /* 00h */
-    U8                      Bus;                        /* 01h */
-    U8                      IocNumber;                  /* 02h */
-    U8                      PhysDiskNumber;             /* 03h */
-    U8                      Reserved[8];                /* 04h */
-    U8                      PhysicalDiskIdentifier[16]; /* 0Ch */
-    U8                      VendorId[8];                /* 1Ch */
-    U8                      ProductId[16];              /* 24h */
-    U8                      ProductRevLevel[4];         /* 34h */
-    U32                     Reserved1;                  /* 38h */
-    U8                      Info[32];                   /* 3Ch */
-} RAIDVOL2_IM_PHYS_ID, MPI_POINTER PTR_RAIDVOL2_IM_PHYS_ID,
-  RaidVol2ImPhysicalID_t, MPI_POINTER pRaidVol2ImPhysicalID_t;
-
-typedef struct _RAIDVOL2_IM_DISK_INFO
+    U16                         Reserved;               /* 00h */
+    U8                          PhysDiskMap;            /* 02h */
+    U8                          PhysDiskNum;            /* 03h */
+} RAID_VOL0_PHYS_DISK, MPI_POINTER PTR_RAID_VOL0_PHYS_DISK,
+  RaidVol0PhysDisk_t, MPI_POINTER pRaidVol0PhysDisk_t;
+
+#define MPI_RAIDVOL0_PHYSDISK_PRIMARY                   (0x01)
+#define MPI_RAIDVOL0_PHYSDISK_SECONDARY                 (0x02)
+
+typedef struct _RAID_VOL0_STATUS
 {
-    U32                     DiskStatus;                 /* 00h */
-    U32                     DeviceSettings;             /* 04h */
-    U16                     ErrorCount;                 /* 08h */
-    U16                     Reserved;                   /* 0Ah */
-    U8                      ErrorCdbByte;               /* 0Ch */
-    U8                      ErrorSenseKey;              /* 0Dh */
-    U8                      ErrorASC;                   /* 0Eh */
-    U8                      ErrorASCQ;                  /* 0Fh */
-    U16                     SmartCount;                 /* 10h */
-    U8                      SmartASC;                   /* 12h */
-    U8                      SmartASCQ;                  /* 13h */
-} RAIDVOL2_IM_DISK_INFO, MPI_POINTER PTR_RAIDVOL2_IM_DISK_INFO,
-  RaidVol2ImDiskInfo_t, MPI_POINTER pRaidVol2ImDiskInfo_t;
+    U8                          Flags;                  /* 00h */
+    U8                          State;                  /* 01h */
+    U16                         Reserved;               /* 02h */
+} RAID_VOL0_STATUS, MPI_POINTER PTR_RAID_VOL0_STATUS,
+  RaidVol0Status_t, MPI_POINTER pRaidVol0Status_t;
 
-/* RAID Volume 2 IM Physical Disk DiskStatus flags */
+/* RAID Volume Page 0 VolumeStatus defines */
+
+#define MPI_RAIDVOL0_STATUS_FLAG_ENABLED                (0x01)
+#define MPI_RAIDVOL0_STATUS_FLAG_QUIESCED               (0x02)
+#define MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS     (0x04)
 
-#define MPI_RVP2_PHYS_DISK_PRIMARY                      (0x00000001)
-#define MPI_RVP2_PHYS_DISK_SECONDARY                    (0x00000002)
-#define MPI_RVP2_PHYS_DISK_HOT_SPARE                    (0x00000004)
-#define MPI_RVP2_PHYS_DISK_OUT_OF_SYNC                  (0x00000008)
-#define MPI_RVP2_PHYS_DISK_STATUS_MASK                  (0x00000F00)
-#define MPI_RVP2_PHYS_DISK_STATUS_ONLINE                (0x00000000)
-#define MPI_RVP2_PHYS_DISK_STATUS_MISSING               (0x00000100)
-#define MPI_RVP2_PHYS_DISK_STATUS_NOT_COMPATIBLE        (0x00000200)
-#define MPI_RVP2_PHYS_DISK_STATUS_FAILED                (0x00000300)
-#define MPI_RVP2_PHYS_DISK_STATUS_INITIALIZING          (0x00000400)
-#define MPI_RVP2_PHYS_DISK_STATUS_OFFLINE_REQUESTED     (0x00000500)
-#define MPI_RVP2_PHYS_DISK_STATUS_OTHER_OFFLINE         (0x00000F00)
-
-
-typedef struct _RAIDVOL2_IM_PHYSICAL_DISK
+#define MPI_RAIDVOL0_STATUS_STATE_OPTIMAL               (0x00)
+#define MPI_RAIDVOL0_STATUS_STATE_DEGRADED              (0x01)
+#define MPI_RAIDVOL0_STATUS_STATE_FAILED                (0x02)
+
+typedef struct _RAID_VOL0_SETTINGS
 {
-    RAIDVOL2_IM_PHYS_ID     Id;                         /* 00h */
-    RAIDVOL2_IM_DISK_INFO   Info;                       /* 5Ch */
-} RAIDVOL2_IM_PHYSICAL_DISK, MPI_POINTER PTR_RAIDVOL2_IM_PHYSICAL_DISK,
-  RaidVol2ImPhysicalDisk_t, MPI_POINTER pRaidVol2ImPhysicalDisk_t;
+    U16                         Settings;       /* 00h */
+    U8                          HotSparePool;   /* 01h */ /* MPI_RAID_HOT_SPARE_POOL_ */
+    U8                          Reserved;       /* 02h */
+} RAID_VOL0_SETTINGS, MPI_POINTER PTR_RAID_VOL0_SETTINGS,
+  RaidVol0Settings, MPI_POINTER pRaidVol0Settings;
+
+/* RAID Volume Page 0 VolumeSettings defines */
+
+#define MPI_RAIDVOL0_SETTING_WRITE_CACHING_ENABLE       (0x0001)
+#define MPI_RAIDVOL0_SETTING_OFFLINE_ON_SMART           (0x0002)
+#define MPI_RAIDVOL0_SETTING_AUTO_CONFIGURE             (0x0004)
+#define MPI_RAIDVOL0_SETTING_PRIORITY_RESYNC            (0x0008)
+#define MPI_RAIDVOL0_SETTING_USE_PRODUCT_ID_SUFFIX      (0x0010)
+#define MPI_RAIDVOL0_SETTING_USE_DEFAULTS               (0x8000)
+
+/* RAID Volume Page 0 HotSparePool defines, also used in RAID Physical Disk */
+#define MPI_RAID_HOT_SPARE_POOL_0                       (0x01)
+#define MPI_RAID_HOT_SPARE_POOL_1                       (0x02)
+#define MPI_RAID_HOT_SPARE_POOL_2                       (0x04)
+#define MPI_RAID_HOT_SPARE_POOL_3                       (0x08)
+#define MPI_RAID_HOT_SPARE_POOL_4                       (0x10)
+#define MPI_RAID_HOT_SPARE_POOL_5                       (0x20)
+#define MPI_RAID_HOT_SPARE_POOL_6                       (0x40)
+#define MPI_RAID_HOT_SPARE_POOL_7                       (0x80)
 
-#define MPI_RAIDVOLPAGE2_MAX_DISKS                      (3)
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check Header.PageLength at runtime.
+ */
+#ifndef MPI_RAID_VOL_PAGE_0_PHYSDISK_MAX
+#define MPI_RAID_VOL_PAGE_0_PHYSDISK_MAX        (1)
+#endif
 
-typedef struct _CONFIG_PAGE_RAID_VOL_2
+typedef struct _CONFIG_PAGE_RAID_VOL_0
 {
-   fCONFIG_PAGE_HEADER          Header;                 /* 00h */
-    U32                         VolumeStatus;           /* 04h */
-    U32                         VolumeSettings;         /* 08h */
-    U32                         Reserved;               /* 0Ch */
-    U64                         MaxLba;                 /* 10h */
-    U32                         BlockSize;              /* 18h */
-    U8                          Reserved1;              /* 1Ch */
-    U8                          NumPhysicalDisks;       /* 1Dh */
-    U16                         Reserved2;              /* 1Eh */
-    RAIDVOL2_IM_PHYSICAL_DISK   IMPhysicalDisk[MPI_RAIDVOLPAGE2_MAX_DISKS];
-} fCONFIG_PAGE_RAID_VOL_2, MPI_POINTER PTR_CONFIG_PAGE_RAID_VOL_2,
-  RaidVolumePage2_t, MPI_POINTER pRaidVolumePage2_t;
+    fCONFIG_PAGE_HEADER      Header;         /* 00h */
+    U8                      VolumeID;       /* 04h */
+    U8                      VolumeBus;      /* 05h */
+    U8                      VolumeIOC;      /* 06h */
+    U8                      VolumeType;     /* 07h */ /* MPI_RAID_VOL_TYPE_ */
+    RAID_VOL0_STATUS        VolumeStatus;   /* 08h */
+    RAID_VOL0_SETTINGS      VolumeSettings; /* 0Ch */
+    U32                     MaxLBA;         /* 10h */
+    U32                     Reserved1;      /* 14h */
+    U32                     StripeSize;     /* 18h */
+    U32                     Reserved2;      /* 1Ch */
+    U32                     Reserved3;      /* 20h */
+    U8                      NumPhysDisks;   /* 24h */
+    U8                      Reserved4;      /* 25h */
+    U16                     Reserved5;      /* 26h */
+    RAID_VOL0_PHYS_DISK     PhysDisk[MPI_RAID_VOL_PAGE_0_PHYSDISK_MAX];/* 28h */
+} fCONFIG_PAGE_RAID_VOL_0, MPI_POINTER PTR_CONFIG_PAGE_RAID_VOL_0,
+  RaidVolumePage0_t, MPI_POINTER pRaidVolumePage0_t;
+
+#define MPI_RAIDVOLPAGE0_PAGEVERSION                    (0x00)
 
-#define MPI_RAIDVOLPAGE2_PAGEVERSION                    (0x00)
 
-/* RAID Volume Page 2 VolumeStatus defines */
+/****************************************************************************
+*   RAID Physical Disk Config Pages
+****************************************************************************/
 
-#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)
+typedef struct _RAID_PHYS_DISK0_ERROR_DATA
+{
+    U8                      ErrorCdbByte;               /* 00h */
+    U8                      ErrorSenseKey;              /* 01h */
+    U16                     Reserved;                   /* 02h */
+    U16                     ErrorCount;                 /* 04h */
+    U8                      ErrorASC;                   /* 06h */
+    U8                      ErrorASCQ;                  /* 07h */
+    U16                     SmartCount;                 /* 08h */
+    U8                      SmartASC;                   /* 0Ah */
+    U8                      SmartASCQ;                  /* 0Bh */
+} RAID_PHYS_DISK0_ERROR_DATA, MPI_POINTER PTR_RAID_PHYS_DISK0_ERROR_DATA,
+  RaidPhysDisk0ErrorData_t, MPI_POINTER pRaidPhysDisk0ErrorData_t;
+
+typedef struct _RAID_PHYS_DISK_INQUIRY_DATA
+{
+    U8                          VendorID[8];            /* 00h */
+    U8                          ProductID[16];          /* 08h */
+    U8                          ProductRevLevel[4];     /* 18h */
+    U8                          Info[32];               /* 1Ch */
+} RAID_PHYS_DISK0_INQUIRY_DATA, MPI_POINTER PTR_RAID_PHYS_DISK0_INQUIRY_DATA,
+  RaidPhysDisk0InquiryData, MPI_POINTER pRaidPhysDisk0InquiryData;
+
+typedef struct _RAID_PHYS_DISK0_SETTINGS
+{
+    U8              SepID;              /* 00h */
+    U8              SepBus;             /* 01h */
+    U8              HotSparePool;       /* 02h */ /* MPI_RAID_HOT_SPARE_POOL_ */
+    U8              PhysDiskSettings;   /* 03h */
+} RAID_PHYS_DISK0_SETTINGS, MPI_POINTER PTR_RAID_PHYS_DISK0_SETTINGS,
+  RaidPhysDiskSettings_t, MPI_POINTER pRaidPhysDiskSettings_t;
+
+typedef struct _RAID_PHYS_DISK0_STATUS
+{
+    U8                              Flags;              /* 00h */
+    U8                              State;              /* 01h */
+    U16                             Reserved;           /* 02h */
+} RAID_PHYS_DISK0_STATUS, MPI_POINTER PTR_RAID_PHYS_DISK0_STATUS,
+  RaidPhysDiskStatus_t, MPI_POINTER pRaidPhysDiskStatus_t;
 
-/* RAID Volume Page 2 VolumeSettings defines */
+/* RAID Volume 2 IM Physical Disk DiskStatus flags */
+
+#define MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC           (0x01)
+#define MPI_PHYSDISK0_STATUS_FLAG_QUIESCED              (0x02)
 
-#define MPI_RAIDVOLPAGE2_SETTING_WRITE_CACHING_ENABLE   (0x00000001)
-#define MPI_RAIDVOLPAGE2_SETTING_OFFLINE_ON_SMART       (0x00000002)
-#define MPI_RAIDVOLPAGE2_SETTING_AUTO_CONFIGURE         (0x00000004)
-#define MPI_RAIDVOLPAGE2_SETTING_USE_DEFAULTS           (0x80000000)
+#define MPI_PHYSDISK0_STATUS_ONLINE                     (0x00)
+#define MPI_PHYSDISK0_STATUS_MISSING                    (0x01)
+#define MPI_PHYSDISK0_STATUS_NOT_COMPATIBLE             (0x02)
+#define MPI_PHYSDISK0_STATUS_FAILED                     (0x03)
+#define MPI_PHYSDISK0_STATUS_INITIALIZING               (0x04)
+#define MPI_PHYSDISK0_STATUS_OFFLINE_REQUESTED          (0x05)
+#define MPI_PHYSDISK0_STATUS_FAILED_REQUESTED           (0x06)
+#define MPI_PHYSDISK0_STATUS_OTHER_OFFLINE              (0xFF)
 
+typedef struct _CONFIG_PAGE_RAID_PHYS_DISK_0
+{
+    fCONFIG_PAGE_HEADER              Header;             /* 00h */
+    U8                              PhysDiskID;         /* 04h */
+    U8                              PhysDiskBus;        /* 05h */
+    U8                              PhysDiskIOC;        /* 06h */
+    U8                              PhysDiskNum;        /* 07h */
+    RAID_PHYS_DISK0_SETTINGS        PhysDiskSettings;   /* 08h */
+    U32                             Reserved1;          /* 0Ch */
+    U32                             Reserved2;          /* 10h */
+    U32                             Reserved3;          /* 14h */
+    U8                              DiskIdentifier[16]; /* 18h */
+    RAID_PHYS_DISK0_INQUIRY_DATA    InquiryData;        /* 28h */
+    RAID_PHYS_DISK0_STATUS          PhysDiskStatus;     /* 64h */
+    U32                             MaxLBA;             /* 68h */
+    RAID_PHYS_DISK0_ERROR_DATA      ErrorData;          /* 6Ch */
+} fCONFIG_PAGE_RAID_PHYS_DISK_0, MPI_POINTER PTR_CONFIG_PAGE_RAID_PHYS_DISK_0,
+  RaidPhysDiskPage0_t, MPI_POINTER pRaidPhysDiskPage0_t;
+
+#define MPI_RAIDPHYSDISKPAGE0_PAGEVERSION           (0x00)
 
-/****************************************************************************/
-/* LAN Config Pages                                                         */
-/****************************************************************************/
+
+/****************************************************************************
+*   LAN Config Pages
+****************************************************************************/
 
 typedef struct _CONFIG_PAGE_LAN_0
 {
@@ -1083,8 +1332,8 @@ typedef struct _CONFIG_PAGE_LAN_1
     U32                     MaxWireSpeedHigh;           /* 1Ch */
     U32                     BucketsRemaining;           /* 20h */
     U32                     MaxReplySize;               /* 24h */
-    U32                     NegWireSpeedHigh;           /* 28h */
-    U32                     NegWireSpeedLow;            /* 2Ch */
+    U32                     NegWireSpeedLow;            /* 28h */
+    U32                     NegWireSpeedHigh;           /* 2Ch */
 } fCONFIG_PAGE_LAN_1, MPI_POINTER PTR_CONFIG_PAGE_LAN_1,
   LANPage1_t, MPI_POINTER pLANPage1_t;
 
index 042953b4a7562a90eab4b71f3cffc69b4f536a2e..b505e70d4129460e02c61bd889a9485ad2f81272 100644 (file)
@@ -6,7 +6,7 @@
  *          Title:  MPI Fibre Channel messages and structures
  *  Creation Date:  June 12, 2000
  *
- *    MPI Version:  01.01.07
+ *    MPI Version:  01.02.02
  *
  *  Version History
  *  ---------------
@@ -32,6 +32,9 @@
  *                      Added MPI_FC_PRIM_SEND_FLAGS_RESET_LINK define.
  *                      Added structure offset comments.
  *  04-09-01  01.01.07  Added RspLength field to MSG_LINK_SERVICE_RSP_REQUEST.
+ *  08-08-01  01.02.01  Original release for v1.2 work.
+ *  09-28-01  01.02.02  Change name of reserved field in
+ *                      MSG_LINK_SERVICE_RSP_REPLY.
  *  --------------------------------------------------------------------------
  */
 
@@ -172,7 +175,7 @@ typedef struct _MSG_LINK_SERVICE_RSP_REPLY
     U8                      MsgLength;          /* 02h */
     U8                      Function;           /* 03h */
     U16                     Reserved1;          /* 04h */
-    U8                      Reserved2;          /* 06h */
+    U8                      Reserved_0100_InitiatorIndex; /* 06h */ /* obsolete InitiatorIndex */
     U8                      MsgFlags;           /* 07h */
     U32                     MsgContext;         /* 08h */
     U16                     Reserved3;          /* 0Ch */
index 5d871e4fd11d61e517123da380750eb3efd7c74a..c0558f1953c976cbde2eaeebe07552168736ad15 100644 (file)
@@ -6,7 +6,7 @@
  *          Title:  MPI initiator mode messages and structures
  *  Creation Date:  June 8, 2000
  *
- *    MPI Version:  01.01.05
+ *    MPI Version:  01.02.04
  *
  *  Version History
  *  ---------------
  *  02-20-01  01.01.03  Started using MPI_POINTER.
  *  03-27-01  01.01.04  Added structure offset comments.
  *  04-10-01  01.01.05  Added new MsgFlag for MSG_SCSI_TASK_MGMT.
+ *  08-08-01  01.02.01  Original release for v1.2 work.
+ *  08-29-01  01.02.02  Added MPI_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET.
+ *                      Added MPI_SCSI_STATE_QUEUE_TAG_REJECTED for
+ *                      MSG_SCSI_IO_REPLY.
+ *  09-28-01  01.02.03  Added structures and defines for SCSI Enclosure
+ *                      Processor messages.
+ *  10-04-01  01.02.04  Added defines for SEP request Action field.
  *  --------------------------------------------------------------------------
  */
 
@@ -151,6 +158,7 @@ typedef struct _MSG_SCSI_IO_REPLY
 #define MPI_SCSI_STATE_NO_SCSI_STATUS           (0x04)
 #define MPI_SCSI_STATE_TERMINATED               (0x08)
 #define MPI_SCSI_STATE_RESPONSE_INFO_VALID      (0x10)
+#define MPI_SCSI_STATE_QUEUE_TAG_REJECTED       (0x20)
 
 /* SCSIIO Reply ResponseInfo values */
 /* (FCP-1 RSP_CODE values and SPI-3 Packetized Failure codes) */
@@ -191,6 +199,7 @@ typedef struct _MSG_SCSI_TASK_MGMT
 #define MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET         (0x02)
 #define MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET          (0x03)
 #define MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS             (0x04)
+#define MPI_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET    (0x05)
 
 /* MsgFlags bits */
 #define MPI_SCSITASKMGMT_MSGFLAGS_TARGET_RESET_OPTION   (0x00)
@@ -216,4 +225,91 @@ typedef struct _MSG_SCSI_TASK_MGMT_REPLY
 } MSG_SCSI_TASK_MGMT_REPLY, MPI_POINTER PTR_MSG_SCSI_TASK_MGMT_REPLY,
   SCSITaskMgmtReply_t, MPI_POINTER pSCSITaskMgmtReply_t;
 
+
+/****************************************************************************/
+/*  SCSI Enclosure Processor messages                                       */
+/****************************************************************************/
+
+typedef struct _MSG_SEP_REQUEST
+{
+    U8                      TargetID;           /* 00h */
+    U8                      Bus;                /* 01h */
+    U8                      ChainOffset;        /* 02h */
+    U8                      Function;           /* 03h */
+    U8                      Action;             /* 04h */
+    U8                      Reserved1;          /* 05h */
+    U8                      Reserved2;          /* 06h */
+    U8                      MsgFlags;           /* 07h */
+    U32                     MsgContext;         /* 08h */
+    U32                     SlotStatus;         /* 0Ch */
+} MSG_SEP_REQUEST, MPI_POINTER PTR_MSG_SEP_REQUEST,
+  SEPRequest_t, MPI_POINTER pSEPRequest_t;
+
+/* Action defines */
+#define MPI_SEP_REQ_ACTION_WRITE_STATUS                 (0x00)
+#define MPI_SEP_REQ_ACTION_READ_STATUS                  (0x01)
+
+/* SlotStatus bits for MSG_SEP_REQUEST */
+#define MPI_SEP_REQ_SLOTSTATUS_NO_ERROR                 (0x00000001)
+#define MPI_SEP_REQ_SLOTSTATUS_DEV_FAULTY               (0x00000002)
+#define MPI_SEP_REQ_SLOTSTATUS_DEV_REBUILDING           (0x00000004)
+#define MPI_SEP_REQ_SLOTSTATUS_IN_FAILED_ARRAY          (0x00000008)
+#define MPI_SEP_REQ_SLOTSTATUS_IN_CRITICAL_ARRAY        (0x00000010)
+#define MPI_SEP_REQ_SLOTSTATUS_PARITY_CHECK             (0x00000020)
+#define MPI_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT          (0x00000040)
+#define MPI_SEP_REQ_SLOTSTATUS_UNCONFIGURED             (0x00000080)
+#define MPI_SEP_REQ_SLOTSTATUS_HOT_SPARE                (0x00000100)
+#define MPI_SEP_REQ_SLOTSTATUS_REBUILD_STOPPED          (0x00000200)
+#define MPI_SEP_REQ_SLOTSTATUS_IDENTIFY_REQUEST         (0x00020000)
+#define MPI_SEP_REQ_SLOTSTATUS_REQUEST_REMOVE           (0x00040000)
+#define MPI_SEP_REQ_SLOTSTATUS_REQUEST_INSERT           (0x00080000)
+#define MPI_SEP_REQ_SLOTSTATUS_DO_NOT_MOVE              (0x00400000)
+#define MPI_SEP_REQ_SLOTSTATUS_B_ENABLE_BYPASS          (0x04000000)
+#define MPI_SEP_REQ_SLOTSTATUS_A_ENABLE_BYPASS          (0x08000000)
+#define MPI_SEP_REQ_SLOTSTATUS_DEV_OFF                  (0x10000000)
+#define MPI_SEP_REQ_SLOTSTATUS_SWAP_RESET               (0x80000000)
+
+
+typedef struct _MSG_SEP_REPLY
+{
+    U8                      TargetID;           /* 00h */
+    U8                      Bus;                /* 01h */
+    U8                      MsgLength;          /* 02h */
+    U8                      Function;           /* 03h */
+    U8                      Action;             /* 04h */
+    U8                      Reserved1;          /* 05h */
+    U8                      Reserved2;          /* 06h */
+    U8                      MsgFlags;           /* 07h */
+    U32                     MsgContext;         /* 08h */
+    U16                     Reserved3;          /* 0Ch */
+    U16                     IOCStatus;          /* 0Eh */
+    U32                     IOCLogInfo;         /* 10h */
+    U32                     SlotStatus;         /* 14h */
+} MSG_SEP_REPLY, MPI_POINTER PTR_MSG_SEP_REPLY,
+  SEPReply_t, MPI_POINTER pSEPReply_t;
+
+/* SlotStatus bits for MSG_SEP_REPLY */
+#define MPI_SEP_REPLY_SLOTSTATUS_NO_ERROR               (0x00000001)
+#define MPI_SEP_REPLY_SLOTSTATUS_DEV_FAULTY             (0x00000002)
+#define MPI_SEP_REPLY_SLOTSTATUS_DEV_REBUILDING         (0x00000004)
+#define MPI_SEP_REPLY_SLOTSTATUS_IN_FAILED_ARRAY        (0x00000008)
+#define MPI_SEP_REPLY_SLOTSTATUS_IN_CRITICAL_ARRAY      (0x00000010)
+#define MPI_SEP_REPLY_SLOTSTATUS_PARITY_CHECK           (0x00000020)
+#define MPI_SEP_REPLY_SLOTSTATUS_PREDICTED_FAULT        (0x00000040)
+#define MPI_SEP_REPLY_SLOTSTATUS_UNCONFIGURED           (0x00000080)
+#define MPI_SEP_REPLY_SLOTSTATUS_HOT_SPARE              (0x00000100)
+#define MPI_SEP_REPLY_SLOTSTATUS_REBUILD_STOPPED        (0x00000200)
+#define MPI_SEP_REPLY_SLOTSTATUS_REPORT                 (0x00010000)
+#define MPI_SEP_REPLY_SLOTSTATUS_IDENTIFY_REQUEST       (0x00020000)
+#define MPI_SEP_REPLY_SLOTSTATUS_REMOVE_READY           (0x00040000)
+#define MPI_SEP_REPLY_SLOTSTATUS_INSERT_READY           (0x00080000)
+#define MPI_SEP_REPLY_SLOTSTATUS_DO_NOT_REMOVE          (0x00400000)
+#define MPI_SEP_REPLY_SLOTSTATUS_B_BYPASS_ENABLED       (0x01000000)
+#define MPI_SEP_REPLY_SLOTSTATUS_A_BYPASS_ENABLED       (0x02000000)
+#define MPI_SEP_REPLY_SLOTSTATUS_B_ENABLE_BYPASS        (0x04000000)
+#define MPI_SEP_REPLY_SLOTSTATUS_A_ENABLE_BYPASS        (0x08000000)
+#define MPI_SEP_REPLY_SLOTSTATUS_DEV_OFF                (0x10000000)
+#define MPI_SEP_REPLY_SLOTSTATUS_FAULT_SENSED           (0x40000000)
+#define MPI_SEP_REPLY_SLOTSTATUS_SWAPPED                (0x80000000)
+
 #endif
index d910811bc0ff19ebdabccf6fcd9e15240da02f94..ac117dc1da314cb359cb3c9827f57b0201f3fbdd 100644 (file)
@@ -6,7 +6,7 @@
  *          Title:  MPI IOC, Port, Event, FW Download, and FW Upload messages
  *  Creation Date:  August 11, 2000
  *
- *    MPI Version:  01.01.07
+ *    MPI Version:  01.02.04
  *
  *  Version History
  *  ---------------
  *  03-27-01  01.01.06  Added defines for ProductId field of MPI_FW_HEADER.
  *                      Added structure offset comments.
  *  04-09-01  01.01.07  Added structure EVENT_DATA_EVENT_CHANGE.
+ *  08-08-01  01.02.01  Original release for v1.2 work.
+ *                      New format for FWVersion and ProductId in
+ *                      MSG_IOC_FACTS_REPLY and MPI_FW_HEADER.
+ *  08-31-01  01.02.02  Addded event MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE and
+ *                      related structure and defines.
+ *                      Added event MPI_EVENT_ON_BUS_TIMER_EXPIRED.
+ *                      Added MPI_IOCINIT_FLAGS_DISCARD_FW_IMAGE.
+ *                      Replaced a reserved field in MSG_IOC_FACTS_REPLY with
+ *                      IOCExceptions and changed DataImageSize to reserved.
+ *                      Added MPI_FW_DOWNLOAD_ITYPE_NVSTORE_DATA and
+ *                      MPI_FW_UPLOAD_ITYPE_NVDATA.
+ *  09-28-01  01.02.03  Modified Event Data for Integrated RAID.
+ *  11-01-01  01.02.04  Added defines for MPI_EXT_IMAGE_HEADER ImageType field.
  *  --------------------------------------------------------------------------
  */
 
@@ -73,6 +86,17 @@ typedef struct _MSG_IOC_INIT
 } MSG_IOC_INIT, MPI_POINTER PTR_MSG_IOC_INIT,
   IOCInit_t, MPI_POINTER pIOCInit_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)
+
+/* Flags values */
+#define MPI_IOCINIT_FLAGS_DISCARD_FW_IMAGE      (0x01)
+
 typedef struct _MSG_IOC_INIT_REPLY
 {
     U8                      WhoInit;                    /* 00h */
@@ -90,14 +114,6 @@ typedef struct _MSG_IOC_INIT_REPLY
 } 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)
 
 
 /****************************************************************************/
@@ -115,8 +131,21 @@ typedef struct _MSG_IOC_FACTS
 } MSG_IOC_FACTS, MPI_POINTER PTR_IOC_FACTS,
   IOCFacts_t, MPI_POINTER pIOCFacts_t;
 
-/* IOC Facts Reply */
+typedef struct _MPI_FW_VERSION_STRUCT
+{
+    U8                      Dev;                        /* 00h */
+    U8                      Unit;                       /* 01h */
+    U8                      Minor;                      /* 02h */
+    U8                      Major;                      /* 03h */
+} MPI_FW_VERSION_STRUCT;
+
+typedef union _MPI_FW_VERSION
+{
+    MPI_FW_VERSION_STRUCT   Struct;
+    U32                     Word;
+} MPI_FW_VERSION;
 
+/* IOC Facts Reply */
 typedef struct _MSG_IOC_FACTS_REPLY
 {
     U16                     MsgVersion;                 /* 00h */
@@ -126,7 +155,7 @@ typedef struct _MSG_IOC_FACTS_REPLY
     U8                      IOCNumber;                  /* 06h */
     U8                      MsgFlags;                   /* 07h */
     U32                     MsgContext;                 /* 08h */
-    U16                     Reserved2;                  /* 0Ch */
+    U16                     IOCExceptions;              /* 0Ch */
     U16                     IOCStatus;                  /* 0Eh */
     U32                     IOCLogInfo;                 /* 10h */
     U8                      MaxChainDepth;              /* 14h */
@@ -135,7 +164,7 @@ typedef struct _MSG_IOC_FACTS_REPLY
     U8                      Flags;                      /* 17h */
     U16                     ReplyQueueDepth;            /* 18h */
     U16                     RequestFrameSize;           /* 1Ah */
-    U16                     FWVersion;                  /* 1Ch */
+    U16                     Reserved_0101_FWVersion;    /* 1Ch */ /* obsolete 16-bit FWVersion */
     U16                     ProductID;                  /* 1Eh */
     U32                     CurrentHostMfaHighAddr;     /* 20h */
     U16                     GlobalCredits;              /* 24h */
@@ -146,18 +175,20 @@ typedef struct _MSG_IOC_FACTS_REPLY
     U8                      MaxDevices;                 /* 2Eh */
     U8                      MaxBuses;                   /* 2Fh */
     U32                     FWImageSize;                /* 30h */
-    U32                     DataImageSize;              /* 34h */
+    U32                     Reserved4;                  /* 34h */
+    MPI_FW_VERSION          FWVersion;                  /* 38h */
 } 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_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_EXCEPT_CONFIG_CHECKSUM_FAIL    (0x0001)
 
-#define MPI_IOCFACTS_EVENTSTATE_DISABLED        (0x00)
-#define MPI_IOCFACTS_EVENTSTATE_ENABLED         (0x01)
+#define MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT         (0x01)
+
+#define MPI_IOCFACTS_EVENTSTATE_DISABLED            (0x00)
+#define MPI_IOCFACTS_EVENTSTATE_ENABLED             (0x01)
 
 
 
@@ -326,7 +357,6 @@ typedef struct _MSG_EVENT_ACK_REPLY
 } 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)
@@ -345,7 +375,9 @@ typedef struct _MSG_EVENT_ACK_REPLY
 #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)
+#define MPI_EVENT_INTEGRATED_RAID           (0x0000000B)
+#define MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE (0x0000000C)
+#define MPI_EVENT_ON_BUS_TIMER_EXPIRED      (0x0000000D)
 
 /* AckRequired field values */
 
@@ -372,6 +404,27 @@ typedef struct _EVENT_DATA_SCSI
 } EVENT_DATA_SCSI, MPI_POINTER PTR_EVENT_DATA_SCSI,
   EventDataScsi_t, MPI_POINTER pEventDataScsi_t;
 
+/* SCSI Device Status Change Event data */
+
+typedef struct _EVENT_DATA_SCSI_DEVICE_STATUS_CHANGE
+{
+    U8                      TargetID;                   /* 00h */
+    U8                      Bus;                        /* 01h */
+    U8                      ReasonCode;                 /* 02h */
+    U8                      LUN;                        /* 03h */
+    U8                      ASC;                        /* 04h */
+    U8                      ASCQ;                       /* 05h */
+    U16                     Reserved;                   /* 06h */
+} EVENT_DATA_SCSI_DEVICE_STATUS_CHANGE,
+  MPI_POINTER PTR_EVENT_DATA_SCSI_DEVICE_STATUS_CHANGE,
+  MpiEventDataScsiDeviceStatusChange_t,
+  MPI_POINTER pMpiEventDataScsiDeviceStatusChange_t;
+
+/* MPI SCSI Device Status Change Event data ReasonCode values */
+#define MPI_EVENT_SCSI_DEV_STAT_RC_ADDED                (0x03)
+#define MPI_EVENT_SCSI_DEV_STAT_RC_NOT_RESPONDING       (0x04)
+#define MPI_EVENT_SCSI_DEV_STAT_RC_SMART_DATA           (0x05)
+
 /* MPI Link Status Change Event data */
 
 typedef struct _EVENT_DATA_LINK_STATUS
@@ -417,29 +470,34 @@ typedef struct _EVENT_DATA_LOGOUT
 } EVENT_DATA_LOGOUT, MPI_POINTER PTR_EVENT_DATA_LOGOUT,
   EventDataLogout_t, MPI_POINTER pEventDataLogout_t;
 
-/* MPI RAID Status Change Event data */
+/* MPI Integrated RAID Event data */
 
-typedef struct _EVENT_DATA_RAID_STATUS_CHANGE
+typedef struct _EVENT_DATA_RAID
 {
-    U8                      VolumeTargetID;             /* 00h */
+    U8                      VolumeID;                   /* 00h */
     U8                      VolumeBus;                  /* 01h */
     U8                      ReasonCode;                 /* 02h */
     U8                      PhysDiskNum;                /* 03h */
     U8                      ASC;                        /* 04h */
     U8                      ASCQ;                       /* 05h */
     U16                     Reserved;                   /* 06h */
-} 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)
+    U32                     SettingsStatus;             /* 08h */
+} EVENT_DATA_RAID, MPI_POINTER PTR_EVENT_DATA_RAID,
+  MpiEventDataRaid_t, MPI_POINTER pMpiEventDataRaid_t;
+
+/* MPI Integrated RAID Event data ReasonCode values */
+#define MPI_EVENT_RAID_RC_VOLUME_CREATED                (0x00)
+#define MPI_EVENT_RAID_RC_VOLUME_DELETED                (0x01)
+#define MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED       (0x02)
+#define MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED         (0x03)
+#define MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED       (0x04)
+#define MPI_EVENT_RAID_RC_PHYSDISK_CREATED              (0x05)
+#define MPI_EVENT_RAID_RC_PHYSDISK_DELETED              (0x06)
+#define MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED     (0x07)
+#define MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED       (0x08)
+#define MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED             (0x09)
+#define MPI_EVENT_RAID_RC_SMART_DATA                    (0x0A)
+#define MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED        (0x0B)
 
 
 /*****************************************************************************
@@ -468,6 +526,7 @@ typedef struct _MSG_FW_DOWNLOAD
 #define MPI_FW_DOWNLOAD_ITYPE_RESERVED      (0x00)
 #define MPI_FW_DOWNLOAD_ITYPE_FW            (0x01)
 #define MPI_FW_DOWNLOAD_ITYPE_BIOS          (0x02)
+#define MPI_FW_DOWNLOAD_ITYPE_NVDATA        (0x03)
 
 
 typedef struct _FWDownloadTCSGE
@@ -476,7 +535,7 @@ typedef struct _FWDownloadTCSGE
     U8                      ContextSize;                /* 01h */
     U8                      DetailsLength;              /* 02h */
     U8                      Flags;                      /* 03h */
-    U32                     Reserved1;                  /* 04h */
+    U32                     Reserved_0100_Checksum;     /* 04h */ /* obsolete Checksum */
     U32                     ImageOffset;                /* 08h */
     U32                     ImageSize;                  /* 0Ch */
 } FW_DOWNLOAD_TCSGE, MPI_POINTER PTR_FW_DOWNLOAD_TCSGE,
@@ -519,7 +578,7 @@ typedef struct _MSG_FW_UPLOAD
 #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)
+#define MPI_FW_UPLOAD_ITYPE_NVDATA          (0x03)
 
 typedef struct _FWUploadTCSGE
 {
@@ -563,11 +622,10 @@ typedef struct _MPI_FW_HEADER
     U32                     Checksum;                   /* 1Ch */
     U16                     VendorId;                   /* 20h */
     U16                     ProductId;                  /* 22h */
-    U16                     FwVersion;                  /* 24h */
-    U16                     Reserved1;                  /* 26h */
+    MPI_FW_VERSION          FWVersion;                  /* 24h */
     U32                     SeqCodeVersion;             /* 28h */
     U32                     ImageSize;                  /* 2Ch */
-    U32                     Reserved2;                  /* 30h */
+    U32                     NextImageHeaderOffset;      /* 30h */
     U32                     LoadStartAddress;           /* 34h */
     U32                     IopResetVectorValue;        /* 38h */
     U32                     IopResetRegAddr;            /* 3Ch */
@@ -581,30 +639,49 @@ typedef struct _MPI_FW_HEADER
 #define MPI_FW_HEADER_WHAT_SIGNATURE        (0x29232840)
 
 /* defines for using the ProductId field */
-#define MPI_FW_HEADER_PID_TYPE_MASK         (0xF000)
-#define MPI_FW_HEADER_PID_TYPE_SCSI         (0x0000)
-#define MPI_FW_HEADER_PID_TYPE_FC           (0x1000)
-
-#define MPI_FW_HEADER_PID_FW_VENDOR_MASK    (0x0F00)
-#define MPI_FW_HEADER_PID_FW_VENDOR_LSI     (0x0000)
-
-#define MPI_FW_HEADER_PID_FAMILY_MASK       (0x000F)
-#define MPI_FW_HEADER_PID_FAMILY_1030_SCSI  (0x0000)
-#define MPI_FW_HEADER_PID_FAMILY_909_FC     (0x0000)
-#define MPI_FW_HEADER_PID_FAMILY_919_FC     (0x0001)
-#define MPI_FW_HEADER_PID_FAMILY_919X_FC    (0x0002)
-
-
-typedef struct _MPI_DATA_HEADER
+#define MPI_FW_HEADER_PID_TYPE_MASK             (0xF000)
+#define MPI_FW_HEADER_PID_TYPE_SCSI             (0x0000)
+#define MPI_FW_HEADER_PID_TYPE_FC               (0x1000)
+
+#define MPI_FW_HEADER_PID_PROD_MASK                     (0x0F00)
+#define MPI_FW_HEADER_PID_PROD_INITIATOR_SCSI           (0x0100)
+#define MPI_FW_HEADER_PID_PROD_TARGET_INITIATOR_SCSI    (0x0200)
+#define MPI_FW_HEADER_PID_PROD_TARGET_SCSI              (0x0300)
+#define MPI_FW_HEADER_PID_PROD_IM_SCSI                  (0x0400)
+#define MPI_FW_HEADER_PID_PROD_IS_SCSI                  (0x0500)
+#define MPI_FW_HEADER_PID_PROD_CTX_SCSI                 (0x0600)
+
+#define MPI_FW_HEADER_PID_FAMILY_MASK           (0x00FF)
+#define MPI_FW_HEADER_PID_FAMILY_1030A0_SCSI    (0x0001)
+#define MPI_FW_HEADER_PID_FAMILY_1030B0_SCSI    (0x0002)
+#define MPI_FW_HEADER_PID_FAMILY_1030B1_SCSI    (0x0003)
+#define MPI_FW_HEADER_PID_FAMILY_1030C0_SCSI    (0x0004)
+#define MPI_FW_HEADER_PID_FAMILY_1020A0_SCSI    (0x0005)
+#define MPI_FW_HEADER_PID_FAMILY_1020B0_SCSI    (0x0006)
+#define MPI_FW_HEADER_PID_FAMILY_1020B1_SCSI    (0x0007)
+#define MPI_FW_HEADER_PID_FAMILY_1020C0_SCSI    (0x0008)
+#define MPI_FW_HEADER_PID_FAMILY_1035A0_SCSI    (0x0009)
+#define MPI_FW_HEADER_PID_FAMILY_1035B0_SCSI    (0x000A)
+#define MPI_FW_HEADER_PID_FAMILY_909_FC         (0x0000)
+#define MPI_FW_HEADER_PID_FAMILY_919_FC         (0x0001)
+#define MPI_FW_HEADER_PID_FAMILY_919X_FC        (0x0002)
+
+typedef struct _MPI_EXT_IMAGE_HEADER
 {
-    U32                     Signature;                  /* 00h */
-    U16                     FunctionNumber;             /* 04h */
-    U16                     Length;                     /* 06h */
-    U32                     Checksum;                   /* 08h */
-    U32                     LoadStartAddress;           /* 0Ch */
-} MPI_DATA_HEADER, MPI_POINTER PTR_MPI_DATA_HEADER,
-  MpiDataHeader_t, MPI_POINTER pMpiDataHeader_t;
-
-#define MPI_DATA_HEADER_SIGNATURE           (0x43504147)
+    U8                      ImageType;                  /* 00h */
+    U8                      Reserved;                   /* 01h */
+    U16                     Reserved1;                  /* 02h */
+    U32                     Checksum;                   /* 04h */
+    U32                     ImageSize;                  /* 08h */
+    U32                     NextImageHeaderOffset;      /* 0Ch */
+    U32                     LoadStartAddress;           /* 10h */
+    U32                     Reserved2;                  /* 14h */
+} MPI_EXT_IMAGE_HEADER, MPI_POINTER PTR_MPI_EXT_IMAGE_HEADER,
+  MpiExtImageHeader_t, MPI_POINTER pMpiExtImageHeader_t;
+
+/* defines for the ImageType field */
+#define MPI_EXT_IMAGE_TYPE_UNSPECIFIED          (0x00)
+#define MPI_EXT_IMAGE_TYPE_FW                   (0x01)
+#define MPI_EXT_IMAGE_TYPE_NVDATA               (0x03)
 
 #endif
index f5a3bb0bf3d6257df655239928937b283862fb05..49d1d52838f7820dfa9d99abd14a29c0943e93a3 100644 (file)
@@ -6,7 +6,7 @@
  *          Title:  MPI LAN messages and structures
  *  Creation Date:  June 30, 2000
  *
- *    MPI Version:  01.01.03
+ *    MPI Version:  01.02.01
  *
  *  Version History
  *  ---------------
@@ -27,6 +27,7 @@
  *  11-02-00  01.01.01  Original release for post 1.0 work
  *  02-20-01  01.01.02  Started using MPI_POINTER.
  *  03-27-01  01.01.03  Added structure offset comments.
+ *  08-08-01  01.02.01  Original release for v1.2 work.
  *  --------------------------------------------------------------------------
  */
 
diff --git a/drivers/message/fusion/lsi/mpi_raid.h b/drivers/message/fusion/lsi/mpi_raid.h
new file mode 100644 (file)
index 0000000..a6248f2
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ *  Copyright (c) 2001 LSI Logic Corporation.
+ *
+ *
+ *           Name:  MPI_RAID.H
+ *          Title:  MPI RAID message and structures
+ *  Creation Date:  February 27, 2001
+ *
+ *    MPI Version:  01.02.04
+ *
+ *  Version History
+ *  ---------------
+ *
+ *  Date      Version   Description
+ *  --------  --------  ------------------------------------------------------
+ *  02-27-01  01.01.01  Original release for this file.
+ *  03-27-01  01.01.02  Added structure offset comments.
+ *  08-08-01  01.02.01  Original release for v1.2 work.
+ *  09-28-01  01.02.02  Major rework for MPI v1.2 Integrated RAID changes.
+ *  10-04-01  01.02.03  Added ActionData defines for
+ *                      MPI_RAID_ACTION_DELETE_VOLUME action.
+ *  11-01-01  01.02.04  Added define for MPI_RAID_ACTION_ADATA_DO_NOT_SYNC.
+ *  --------------------------------------------------------------------------
+ */
+
+#ifndef MPI_RAID_H
+#define MPI_RAID_H
+
+
+/******************************************************************************
+*
+*        R A I D    M e s s a g e s
+*
+*******************************************************************************/
+
+
+/****************************************************************************/
+/* RAID Volume Request                                                      */
+/****************************************************************************/
+
+typedef struct _MSG_RAID_ACTION
+{
+    U8                      Action;             /* 00h */
+    U8                      Reserved1;          /* 01h */
+    U8                      ChainOffset;        /* 02h */
+    U8                      Function;           /* 03h */
+    U8                      VolumeID;           /* 04h */
+    U8                      VolumeBus;          /* 05h */
+    U8                      PhysDiskNum;        /* 06h */
+    U8                      MsgFlags;           /* 07h */
+    U32                     MsgContext;         /* 08h */
+    U32                     Reserved2;          /* 0Ch */
+    U32                     ActionDataWord;     /* 10h */
+    SGE_SIMPLE_UNION        ActionDataSGE;      /* 14h */
+} MSG_RAID_ACTION_REQUEST, MPI_POINTER PTR_MSG_RAID_ACTION_REQUEST,
+  MpiRaidActionRequest_t , MPI_POINTER pMpiRaidActionRequest_t;
+
+
+/* RAID Action request Action values */
+
+#define MPI_RAID_ACTION_STATUS                      (0x00)
+#define MPI_RAID_ACTION_INDICATOR_STRUCT            (0x01)
+#define MPI_RAID_ACTION_CREATE_VOLUME               (0x02)
+#define MPI_RAID_ACTION_DELETE_VOLUME               (0x03)
+#define MPI_RAID_ACTION_DISABLE_VOLUME              (0x04)
+#define MPI_RAID_ACTION_ENABLE_VOLUME               (0x05)
+#define MPI_RAID_ACTION_QUIESCE_PHYS_IO             (0x06)
+#define MPI_RAID_ACTION_ENABLE_PHYS_IO              (0x07)
+#define MPI_RAID_ACTION_CHANGE_VOLUME_SETTINGS      (0x08)
+#define MPI_RAID_ACTION_PHYSDISK_OFFLINE            (0x0A)
+#define MPI_RAID_ACTION_PHYSDISK_ONLINE             (0x0B)
+#define MPI_RAID_ACTION_CHANGE_PHYSDISK_SETTINGS    (0x0C)
+#define MPI_RAID_ACTION_CREATE_PHYSDISK             (0x0D)
+#define MPI_RAID_ACTION_DELETE_PHYSDISK             (0x0E)
+#define MPI_RAID_ACTION_FAIL_PHYSDISK               (0x0F)
+#define MPI_RAID_ACTION_REPLACE_PHYSDISK            (0x10)
+
+/* ActionDataWord defines for use with MPI_RAID_ACTION_CREATE_VOLUME action */
+#define MPI_RAID_ACTION_ADATA_DO_NOT_SYNC           (0x00000001)
+
+/* ActionDataWord defines for use with MPI_RAID_ACTION_DELETE_VOLUME action */
+#define MPI_RAID_ACTION_ADATA_KEEP_PHYS_DISKS       (0x00000000)
+#define MPI_RAID_ACTION_ADATA_DEL_PHYS_DISKS        (0x00000001)
+
+
+/* RAID Action reply message */
+
+typedef struct _MSG_RAID_ACTION_REPLY
+{
+    U8                      Action;             /* 00h */
+    U8                      Reserved;           /* 01h */
+    U8                      MsgLength;          /* 02h */
+    U8                      Function;           /* 03h */
+    U8                      VolumeID;           /* 04h */
+    U8                      VolumeBus;          /* 05h */
+    U8                      PhysDiskNum;        /* 06h */
+    U8                      MsgFlags;           /* 07h */
+    U32                     MsgContext;         /* 08h */
+    U16                     ActionStatus;       /* 0Ch */
+    U16                     IOCStatus;          /* 0Eh */
+    U32                     IOCLogInfo;         /* 10h */
+    U32                     VolumeStatus;       /* 14h */
+    U32                     ActionData;         /* 18h */
+} MSG_RAID_ACTION_REPLY, MPI_POINTER PTR_MSG_RAID_ACTION_REPLY,
+  MpiRaidActionReply_t, MPI_POINTER pMpiRaidActionReply_t;
+
+
+/* RAID Volume reply ActionStatus values */
+
+#define MPI_RAID_ACTION_ASTATUS_SUCCESS             (0x0000)
+#define MPI_RAID_ACTION_ASTATUS_INVALID_ACTION      (0x0001)
+#define MPI_RAID_ACTION_ASTATUS_FAILURE             (0x0002)
+#define MPI_RAID_ACTION_ASTATUS_IN_PROGRESS         (0x0003)
+
+
+/* RAID Volume reply RAID Volume Indicator structure */
+
+typedef struct _MPI_RAID_VOL_INDICATOR
+{
+    U64                     TotalBlocks;        /* 00h */
+    U64                     BlocksRemaining;    /* 08h */
+} MPI_RAID_VOL_INDICATOR, MPI_POINTER PTR_MPI_RAID_VOL_INDICATOR,
+  MpiRaidVolIndicator_t, MPI_POINTER pMpiRaidVolIndicator_t;
+
+
+/****************************************************************************/
+/* SCSI IO RAID Passthrough Request                                         */
+/****************************************************************************/
+
+typedef struct _MSG_SCSI_IO_RAID_PT_REQUEST
+{
+    U8                      PhysDiskNum;        /* 00h */
+    U8                      Reserved1;          /* 01h */
+    U8                      ChainOffset;        /* 02h */
+    U8                      Function;           /* 03h */
+    U8                      CDBLength;          /* 04h */
+    U8                      SenseBufferLength;  /* 05h */
+    U8                      Reserved2;          /* 06h */
+    U8                      MsgFlags;           /* 07h */
+    U32                     MsgContext;         /* 08h */
+    U8                      LUN[8];             /* 0Ch */
+    U32                     Control;            /* 14h */
+    U8                      CDB[16];            /* 18h */
+    U32                     DataLength;         /* 28h */
+    U32                     SenseBufferLowAddr; /* 2Ch */
+    SGE_IO_UNION            SGL;                /* 30h */
+} MSG_SCSI_IO_RAID_PT_REQUEST, MPI_POINTER PTR_MSG_SCSI_IO_RAID_PT_REQUEST,
+  SCSIIORaidPassthroughRequest_t, MPI_POINTER pSCSIIORaidPassthroughRequest_t;
+
+
+/* SCSI IO RAID Passthrough reply structure */
+
+typedef struct _MSG_SCSI_IO_RAID_PT_REPLY
+{
+    U8                      PhysDiskNum;        /* 00h */
+    U8                      Reserved1;          /* 01h */
+    U8                      MsgLength;          /* 02h */
+    U8                      Function;           /* 03h */
+    U8                      CDBLength;          /* 04h */
+    U8                      SenseBufferLength;  /* 05h */
+    U8                      Reserved2;          /* 06h */
+    U8                      MsgFlags;           /* 07h */
+    U32                     MsgContext;         /* 08h */
+    U8                      SCSIStatus;         /* 0Ch */
+    U8                      SCSIState;          /* 0Dh */
+    U16                     IOCStatus;          /* 0Eh */
+    U32                     IOCLogInfo;         /* 10h */
+    U32                     TransferCount;      /* 14h */
+    U32                     SenseCount;         /* 18h */
+    U32                     ResponseInfo;       /* 1Ch */
+} MSG_SCSI_IO_RAID_PT_REPLY, MPI_POINTER PTR_MSG_SCSI_IO_RAID_PT_REPLY,
+  SCSIIORaidPassthroughReply_t, MPI_POINTER pSCSIIORaidPassthroughReply_t;
+
+
+#endif
+
+
+
index 1f24a957f5c71f00efaceb585e6a19c2b8d150fe..a009f1b075df81675ae95e03a042eb554d9ac7eb 100644 (file)
@@ -6,7 +6,7 @@
  *          Title:  MPI Target mode messages and structures
  *  Creation Date:  June 22, 2000
  *
- *    MPI Version:  01.01.04
+ *    MPI Version:  01.02.04
  *
  *  Version History
  *  ---------------
  *                      Added structures for MPI_TARGET_SCSI_SPI_CMD_BUFFER and
  *                      MPI_TARGET_FCP_CMD_BUFFER.
  *  03-27-01  01.01.04  Added structure offset comments.
+ *  08-08-01  01.02.01  Original release for v1.2 work.
+ *  09-28-01  01.02.02  Added structure for MPI_TARGET_SCSI_SPI_STATUS_IU.
+ *                      Added PriorityReason field to some replies and
+ *                      defined more PriorityReason codes.
+ *                      Added some defines for to support previous version
+ *                      of MPI.
+ *  10-04-01  01.02.03  Added PriorityReason to MSG_TARGET_ERROR_REPLY.
+ *  11-01-01  01.02.04  Added define for TARGET_STATUS_SEND_FLAGS_HIGH_PRIORITY.
  *  --------------------------------------------------------------------------
  */
 
@@ -78,6 +86,7 @@ typedef struct _MSG_TARGET_CMD_BUFFER_POST_REQUEST
 #define CMD_BUFFER_POST_FLAGS_64_BIT_ADDR       (0x80)
 
 #define CMD_BUFFER_POST_IO_INDEX_MASK           (0x00003FFF)
+#define CMD_BUFFER_POST_IO_INDEX_MASK_0100      (0x000003FF) /* obsolete */
 
 
 typedef struct _MSG_TARGET_CMD_BUFFER_POST_REPLY
@@ -97,7 +106,7 @@ typedef struct _MSG_TARGET_CMD_BUFFER_POST_REPLY
 } MSG_TARGET_CMD_BUFFER_POST_REPLY, MPI_POINTER PTR_MSG_TARGET_CMD_BUFFER_POST_REPLY,
   TargetCmdBufferPostReply_t, MPI_POINTER pTargetCmdBufferPostReply_t;
 
-
+/* the following structure is obsolete as of MPI v1.2 */
 typedef struct _MSG_PRIORITY_CMD_RECEIVED_REPLY
 {
     U16                     Reserved;                   /* 00h */
@@ -117,6 +126,13 @@ typedef struct _MSG_PRIORITY_CMD_RECEIVED_REPLY
 
 #define PRIORITY_REASON_NO_DISCONNECT           (0x00)
 #define PRIORITY_REASON_SCSI_TASK_MANAGEMENT    (0x01)
+#define PRIORITY_REASON_CMD_PARITY_ERR          (0x02)
+#define PRIORITY_REASON_MSG_OUT_PARITY_ERR      (0x03)
+#define PRIORITY_REASON_LQ_CRC_ERR              (0x04)
+#define PRIORITY_REASON_CMD_CRC_ERR             (0x05)
+#define PRIORITY_REASON_PROTOCOL_ERR            (0x06)
+#define PRIORITY_REASON_DATA_OUT_PARITY_ERR     (0x07)
+#define PRIORITY_REASON_DATA_OUT_CRC_ERR        (0x08)
 #define PRIORITY_REASON_UNKNOWN                 (0xFF)
 
 
@@ -129,7 +145,8 @@ typedef struct _MSG_TARGET_CMD_BUFFER_POST_ERROR_REPLY
     U8                      Reserved2;                  /* 06h */
     U8                      MsgFlags;                   /* 07h */
     U32                     MsgContext;                 /* 08h */
-    U16                     Reserved3;                  /* 0Ch */
+    U8                      PriorityReason;             /* 0Ch */
+    U8                      Reserved3;                  /* 0Dh */
     U16                     IOCStatus;                  /* 0Eh */
     U32                     IOCLogInfo;                 /* 10h */
     U32                     ReplyWord;                  /* 14h */
@@ -204,7 +221,8 @@ typedef struct _MSG_TARGET_ERROR_REPLY
     U8                      Reserved2;                  /* 06h */
     U8                      MsgFlags;                   /* 07h */
     U32                     MsgContext;                 /* 08h */
-    U16                     Reserved3;                  /* 0Ch */
+    U8                      PriorityReason;             /* 0Ch */
+    U8                      Reserved3;                  /* 0Dh */
     U16                     IOCStatus;                  /* 0Eh */
     U32                     IOCLogInfo;                 /* 10h */
     U32                     ReplyWord;                  /* 14h */
@@ -234,8 +252,34 @@ typedef struct _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_HIGH_PRIORITY      (0x04)
 #define TARGET_STATUS_SEND_FLAGS_REPOST_CMD_BUFFER  (0x80)
 
+typedef struct _MPI_TARGET_FCP_RSP_BUFFER
+{
+    U8      Reserved0[8];                               /* 00h */
+    U8      FcpStatus;                                  /* 08h */
+    U8      FcpFlags;                                   /* 09h */
+    U8      Reserved1[2];                               /* 0Ah */
+    U32     FcpResid;                                   /* 0Ch */
+    U32     FcpSenseLength;                             /* 10h */
+    U32     FcpResponseLength;                          /* 14h */
+    U8      FcpResponseData[8];                         /* 18h */
+    U8      FcpSenseData[32]; /* Pad to 64 bytes */     /* 20h */
+} MPI_TARGET_FCP_RSP_BUFFER, MPI_POINTER PTR_MPI_TARGET_FCP_RSP_BUFFER,
+  MpiTargetFcpRspBuffer, MPI_POINTER pMpiTargetFcpRspBuffer;
+
+typedef struct _MPI_TARGET_SCSI_SPI_STATUS_IU
+{
+    U8      Reserved0;                                  /* 00h */
+    U8      Reserved1;                                  /* 01h */
+    U8      Valid;                                      /* 02h */
+    U8      Status;                                     /* 03h */
+    U32     SenseDataListLength;                        /* 04h */
+    U32     PktFailuresListLength;                      /* 08h */
+    U8      SenseData[52]; /* Pad the IU to 64 bytes */ /* 0Ch */
+} MPI_TARGET_SCSI_SPI_STATUS_IU, MPI_POINTER PTR_MPI_TARGET_SCSI_SPI_STATUS_IU,
+  TargetScsiSpiStatusIU_t, MPI_POINTER pTargetScsiSpiStatusIU_t;
 
 /****************************************************************************/
 /* Target Mode Abort Request                                                */
@@ -324,6 +368,41 @@ typedef struct _MSG_TARGET_MODE_ABORT_REPLY
                                     (((p) << TARGET_MODE_REPLY_PORT_SHIFT) &   \
                                                   TARGET_MODE_REPLY_PORT_MASK))
 
+/* the following obsolete values are for MPI v1.0 support */
+#define TARGET_MODE_REPLY_0100_MASK_HOST_INDEX       (0x000003FF)
+#define TARGET_MODE_REPLY_0100_SHIFT_HOST_INDEX      (0)
+#define TARGET_MODE_REPLY_0100_MASK_IOC_INDEX        (0x001FF800)
+#define TARGET_MODE_REPLY_0100_SHIFT_IOC_INDEX       (11)
+#define TARGET_MODE_REPLY_0100_PORT_MASK             (0x00400000)
+#define TARGET_MODE_REPLY_0100_PORT_SHIFT            (22)
+#define TARGET_MODE_REPLY_0100_MASK_INITIATOR_INDEX  (0x1F800000)
+#define TARGET_MODE_REPLY_0100_SHIFT_INITIATOR_INDEX (23)
+
+#define GET_HOST_INDEX_0100(x) (((x) & TARGET_MODE_REPLY_0100_MASK_HOST_INDEX) \
+                                  >> TARGET_MODE_REPLY_0100_SHIFT_HOST_INDEX)
+
+#define SET_HOST_INDEX_0100(t, hi)                                             \
+            ((t) = ((t) & ~TARGET_MODE_REPLY_0100_MASK_HOST_INDEX) |           \
+                         (((hi) << TARGET_MODE_REPLY_0100_SHIFT_HOST_INDEX) &  \
+                                      TARGET_MODE_REPLY_0100_MASK_HOST_INDEX))
+
+#define GET_IOC_INDEX_0100(x)   (((x) & TARGET_MODE_REPLY_0100_MASK_IOC_INDEX) \
+                                  >> TARGET_MODE_REPLY_0100_SHIFT_IOC_INDEX)
+
+#define SET_IOC_INDEX_0100(t, ii)                                              \
+            ((t) = ((t) & ~TARGET_MODE_REPLY_0100_MASK_IOC_INDEX) |            \
+                        (((ii) << TARGET_MODE_REPLY_0100_SHIFT_IOC_INDEX) &    \
+                                     TARGET_MODE_REPLY_0100_MASK_IOC_INDEX))
+
+#define GET_INITIATOR_INDEX_0100(x)                                            \
+            (((x) & TARGET_MODE_REPLY_0100_MASK_INITIATOR_INDEX)               \
+                              >> TARGET_MODE_REPLY_0100_SHIFT_INITIATOR_INDEX)
+
+#define SET_INITIATOR_INDEX_0100(t, ii)                                        \
+        ((t) = ((t) & ~TARGET_MODE_REPLY_0100_MASK_INITIATOR_INDEX) |          \
+                   (((ii) << TARGET_MODE_REPLY_0100_SHIFT_INITIATOR_INDEX) &   \
+                                TARGET_MODE_REPLY_0100_MASK_INITIATOR_INDEX))
+
 
 #endif
 
index 733dec74c6d80b791ea8202a06d306202056e6c0..22d454d0642737750bf3069c73ccbd6280237474 100644 (file)
@@ -6,7 +6,7 @@
  *          Title:  MPI Basic type definitions
  *  Creation Date:  June 6, 2000
  *
- *    MPI Version:  01.01.02
+ *    MPI Version:  01.02.01
  *
  *  Version History
  *  ---------------
@@ -17,6 +17,7 @@
  *  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.
+ *  08-08-01  01.02.01  Original release for v1.2 work.
  *  --------------------------------------------------------------------------
  */
 
index fd7b1515ac3b271a15722320a6b0d15307e3ac64..a92f816b716845248421fa13c7ad68f3d984a9f4 100644 (file)
  *      And to Roger Hickerson (LSI Logic) for tirelessly supporting
  *      this driver project.
  *
+ *      A special thanks to Pamela Delaney (LSI Logic) for tons of work
+ *      and countless enhancements while adding support for the 1030
+ *      chip family.  Pam has been instrumental in the development of
+ *      of the 2.xx.xx series fusion drivers, and her contributions are
+ *      far too numerous to hope to list in one place.
+ *
  *      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,
  *      for gobs of hard work fixing and optimizing LAN code.
  *      THANK YOU!
  *
- *  Copyright (c) 1999-2001 LSI Logic Corporation
+ *  Copyright (c) 1999-2002 LSI Logic Corporation
  *  Originally By: Steven J. Ralston
- *  (mailto:Steve.Ralston@lsil.com)
+ *  (mailto:sjralston1@netscape.net)
+ *  (mailto:Pam.Delaney@lsil.com)
  *
- *  $Id: mptbase.c,v 1.53.4.3 2001/09/18 03:54:54 sralston Exp $
+ *  $Id: mptbase.c,v 1.119 2002/06/20 13:28:15 pdelaney Exp $
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
 #include <linux/kdev_t.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
-#include <linux/proc_fs.h>
+#include <linux/interrupt.h>           /* needed for in_interrupt() proto */
 #include <asm/io.h>
 #ifdef CONFIG_MTRR
 #include <asm/mtrr.h>
 #endif
+#ifdef __sparc__
+#include <asm/irq.h>                   /* needed for __irq_itoa() proto */
+#endif
 
 #include "mptbase.h"
 
@@ -110,27 +120,33 @@ MODULE_AUTHOR(MODULEAUTHOR);
 MODULE_DESCRIPTION(my_NAME);
 MODULE_LICENSE("GPL");
 
-
 /*
  *  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;
+
+#ifdef MFCNT
+static int mfcounter = 0;
+#define PRINT_MF_COUNT 20000
+#endif
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
  *  Public data...
  */
-int mpt_lan_index = 0;
-int mpt_stm_index = 0;
+int mpt_lan_index = -1;
+int mpt_stm_index = -1;
+
+struct proc_dir_entry *mpt_proc_root_dir;
+
+DmpServices_t *DmpService;
+
+void *mpt_v_ASCQ_TablePtr;
+const char **mpt_ScsiOpcodesPtr;
+int mpt_ASCQ_TableSz;
 
-void *mpt_v_ASCQ_TablePtr = NULL;
-const char **mpt_ScsiOpcodesPtr = NULL;
-int mpt_ASCQ_TableSz = 0;
 
 #define WHOINIT_UNKNOWN                0xAA
 
@@ -139,12 +155,12 @@ int mpt_ASCQ_TableSz = 0;
  *  Private data...
  */
                                        /* Adapter lookup table */
-static MPT_ADAPTER             *mpt_adapters[MPT_MAX_ADAPTERS] = {0};
+       MPT_ADAPTER             *mpt_adapters[MPT_MAX_ADAPTERS];
 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];
+static int                      MptDriverClass[MPT_MAX_PROTOCOL_DRIVERS];
                                        /* Event handler lookup table */
 static MPT_EVHANDLER            MptEvHandlers[MPT_MAX_PROTOCOL_DRIVERS];
                                        /* Reset handler lookup table */
@@ -152,6 +168,10 @@ static MPT_RESETHANDLER             MptResetHandlers[MPT_MAX_PROTOCOL_DRIVERS];
 
 static int     FusionInitCalled = 0;
 static int     mpt_base_index = -1;
+static int     last_drv_idx = -1;
+static int     isense_idx = -1;
+
+static DECLARE_WAIT_QUEUE_HEAD(mpt_waitq);
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -160,48 +180,83 @@ static int        mpt_base_index = -1;
 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_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason);
-static int     mpt_adapter_install(struct pci_dev *pdev);
-static void    mpt_detect_929_bound_ports(MPT_ADAPTER *this, struct pci_dev *pdev);
+static int     mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag);
+static int     mpt_adapter_install(struct pci_dev *pdev);
+static void    mpt_detect_bound_ports(MPT_ADAPTER *this, struct pci_dev *pdev);
 static void    mpt_adapter_disable(MPT_ADAPTER *ioc, int freeup);
 static void    mpt_adapter_dispose(MPT_ADAPTER *ioc);
 
 static void    MptDisplayIocCapabilities(MPT_ADAPTER *ioc);
-static int     MakeIocReady(MPT_ADAPTER *ioc, int force);
-static u32     GetIocState(MPT_ADAPTER *ioc, int cooked);
-static int     GetIocFacts(MPT_ADAPTER *ioc);
-static int     GetPortFacts(MPT_ADAPTER *ioc, int portnum);
-static int     SendIocInit(MPT_ADAPTER *ioc);
-static int     SendPortEnable(MPT_ADAPTER *ioc, int portnum);
-static int     mpt_fc9x9_reset(MPT_ADAPTER *ioc, int ignore);
-static int     KickStart(MPT_ADAPTER *ioc, int ignore);
-static int     SendIocReset(MPT_ADAPTER *ioc, u8 reset_type);
+static int     MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag);
+//static u32   mpt_GetIocState(MPT_ADAPTER *ioc, int cooked);
+static int     GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason);
+static int     GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
+static int     SendIocInit(MPT_ADAPTER *ioc, int sleepFlag);
+static int     SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
+static int     mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag);
+static int     mpt_downloadboot(MPT_ADAPTER *ioc, int sleepFlag);
+static int     mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
+static int     KickStart(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
+static int     SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag);
 static int     PrimeIocFifos(MPT_ADAPTER *ioc);
-static int     HandShakeReqAndReply(MPT_ADAPTER *ioc, int reqBytes, u32 *req, int replyBytes, u16 *u16reply, int maxwait);
-static int     WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong);
-static int     WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong);
-static int     WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong);
+static int     WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
+static int     WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
+static int     WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
 static int     GetLanConfigPages(MPT_ADAPTER *ioc);
+static int     GetFcPortPage0(MPT_ADAPTER *ioc, int portnum);
+static int     GetIoUnitPage2(MPT_ADAPTER *ioc);
+static int     mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum);
+static int     mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum);
+static int     mpt_findImVolumes(MPT_ADAPTER *ioc);
+static void    mpt_timer_expired(unsigned long data);
 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_create(void);
 static int     procmpt_destroy(void);
+static int     procmpt_summary_read(char *buf, char **start, off_t offset,
+                               int request, int *eof, void *data);
+static int     procmpt_version_read(char *buf, char **start, off_t offset,
+                               int request, int *eof, void *data);
+static int     procmpt_iocinfo_read(char *buf, char **start, off_t offset,
+                               int request, int *eof, void *data);
 #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 void    mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc);
 
+//int          mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag);
 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);
 static void    fusion_exit(void);
 
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *  more Private data...
+ */
+#ifdef CONFIG_PROC_FS
+struct _mpt_proc_list {
+       const char      *name;
+       int             (*f)(char *, char **, off_t, int, int *, void *);
+} mpt_proc_list[] = {
+       { "summary", procmpt_summary_read},
+       { "version", procmpt_version_read},
+};
+#define MPT_PROC_ENTRIES (sizeof(mpt_proc_list)/sizeof(mpt_proc_list[0]))
+
+struct _mpt_ioc_proc_list {
+       const char      *name;
+       int             (*f)(char *, char **, off_t, int, int *, void *);
+} mpt_ioc_proc_list[] = {
+       { "info", procmpt_iocinfo_read},
+       { "summary", procmpt_summary_read},
+};
+#define MPT_IOC_PROC_ENTRIES (sizeof(mpt_ioc_proc_list)/sizeof(mpt_ioc_proc_list[0]))
+
+#endif
+
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /* 20000207 -sralston
  *  GRRRRR...  IOSpace (port i/o) register access (for the 909) is back!
@@ -225,9 +280,18 @@ static inline void CHIPREG_WRITE32(volatile u32 *a, u32 v)
                writel(v, a);
 }
 
+static inline void CHIPREG_PIO_WRITE32(volatile u32 *a, u32 v)
+{
+       outl(v, (unsigned long)a);
+}
+
+static inline u32 CHIPREG_PIO_READ32(volatile u32 *a)
+{
+       return inl((unsigned long)a);
+}
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/**
+/*
  *     mpt_interrupt - MPT adapter (IOC) specific interrupt handler.
  *     @irq: irq number (not used)
  *     @bus_id: bus identifier cookie == pointer to MPT_ADAPTER structure
@@ -252,8 +316,7 @@ mpt_interrupt(int irq, void *bus_id, struct pt_regs *r)
        MPT_FRAME_HDR   *mf;
        MPT_FRAME_HDR   *mr;
        u32              pa;
-       u32             *m;
-       int              req_idx;
+       int              req_idx = -1;
        int              cb_idx;
        int              type;
        int              freeme;
@@ -261,6 +324,21 @@ mpt_interrupt(int irq, void *bus_id, struct pt_regs *r)
 
        ioc = bus_id;
 
+       /*
+        * Verify ioc pointer is ok
+        */
+       {
+               MPT_ADAPTER     *iocCmp;
+               iocCmp = mpt_adapter_find_first();
+               while ((ioc != iocCmp)  && iocCmp)
+                       iocCmp = mpt_adapter_find_next(iocCmp);
+
+               if (!iocCmp) {
+                       printk(KERN_WARNING "mpt_interrupt: Invalid ioc!\n");
+                       return;
+               }
+       }
+
        /*
         *  Drain the reply FIFO!
         *
@@ -281,25 +359,27 @@ mpt_interrupt(int irq, void *bus_id, struct pt_regs *r)
                 *  Check for non-TURBO reply!
                 */
                if (pa & MPI_ADDRESS_REPLY_A_BIT) {
-                       dma_addr_t reply_dma_addr;
+                       u32 reply_dma_low;
                        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));
+                       /* Map DMA address of reply header to cpu address.
+                        * pa is 32 bits - but the dma address may be 32 or 64 bits
+                        * get offset based only only the low addresses
+                        */
+                       reply_dma_low = (pa = (pa << 1));
+                       mr = (MPT_FRAME_HDR *)((u8 *)ioc->reply_frames +
+                                        (reply_dma_low - ioc->reply_frames_low_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",
+                       dprintk((MYIOC_s_INFO_FMT "Got non-TURBO reply=%p\n",
                                        ioc->name, mr));
                        DBG_DUMP_REPLY_FRAME(mr)
 
@@ -307,7 +387,7 @@ mpt_interrupt(int irq, void *bus_id, struct pt_regs *r)
                         *  Check/log IOC log info
                         */
                        ioc_stat = le16_to_cpu(mr->u.reply.IOCStatus);
-                       if (ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
+                       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);
@@ -318,7 +398,7 @@ mpt_interrupt(int irq, void *bus_id, struct pt_regs *r)
                        /*
                         *  Process turbo (context) reply...
                         */
-                       dirqprintk((KERN_INFO MYNAM ": %s: Got TURBO reply(=%08x)\n", ioc->name, pa));
+                       dirqprintk((MYIOC_s_INFO_FMT "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;
@@ -357,6 +437,34 @@ mpt_interrupt(int irq, void *bus_id, struct pt_regs *r)
                        pa = 0;                                 /* No reply flush! */
                }
 
+               if ((int)ioc->chip_type > (int)FC929) {
+                       /* Verify mf, mf are reasonable.
+                        */
+                       if ((mf) && ((mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))
+                               || (mf < ioc->req_frames)) ) {
+                               printk(MYIOC_s_WARN_FMT 
+                                       "mpt_interrupt: Invalid mf (%p) req_idx (%d)!\n", ioc->name, (void *)mf, req_idx);
+                               cb_idx = 0;
+                               pa = 0;
+                               freeme = 0;
+                       }
+                       if ((pa) && (mr) && ((mr >= MPT_INDEX_2_RFPTR(ioc, ioc->req_depth))
+                               || (mr < ioc->reply_frames)) ) {
+                               printk(MYIOC_s_WARN_FMT 
+                                       "mpt_interrupt: Invalid rf (%p)!\n", ioc->name, (void *)mr);
+                               cb_idx = 0;
+                               pa = 0;
+                               freeme = 0;
+                       }
+                       if (cb_idx > (MPT_MAX_PROTOCOL_DRIVERS-1)) {
+                               printk(MYIOC_s_WARN_FMT 
+                                       "mpt_interrupt: Invalid cb_idx (%d)!\n", ioc->name, cb_idx);
+                               cb_idx = 0;
+                               pa = 0;
+                               freeme = 0;
+                       }
+               }
+
                /*  Check for (valid) IO callback!  */
                if (cb_idx) {
                        /*  Do the callback!  */
@@ -374,15 +482,18 @@ mpt_interrupt(int irq, void *bus_id, struct pt_regs *r)
                        /*  Put Request back on FreeQ!  */
                        spin_lock_irqsave(&ioc->FreeQlock, flags);
                        Q_ADD_TAIL(&ioc->FreeQ, &mf->u.frame.linkage, MPT_FRAME_HDR);
+#ifdef MFCNT
+                       ioc->mfcnt--;
+#endif
                        spin_unlock_irqrestore(&ioc->FreeQlock, flags);
                }
 
                count++;
-               dirqprintk((KERN_INFO MYNAM ": %s: ISR processed frame #%d\n", ioc->name, count));
+               dirqprintk((MYIOC_s_INFO_FMT "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.",
+                       dirqprintk((MYIOC_s_INFO_FMT "ISR processed %d replies.",
                                        ioc->name, count));
                        dirqprintk((" Giving this ISR a break!\n"));
                        return;
@@ -409,17 +520,17 @@ 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));
+       dprintk((MYIOC_s_INFO_FMT "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);
+               printk(MYIOC_s_ERR_FMT "NULL or BAD request frame ptr! (=%p)\n",
+                               ioc->name, (void *)mf);
                return 1;
        }
 
        if (reply == NULL) {
-               dprintk((KERN_ERR MYNAM ": %s: ERROR - Unexpected NULL Event (turbo?) reply!\n",
+               dprintk((MYIOC_s_ERR_FMT "Unexpected NULL Event (turbo?) reply!\n",
                                ioc->name));
                return 1;
        }
@@ -430,7 +541,7 @@ mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply)
        }
 
        func = reply->u.hdr.Function;
-       dprintk((KERN_INFO MYNAM ": %s: mpt_base_reply, Function=%02Xh\n",
+       dprintk((MYIOC_s_INFO_FMT "mpt_base_reply, Function=%02Xh\n",
                        ioc->name, func));
 
        if (func == MPI_FUNCTION_EVENT_NOTIFICATION) {
@@ -441,30 +552,77 @@ mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply)
                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",
+                       dprintk((MYIOC_s_WARN_FMT "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.
+                *      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",
+               dprintk((MYIOC_s_INFO_FMT "mpt_base_reply, EventAck reply received\n",
                                ioc->name));
+       } else if (func == MPI_FUNCTION_CONFIG) {
+               CONFIGPARMS *pCfg;
+               unsigned long flags;
+
+               dprintk((MYIOC_s_INFO_FMT "config_complete (mf=%p,mr=%p)\n",
+                               ioc->name, mf, reply));
+
+               pCfg = * ((CONFIGPARMS **)((u8 *) mf + ioc->req_sz - sizeof(void *)));
+
+               if (pCfg) {
+                       /* disable timer and remove from linked list */
+                       del_timer(&pCfg->timer);
+
+                       spin_lock_irqsave(&ioc->FreeQlock, flags);
+                       Q_DEL_ITEM(&pCfg->linkage);
+                       spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+
+                       /*
+                        *      If IOC Status is SUCCESS, save the header
+                        *      and set the status code to GOOD.
+                        */
+                       pCfg->status = MPT_CONFIG_ERROR;
+                       if (reply) {
+                               ConfigReply_t   *pReply = (ConfigReply_t *)reply;
+                               u16              status;
+
+                               status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
+                               dprintk((KERN_NOTICE "  IOCStatus=%04xh, IOCLogInfo=%08xh\n",
+                                    status, le32_to_cpu(pReply->IOCLogInfo)));
+
+                               pCfg->status = status;
+                               if (status == MPI_IOCSTATUS_SUCCESS) {
+                                       pCfg->hdr->PageVersion = pReply->Header.PageVersion;
+                                       pCfg->hdr->PageLength = pReply->Header.PageLength;
+                                       pCfg->hdr->PageNumber = pReply->Header.PageNumber;
+                                       pCfg->hdr->PageType = pReply->Header.PageType;
+                               }
+                       }
+
+                       /*
+                        *      Wake up the original calling thread
+                        */
+                       pCfg->wait_done = 1;
+                       wake_up(&mpt_waitq);
+               }
        } else {
-               printk(KERN_ERR MYNAM ": %s: ERROR - Unexpected msg function (=%02Xh) reply received!\n",
+               printk(MYIOC_s_ERR_FMT "Unexpected msg function (=%02Xh) reply received!\n",
                                ioc->name, func);
        }
 
        /*
-        *  Conditionally tell caller to free the original
-        *  EventNotification/EventAck/unexpected request frame!
+        *      Conditionally tell caller to free the original
+        *      EventNotification/EventAck/unexpected request frame!
         */
        return freereq;
 }
@@ -480,21 +638,22 @@ mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply)
  *     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.
+ *     NOTES: The SCSI protocol driver currently calls this routine thrice
+ *     in order to register separate callbacks; one for "normal" SCSI IO;
+ *     one for MptScsiTaskMgmt requests; one for Scan/DV requests.
  *
  *     Returns a positive integer valued "handle" in the
- *     range (and S.O.D. order) {7,6,...,1} if successful.
+ *     range (and S.O.D. order) {N,...,7,6,5,...,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;
 
+       last_drv_idx = -1;
+
 #ifndef MODULE
        /*
         *  Handle possibility of the mptscsih_detect() routine getting
@@ -512,7 +671,7 @@ mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass)
 #endif
 
        /*
-        *  Search for empty callback slot in this order: {7,6,...,1}
+        *  Search for empty callback slot in this order: {N,...,7,6,5,...,1}
         *  (slot/handle 0 is reserved!)
         */
        for (i = MPT_MAX_PROTOCOL_DRIVERS-1; i; i--) {
@@ -520,7 +679,7 @@ mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass)
                        MptCallbacks[i] = cbfunc;
                        MptDriverClass[i] = dclass;
                        MptEvHandlers[i] = NULL;
-                       r = i;
+                       last_drv_idx = i;
                        if (cbfunc != mpt_base_reply) {
                                MOD_INC_USE_COUNT;
                        }
@@ -528,7 +687,7 @@ mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass)
                }
        }
 
-       return r;
+       return last_drv_idx;
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -546,6 +705,11 @@ mpt_deregister(int cb_idx)
                MptCallbacks[cb_idx] = NULL;
                MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
                MptEvHandlers[cb_idx] = NULL;
+
+               last_drv_idx++;
+               if (isense_idx != -1 && isense_idx <= cb_idx)
+                       isense_idx++;
+
                if (cb_idx != mpt_base_index) {
                        MOD_DEC_USE_COUNT;
                }
@@ -639,7 +803,8 @@ mpt_reset_deregister(int cb_idx)
  *     @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.
+ *     Returns pointer to a MPT request frame or %NULL if none are available
+ *     or IOC is not active.
  */
 MPT_FRAME_HDR*
 mpt_get_msg_frame(int handle, int iocid)
@@ -650,6 +815,16 @@ mpt_get_msg_frame(int handle, int iocid)
 
        /* validate handle and ioc identifier */
        iocp = mpt_adapters[iocid];
+
+#ifdef MFCNT
+       if (!iocp->active)
+               printk(KERN_WARNING "IOC Not Active! mpt_get_msg_frame returning NULL!\n");
+#endif
+
+       /* If interrupts are not attached, do not return a request frame */
+       if (!iocp->active)
+               return NULL;
+
        spin_lock_irqsave(&iocp->FreeQlock, flags);
        if (! Q_IS_EMPTY(&iocp->FreeQ)) {
                int req_offset;
@@ -662,8 +837,20 @@ mpt_get_msg_frame(int handle, int iocid)
                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 MFCNT
+               iocp->mfcnt++;
+#endif
        }
        spin_unlock_irqrestore(&iocp->FreeQlock, flags);
+
+#ifdef MFCNT
+       if (mf == NULL)
+               printk(KERN_WARNING "IOC Active. No free Msg Frames! Count 0x%x Max 0x%x\n", iocp->mfcnt, iocp->req_depth);
+       mfcounter++;
+       if (mfcounter == PRINT_MF_COUNT)
+               printk(KERN_INFO "MF Count 0x%x Max 0x%x \n", iocp->mfcnt, iocp->req_depth);
+#endif
+
        dmfprintk((KERN_INFO MYNAM ": %s: mpt_get_msg_frame(%d,%d), got mf=%p\n",
                        iocp->name, handle, iocid, mf));
        return mf;
@@ -687,7 +874,7 @@ mpt_put_msg_frame(int handle, int iocid, MPT_FRAME_HDR *mf)
 
        iocp = mpt_adapters[iocid];
        if (iocp != NULL) {
-               dma_addr_t mf_dma_addr;
+               u32 mf_dma_addr;
                int req_offset;
 
                /* ensure values are reset properly! */
@@ -700,23 +887,23 @@ mpt_put_msg_frame(int handle, int iocid, MPT_FRAME_HDR *mf)
 #ifdef MPT_DEBUG_MSG_FRAME
                {
                        u32     *m = mf->u.frame.hwhdr.__hdr;
-                       int      i, n;
+                       int      ii, 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))
+                       for (ii=0; ii<=n; ii++) {
+                               if (ii && ((ii%8)==0))
                                        printk("\n" KERN_INFO " ");
-                               printk(" %08x", le32_to_cpu(m[i]));
+                               printk(" %08x", le32_to_cpu(m[ii]));
                        }
                        printk("\n");
                }
 #endif
 
-               mf_dma_addr = iocp->req_frames_dma + req_offset;
+               mf_dma_addr = iocp->req_frames_low_dma + req_offset;
                CHIPREG_WRITE32(&iocp->chip->RequestFifo, mf_dma_addr);
        }
 }
@@ -742,10 +929,77 @@ mpt_free_msg_frame(int handle, int iocid, MPT_FRAME_HDR *mf)
                /*  Put Request back on FreeQ!  */
                spin_lock_irqsave(&iocp->FreeQlock, flags);
                Q_ADD_TAIL(&iocp->FreeQ, &mf->u.frame.linkage, MPT_FRAME_HDR);
+#ifdef MFCNT
+               iocp->mfcnt--;
+#endif
                spin_unlock_irqrestore(&iocp->FreeQlock, flags);
        }
 }
 
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mpt_add_sge - Place a simple SGE at address pAddr.
+ *     @pAddr: virtual address for SGE
+ *     @flagslength: SGE flags and data transfer length
+ *     @dma_addr: Physical address 
+ *
+ *     This routine places a MPT request frame back on the MPT adapter's
+ *     FreeQ.
+ */
+void
+mpt_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr)
+{
+       if (sizeof(dma_addr_t) == sizeof(u64)) {
+               SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
+               u32 tmp = dma_addr & 0xFFFFFFFF;
+
+               pSge->FlagsLength = cpu_to_le32(flagslength);
+               pSge->Address.Low = cpu_to_le32(tmp);
+               tmp = (u32) ((u64)dma_addr >> 32);
+               pSge->Address.High = cpu_to_le32(tmp);
+
+       } else {
+               SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
+               pSge->FlagsLength = cpu_to_le32(flagslength);
+               pSge->Address = cpu_to_le32(dma_addr);
+       }
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mpt_add_chain - Place a chain SGE at address pAddr.
+ *     @pAddr: virtual address for SGE
+ *     @next: nextChainOffset value (u32's)
+ *     @length: length of next SGL segment
+ *     @dma_addr: Physical address 
+ *
+ *     This routine places a MPT request frame back on the MPT adapter's
+ *     FreeQ.
+ */
+void
+mpt_add_chain(char *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
+{
+       if (sizeof(dma_addr_t) == sizeof(u64)) {
+               SGEChain64_t *pChain = (SGEChain64_t *) pAddr;
+               u32 tmp = dma_addr & 0xFFFFFFFF;
+
+               pChain->Length = cpu_to_le16(length);
+               pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size(); 
+
+               pChain->NextChainOffset = next;
+
+               pChain->Address.Low = cpu_to_le32(tmp);
+               tmp = (u32) ((u64)dma_addr >> 32);
+               pChain->Address.High = cpu_to_le32(tmp);
+       } else {
+               SGEChain32_t *pChain = (SGEChain32_t *) pAddr;
+               pChain->Length = cpu_to_le16(length);
+               pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size();
+               pChain->NextChainOffset = next;
+               pChain->Address = cpu_to_le32(dma_addr);
+       }
+}
+
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *     mpt_send_handshake_request - Send MPT request via doorbell
@@ -754,8 +1008,9 @@ mpt_free_msg_frame(int handle, int iocid, MPT_FRAME_HDR *mf)
  *     @iocid: IOC unique identifier (integer)
  *     @reqBytes: Size of the request in bytes
  *     @req: Pointer to MPT request frame
+ *     @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
  *
- *     This routine is used exclusively by mptscsih to send MptScsiTaskMgmt
+ *     This routine is used exclusively 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
@@ -764,41 +1019,30 @@ mpt_free_msg_frame(int handle, int iocid, MPT_FRAME_HDR *mf)
  *     Returns 0 for success, non-zero for failure.
  */
 int
-mpt_send_handshake_request(int handle, int iocid, int reqBytes, u32 *req)
+mpt_send_handshake_request(int handle, int iocid, int reqBytes, u32 *req, int sleepFlag)
 {
        MPT_ADAPTER     *iocp;
        int              r = 0;
 
        iocp = mpt_adapters[iocid];
        if (iocp != NULL) {
-               u8              *req_as_bytes;
-               u32              ioc_raw_state;
-               int              i;
+               u8      *req_as_bytes;
+               int      ii;
 
-               /* YIKES!  We already know something is amiss.
-                * Do upfront check on IOC state.
+               /* State is known to be good upon entering
+                * this function so issue the bus reset
+                * request.
                 */
-               ioc_raw_state = GetIocState(iocp, 0);
-               if ((ioc_raw_state & MPI_DOORBELL_ACTIVE) ||
-                   ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL)) {
-                       printk(KERN_WARNING MYNAM ": %s: Bad IOC state (%08x) WARNING!\n",
-                                       iocp->name, ioc_raw_state);
-                       if ((r = mpt_do_ioc_recovery(iocp, MPT_HOSTEVENT_IOC_RECOVER)) != 0) {
-                               printk(KERN_WARNING MYNAM ": WARNING - (%d) Cannot recover %s\n",
-                                               r, iocp->name);
-                               return r;
-                       }
-               }
 
                /*
                 * 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) {
+               ii = MFPTR_2_MPT_INDEX(iocp,(MPT_FRAME_HDR*)req);
+               if (reqBytes >= 12 && ii >= 0 && ii < 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.req_idx = cpu_to_le16(ii);
                        mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle;
                }
 
@@ -810,36 +1054,40 @@ mpt_send_handshake_request(int handle, int iocid, int reqBytes, u32 *req)
                                 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
 
                /* Wait for IOC doorbell int */
-               if ((i = WaitForDoorbellInt(iocp, 2)) < 0) {
-                       return i;
+               if ((ii = WaitForDoorbellInt(iocp, 2, sleepFlag)) < 0) {
+                       return ii;
                }
 
+               /* Read doorbell and check for active bit */
+               if (!(CHIPREG_READ32(&iocp->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
+                               return -5;
+
                dhsprintk((KERN_INFO MYNAM ": %s: mpt_send_handshake_request start, WaitCnt=%d\n",
-                               iocp->name, i));
+                               iocp->name, ii));
 
                CHIPREG_WRITE32(&iocp->chip->IntStatus, 0);
 
-               if ((r = WaitForDoorbellAck(iocp, 1)) < 0) {
+               if ((r = WaitForDoorbellAck(iocp, 1, sleepFlag)) < 0) {
                        return -2;
                }
 
                /* Send request via doorbell handshake */
                req_as_bytes = (u8 *) req;
-               for (i = 0; i < reqBytes/4; i++) {
+               for (ii = 0; ii < reqBytes/4; ii++) {
                        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));
+                       word = ((req_as_bytes[(ii*4) + 0] <<  0) |
+                               (req_as_bytes[(ii*4) + 1] <<  8) |
+                               (req_as_bytes[(ii*4) + 2] << 16) |
+                               (req_as_bytes[(ii*4) + 3] << 24));
                        CHIPREG_WRITE32(&iocp->chip->Doorbell, word);
-                       if ((r = WaitForDoorbellAck(iocp, 1)) < 0) {
+                       if ((r = WaitForDoorbellAck(iocp, 1, sleepFlag)) < 0) {
                                r = -3;
                                break;
                        }
                }
 
-               if ((r = WaitForDoorbellInt(iocp, 2)) >= 0)
+               if (r >= 0 && WaitForDoorbellInt(iocp, 10, sleepFlag) >= 0)
                        r = 0;
                else
                        r = -4;
@@ -871,8 +1119,8 @@ mpt_adapter_find_first(void)
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
- *     mpt_adapter_find_next - Find next MPT adapter pointer.
- *     @prev: Pointer to previous MPT adapter
+ *     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.
  */
@@ -888,13 +1136,13 @@ mpt_adapter_find_next(MPT_ADAPTER *prev)
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/**
+/*
  *     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
+static int __init
 mpt_pci_scan(void)
 {
        struct pci_dev *pdev;
@@ -906,7 +1154,7 @@ mpt_pci_scan(void)
        dprintk((KERN_INFO MYNAM ": Checking for MPT adapters...\n"));
 
        /*
-        *  NOTE: The 929 (I believe) will appear as 2 separate PCI devices,
+        *  NOTE: The 929, 929X and 1030 will appear as 2 separate PCI devices,
         *  one for each channel.
         */
        pci_for_each_dev(pdev) {
@@ -917,9 +1165,11 @@ mpt_pci_scan(void)
                if ((pdev->device != MPI_MANUFACTPAGE_DEVICEID_FC909) &&
                    (pdev->device != MPI_MANUFACTPAGE_DEVICEID_FC929) &&
                    (pdev->device != MPI_MANUFACTPAGE_DEVICEID_FC919) &&
+                   (pdev->device != MPI_MANUFACTPAGE_DEVICEID_FC929X) &&
+                   (pdev->device != MPI_MANUFACTPAGE_DEVICEID_FC919X) &&
+                   (pdev->device != MPI_MANUFACTPAGE_DEVID_53C1030) &&
 #if 0
                    /* FIXME! C103x family */
-                   (pdev->device != MPI_MANUFACTPAGE_DEVID_53C1030) &&
                    (pdev->device != MPI_MANUFACTPAGE_DEVID_53C1030_ZC) &&
                    (pdev->device != MPI_MANUFACTPAGE_DEVID_53C1035) &&
 #endif
@@ -929,7 +1179,7 @@ mpt_pci_scan(void)
                }
 
                /* GRRRRR
-                * 929 dual function devices may be presented in Func 1,0 order,
+                * dual function devices (929, 929X, 1030) 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...
                 */
@@ -937,11 +1187,11 @@ mpt_pci_scan(void)
                        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->device == pdev->device) &&
                            (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));
+                                       pdev2->bus->number, pdev2->devfn, pdev2->class, pdev2->device));
                                found++;
                                if ((r = mpt_adapter_install(pdev2)) == 0)
                                        count++;
@@ -969,9 +1219,7 @@ mpt_pci_scan(void)
        }
 
 #ifdef CONFIG_PROC_FS
-       if (procmpt_create() != 0)
-               printk(KERN_WARNING MYNAM ": WARNING! - %s creation failed!\n",
-                               MPT_PROCFS_MPTBASEDIR);
+       (void) procmpt_create();
 #endif
 
        return count;
@@ -1004,7 +1252,7 @@ mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp)
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/**
+/*
  *     mpt_adapter_install - Install a PCI intelligent MPT adapter.
  *     @pdev: Pointer to pci_dev structure
  *
@@ -1024,57 +1272,91 @@ 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;
-       int              i;
+       int              ii;
        int              r = -ENODEV;
-       int              len;
+       u64              mask = 0xffffffffffffffff;
 
-       ioc = kmalloc(sizeof(MPT_ADAPTER), GFP_KERNEL);
+       if (pci_enable_device(pdev))
+               return r;
+
+       if (!pci_set_dma_mask(pdev, mask)) {
+               dprintk((KERN_INFO MYNAM 
+                       ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n"));
+       } else if (pci_set_dma_mask(pdev, (u64) 0xffffffff)) {
+               printk(KERN_WARNING MYNAM ": 32 BIT PCI BUS DMA ADDRESSING NOT SUPPORTED\n");
+               return r;
+       }
+
+       ioc = kmalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC);
        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->req_sz = MPT_DEFAULT_FRAME_SIZE;           /* avoid div by zero! */
+       ioc->reply_sz = ioc->req_sz;
 
        ioc->pcidev = pdev;
+       ioc->diagPending = 0;
+       spin_lock_init(&ioc->diagLock);
+
+       /* Initialize the event logging.
+        */
+       ioc->eventTypes = 0;    /* None */
+       ioc->eventContext = 0;
+       ioc->eventLogSize = 0;
+       ioc->events = NULL;
+
+#ifdef MFCNT
+       ioc->mfcnt = 0;
+#endif
+
+       ioc->cached_fw = NULL;
+
+       /* Initilize SCSI Config Data structure
+        */
+       memset(&ioc->spi_data, 0, sizeof(ScsiCfgData));
+
+       /* Initialize the running configQ head.
+        */
+       Q_INIT(&ioc->configQ, Q_ITEM);
 
        /* Find lookup slot. */
-       for (i=0; i < MPT_MAX_ADAPTERS; i++) {
-               if (mpt_adapters[i] == NULL) {
-                       ioc->id = i           /* Assign adapter unique id (lookup) */
+       for (ii=0; ii < MPT_MAX_ADAPTERS; ii++) {
+               if (mpt_adapters[ii] == NULL) {
+                       ioc->id = ii;           /* Assign adapter unique id (lookup) */
                        break;
                }
        }
-       if (i == MPT_MAX_ADAPTERS) {
-               printk(KERN_ERR MYNAM ": ERROR - mpt_adapters[%d] table overflow!\n", i);
+       if (ii == MPT_MAX_ADAPTERS) {
+               printk(KERN_ERR MYNAM ": ERROR - mpt_adapters[%d] table overflow!\n", ii);
                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) {
+       for (ii=0; ii < DEVICE_COUNT_RESOURCE; ii++) {
+               if (pdev->PCI_BASEADDR_FLAGS(ii) & PCI_BASE_ADDRESS_SPACE_IO) {
                        /* Get I/O space! */
-                       port = pdev->PCI_BASEADDR_START(i);
-                       psize = PCI_BASEADDR_SIZE(pdev,i);
+                       port = pdev->PCI_BASEADDR_START(ii);
+                       psize = PCI_BASEADDR_SIZE(pdev,ii);
                } else {
                        /* Get memmap */
-                       mem_phys = pdev->PCI_BASEADDR_START(i);
-                       msize = PCI_BASEADDR_SIZE(pdev,i);
+                       mem_phys = pdev->PCI_BASEADDR_START(ii);
+                       msize = PCI_BASEADDR_SIZE(pdev,ii);
                        break;
                }
        }
        ioc->mem_size = msize;
 
-       if (i == DEVICE_COUNT_RESOURCE) {
+       if (ii == DEVICE_COUNT_RESOURCE) {
                printk(KERN_ERR MYNAM ": ERROR - MPT adapter has no memory regions defined!\n");
                kfree(ioc);
                return -EINVAL;
@@ -1098,6 +1380,8 @@ mpt_adapter_install(struct pci_dev *pdev)
        }
        dprintk((KERN_INFO MYNAM ": mem = %p, mem_phys = %lx\n", mem, mem_phys));
 
+       dprintk((KERN_INFO MYNAM ": facts @ %p, pfacts[0] @ %p\n",
+                       &ioc->facts, &ioc->pfacts[0]));
        if (PortIo) {
                u8 *pmem = (u8*)port;
                ioc->mem_phys = port;
@@ -1107,6 +1391,13 @@ mpt_adapter_install(struct pci_dev *pdev)
                ioc->chip = (SYSIF_REGS*)mem;
        }
 
+       /* Save Port IO values incase we need to do downloadboot */
+       {
+               u8 *pmem = (u8*)port;
+               ioc->pio_mem_phys = port;
+               ioc->pio_chip = (SYSIF_REGS*)pmem;
+       }
+
        ioc->chip_type = FCUNK;
        if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC909) {
                ioc->chip_type = FC909;
@@ -1120,17 +1411,29 @@ mpt_adapter_install(struct pci_dev *pdev)
                ioc->chip_type = FC919;
                ioc->prod_name = "LSIFC919";
        }
-#if 0
-       else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_53C1030) {
+       else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC929X) {
+               ioc->chip_type = FC929X;
+               ioc->prod_name = "LSIFC929X";
+       }
+       else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC919X) {
+               ioc->chip_type = FC919X;
+               ioc->prod_name = "LSIFC919X";
+       }
+       else if (pdev->device == MPI_MANUFACTPAGE_DEVID_53C1030) {
                ioc->chip_type = C1030;
                ioc->prod_name = "LSI53C1030";
+               {
+                       /* 1030 Chip Fix. Disable Split transactions
+                        * for PCIX. Set bits 4 - 6 to zero.
+                        */
+                       u16 pcixcmd = 0;
+                       pci_read_config_word(pdev, 0x6a, &pcixcmd);
+                       pcixcmd &= 0xFF8F;
+                       pci_write_config_word(pdev, 0x6a, pcixcmd);
+               }
        }
-#endif
 
-       myname = "iocN";
-       len = strlen(myname);
-       memcpy(ioc->name, myname, len+1);
-       ioc->name[len-1] = '0' + ioc->id;
+       sprintf(ioc->name, "ioc%d", ioc->id);
 
        Q_INIT(&ioc->FreeQ, MPT_FRAME_HDR);
        spin_lock_init(&ioc->FreeQlock);
@@ -1145,8 +1448,13 @@ mpt_adapter_install(struct pci_dev *pdev)
                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",
+#ifndef __sparc__
+                       printk(MYIOC_s_ERR_FMT "Unable to allocate interrupt %d!\n",
                                        ioc->name, pdev->irq);
+#else
+                       printk(MYIOC_s_ERR_FMT "Unable to allocate interrupt %s!\n",
+                                       ioc->name, __irq_itoa(pdev->irq));
+#endif
                        iounmap(mem);
                        kfree(ioc);
                        return -EBUSY;
@@ -1156,7 +1464,11 @@ mpt_adapter_install(struct pci_dev *pdev)
 
                pci_set_master(pdev);                   /* ?? */
 
+#ifndef __sparc__
                dprintk((KERN_INFO MYNAM ": %s installed at interrupt %d\n", ioc->name, pdev->irq));
+#else
+               dprintk((KERN_INFO MYNAM ": %s installed at interrupt %s\n", ioc->name, __irq_itoa(pdev->irq)));
+#endif
        }
 
        /* tack onto tail of our MPT adapter list */
@@ -1166,12 +1478,12 @@ mpt_adapter_install(struct pci_dev *pdev)
        mpt_adapters[ioc->id] = ioc;
 
        /* NEW!  20010220 -sralston
-        * Check for "929 bound ports" to reduce redundant resets.
+        * Check for "bound ports" (929, 929X, 1030) to reduce redundant resets.
         */
-       if (ioc->chip_type == FC929)
-               mpt_detect_929_bound_ports(ioc, pdev);
+       if ((ioc->chip_type == FC929) || (ioc->chip_type == C1030) || (ioc->chip_type == FC929X))
+               mpt_detect_bound_ports(ioc, pdev);
 
-       if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP)) != 0) {
+       if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP, CAN_SLEEP)) != 0) {
                printk(KERN_WARNING MYNAM ": WARNING - %s did not initialize properly! (%d)\n",
                                ioc->name, r);
        }
@@ -1180,10 +1492,11 @@ mpt_adapter_install(struct pci_dev *pdev)
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/**
+/*
  *     mpt_do_ioc_recovery - Initialize or recover MPT adapter.
  *     @ioc: Pointer to MPT adapter structure
  *     @reason: Event word / reason
+ *     @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
  *
  *     This routine performs all the steps necessary to bring the IOC
  *     to a OPERATIONAL state.
@@ -1191,16 +1504,21 @@ mpt_adapter_install(struct pci_dev *pdev)
  *     This routine also pre-fetches the LAN MAC address of a Fibre Channel
  *     MPT adapter.
  *
- *     Returns 0 for success.
+ *     Returns:
+ *              0 for success
+ *             -1 if failed to get board READY
+ *             -2 if READY but IOCFacts Failed
+ *             -3 if READY but PrimeIOCFifos Failed
+ *             -4 if READY but IOCInit Failed
  */
 static int
-mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason)
+mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
 {
        int      hard_reset_done = 0;
        int      alt_ioc_ready = 0;
        int      hard;
        int      r;
-       int      i;
+       int      ii;
        int      handlers;
 
        printk(KERN_INFO MYNAM ": Initiating %s %s\n",
@@ -1211,156 +1529,106 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason)
        ioc->active = 0;
        /* NOTE: Access to IOC's request FreeQ is now blocked! */
 
-// FIXME? Cleanup all IOC requests here! (or below?)
-// But watch out for event associated request?
+       if (ioc->alt_ioc) {
+               /* Disable alt-IOC's reply interrupts for a bit ... */
+               CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, 0xFFFFFFFF);
+               ioc->alt_ioc->active = 0;
+               /* NOTE: Access to alt-IOC's request FreeQ is now blocked! */
+       }
 
-       hard = HardReset;
-       if (ioc->alt_ioc && (reason == MPT_HOSTEVENT_IOC_BRINGUP))
+       hard = 1;
+       if (reason == MPT_HOSTEVENT_IOC_BRINGUP)
                hard = 0;
 
-       if ((hard_reset_done = MakeIocReady(ioc, hard)) < 0) {
+       if ((hard_reset_done = MakeIocReady(ioc, hard, sleepFlag)) < 0) {
                printk(KERN_WARNING MYNAM ": %s NOT READY WARNING!\n",
                                ioc->name);
                return -1;
        }
 
-// NEW!
-#if 0                                          // Kiss-of-death!?!
-       if (ioc->alt_ioc) {
-// Grrr... Hold off any alt-IOC interrupts (and events) while
-// handshaking to <this> IOC, needed because?
-               /* Disable alt-IOC's reply interrupts for a bit ... */
-               alt_ioc_intmask = CHIPREG_READ32(&ioc->alt_ioc->chip->IntMask);
-               CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, 0xFFFFFFFF);
-               ioc->alt_ioc->active = 0;
-               /* NOTE: Access to alt-IOC's request FreeQ is now blocked! */
-       }
-#endif
-
+       /* hard_reset_done = 0 if a soft reset was performed
+        * and 1 if a hard reset was performed.
+        */
        if (hard_reset_done && ioc->alt_ioc) {
-               if ((r = MakeIocReady(ioc->alt_ioc, 0)) == 0)
+               if ((r = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0)
                        alt_ioc_ready = 1;
                else
-                       printk(KERN_WARNING MYNAM ": alt-%s: (%d) Not ready WARNING!\n",
+                       printk(KERN_WARNING MYNAM
+                                       ": alt-%s: (%d) Not ready WARNING!\n",
                                        ioc->alt_ioc->name, r);
        }
 
+       /* Get IOC facts! */
+       if ((r = GetIocFacts(ioc, sleepFlag, reason)) != 0)
+               return -2;
        if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
-               /* Get IOC facts! */
-               if ((r = GetIocFacts(ioc)) != 0)
-                       return -2;
                MptDisplayIocCapabilities(ioc);
        }
 
-       /*
-        * Call each currently registered protocol IOC reset handler
-        * with pre-reset indication.
-        * NOTE: If we're doing _IOC_BRINGUP, there can be no
-        * MptResetHandlers[] registered yet.
-        */
-       if (hard_reset_done) {
-               r = handlers = 0;
-               for (i=MPT_MAX_PROTOCOL_DRIVERS-1; i; i--) {
-                       if (MptResetHandlers[i]) {
-                               dprintk((KERN_INFO MYNAM ": %s: Calling IOC pre_reset handler #%d\n",
-                                               ioc->name, i));
-                               r += (*(MptResetHandlers[i]))(ioc, MPT_IOC_PRE_RESET);
-                               handlers++;
-
-                               if (alt_ioc_ready) {
-                                       dprintk((KERN_INFO MYNAM ": %s: Calling alt-IOC pre_reset handler #%d\n",
-                                                       ioc->alt_ioc->name, i));
-                                       r += (*(MptResetHandlers[i]))(ioc->alt_ioc, MPT_IOC_PRE_RESET);
-                                       handlers++;
-                               }
-                       }
-               }
-               /* FIXME?  Examine results here? */
-       }
-
-       // May need to check/upload firmware & data here!
-
-       if ((r = SendIocInit(ioc)) != 0)
-               return -3;
-// NEW!
        if (alt_ioc_ready) {
-               if ((r = SendIocInit(ioc->alt_ioc)) != 0) {
-                       alt_ioc_ready = 0;
-                       printk(KERN_WARNING MYNAM ": alt-%s: (%d) init failure WARNING!\n",
-                                       ioc->alt_ioc->name, r);
-               }
-       }
-
-       /*
-        * Call each currently registered protocol IOC reset handler
-        * with post-reset indication.
-        * NOTE: If we're doing _IOC_BRINGUP, there can be no
-        * MptResetHandlers[] registered yet.
-        */
-       if (hard_reset_done) {
-               r = handlers = 0;
-               for (i=MPT_MAX_PROTOCOL_DRIVERS-1; i; i--) {
-                       if (MptResetHandlers[i]) {
-                               dprintk((KERN_INFO MYNAM ": %s: Calling IOC post_reset handler #%d\n",
-                                               ioc->name, i));
-                               r += (*(MptResetHandlers[i]))(ioc, MPT_IOC_POST_RESET);
-                               handlers++;
-
-                               if (alt_ioc_ready) {
-                                       dprintk((KERN_INFO MYNAM ": %s: Calling alt-IOC post_reset handler #%d\n",
-                                                       ioc->alt_ioc->name, i));
-                                       r += (*(MptResetHandlers[i]))(ioc->alt_ioc, MPT_IOC_POST_RESET);
-                                       handlers++;
-                               }
-                       }
+               if ((r = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0)
+                       return -2;
+               if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
+                       MptDisplayIocCapabilities(ioc->alt_ioc);
                }
-               /* FIXME?  Examine results here? */
        }
 
        /*
         * Prime reply & request queues!
-        * (mucho alloc's)
+        * (mucho alloc's) Must be done prior to
+        * init as upper addresses are needed for init.
         */
        if ((r = PrimeIocFifos(ioc)) != 0)
+               return -3;
+
+       // May need to check/upload firmware & data here!
+       if ((r = SendIocInit(ioc, sleepFlag)) != 0)
                return -4;
 // NEW!
        if (alt_ioc_ready && ((r = PrimeIocFifos(ioc->alt_ioc)) != 0)) {
                printk(KERN_WARNING MYNAM ": alt-%s: (%d) FIFO mgmt alloc WARNING!\n",
                                ioc->alt_ioc->name, r);
+               alt_ioc_ready = 0;
        }
 
-// FIXME! Cleanup all IOC (and alt-IOC?) requests here!
+       if (alt_ioc_ready) {
+               if ((r = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) {
+                       alt_ioc_ready = 0;
+                       printk(KERN_WARNING MYNAM
+                               ": alt-%s: (%d) init failure WARNING!\n",
+                                       ioc->alt_ioc->name, r);
+               }
+       }
 
-       if ((ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) &&
-           (ioc->lan_cnfg_page0.Header.PageLength == 0)) {
-               /*
-                *  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] ));
+       if (reason == MPT_HOSTEVENT_IOC_BRINGUP){
+               if (ioc->upload_fw) {
+                       dprintk((MYIOC_s_INFO_FMT
+                               "firmware upload required!\n", ioc->name));
+
+                       r = mpt_do_upload(ioc, sleepFlag);
+                       if (r != 0)
+                               printk(KERN_WARNING MYNAM ": firmware upload failure!\n");
+                       /* Handle the alt IOC too */
+                       if ((alt_ioc_ready) && (ioc->alt_ioc->upload_fw)){
+                               r = mpt_do_upload(ioc->alt_ioc, sleepFlag);
+                               if (r != 0)
+                                       printk(KERN_WARNING MYNAM ": firmware upload failure!\n");
+                       }
                }
-#endif
        }
 
+
        /* Enable! (reply interrupt) */
        CHIPREG_WRITE32(&ioc->chip->IntMask, ~(MPI_HIM_RIM));
        ioc->active = 1;
 
-// NEW!
-#if 0                                          // Kiss-of-death!?!
-       if (alt_ioc_ready && (r==0)) {
+       if (ioc->alt_ioc) {
                /* (re)Enable alt-IOC! (reply interrupt) */
                dprintk((KERN_INFO MYNAM ": alt-%s reply irq re-enabled\n",
                                ioc->alt_ioc->name));
                CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, ~(MPI_HIM_RIM));
                ioc->alt_ioc->active = 1;
        }
-#endif
 
        /* NEW!  20010120 -sralston
         *  Enable MPT base driver management of EventNotification
@@ -1368,46 +1636,122 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason)
         */
        if (!ioc->facts.EventState)
                (void) SendEventNotification(ioc, 1);   /* 1=Enable EventNotification */
-// NEW!
-// FIXME!?!
-//     if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState) {
-//             (void) SendEventNotification(ioc->alt_ioc, 1);  /* 1=Enable EventNotification */
-//     }
 
-       return 0;
-}
+       if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState)
+               (void) SendEventNotification(ioc->alt_ioc, 1);  /* 1=Enable EventNotification */
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*
- *     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;
+       /* (Bugzilla:fibrebugs, #513)
+        * Bug fix (part 2)!  20010905 -sralston
+        *      Add additional "reason" check before call to GetLanConfigPages
+        *      (combined with GetIoUnitPage2 call).  This prevents a somewhat
+        *      recursive scenario; GetLanConfigPages times out, timer expired
+        *      routine calls HardResetHandler, which calls into here again,
+        *      and we try GetLanConfigPages again...
+        */
+       if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
+               if ((int)ioc->chip_type <= (int)FC929) {
+                       /*
+                        *  Pre-fetch FC port WWN and stuff...
+                        *  (FCPortPage0_t stuff)
+                        */
+                       for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {
+                               (void) GetFcPortPage0(ioc, ii);
+                       }
 
-       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));
+                       if ((ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) &&
+                           (ioc->lan_cnfg_page0.Header.PageLength == 0)) {
+                               /*
+                                *  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((MYIOC_s_INFO_FMT "LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
+                                                       ioc->name, a[5], a[4], a[3], a[2], a[1], a[0] ));
+                               }
+#endif
+                       }
+               } else {
+                       /* Get NVRAM and adapter maximums from SPP 0 and 2
+                        */
+                       mpt_GetScsiPortSettings(ioc, 0);
 
-       while (ioc_srch != NULL) {
-               struct pci_dev *_pcidev = ioc_srch->pcidev;
+                       /* Get version and length of SDP 1 
+                        */
+                       mpt_readScsiDevicePageHeaders(ioc, 0);
 
-               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);
+                       /* Find IM volumes 
+                        */
+                       if (ioc->facts.MsgVersion >= 0x0102)
+                               mpt_findImVolumes(ioc);
+               }
+
+               GetIoUnitPage2(ioc);
+       }
+
+       /*
+        * Call each currently registered protocol IOC reset handler
+        * with post-reset indication.
+        * NOTE: If we're doing _IOC_BRINGUP, there can be no
+        * MptResetHandlers[] registered yet.
+        */
+       if (hard_reset_done) {
+               r = handlers = 0;
+               for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
+                       if (MptResetHandlers[ii]) {
+                               dprintk((MYIOC_s_INFO_FMT "Calling IOC post_reset handler #%d\n",
+                                               ioc->name, ii));
+                               r += (*(MptResetHandlers[ii]))(ioc, MPT_IOC_POST_RESET);
+                               handlers++;
+
+                               if (alt_ioc_ready) {
+                                       dprintk((MYIOC_s_INFO_FMT "Calling alt-%s post_reset handler #%d\n",
+                                                       ioc->name, ioc->alt_ioc->name, ii));
+                                       r += (*(MptResetHandlers[ii]))(ioc->alt_ioc, MPT_IOC_POST_RESET);
+                                       handlers++;
+                               }
+                       }
+               }
+               /* FIXME?  Examine results here? */
+       }
+
+       return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     mpt_detect_bound_ports - Search for PCI bus/dev_function
+ *     which matches PCI bus/dev_function (+/-1) for newly discovered 929,
+ *     929X or 1030.
+ *     @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_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((MYIOC_s_INFO_FMT "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 == pdev->device) &&
+                   (_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",
@@ -1418,8 +1762,6 @@ mpt_detect_929_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
                                        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);
@@ -1440,10 +1782,10 @@ mpt_adapter_disable(MPT_ADAPTER *this, int freeup)
                u32 state;
 
                /* Disable the FW */
-               state = GetIocState(this, 1);
+               state = mpt_GetIocState(this, 1);
                if (state == MPI_IOC_STATE_OPERATIONAL) {
-                       if (SendIocReset(this, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET) != 0)
-                               (void) KickStart(this, 1);
+                       if (SendIocReset(this, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, NO_SLEEP) != 0)
+                               (void) KickStart(this, 1, NO_SLEEP);
                }
 
                /* Disable adapter interrupts! */
@@ -1475,12 +1817,52 @@ mpt_adapter_disable(MPT_ADAPTER *this, int freeup)
                }
 
                if (freeup && this->sense_buf_pool != NULL) {
-                       sz = (this->req_depth * 256);
+                       sz = (this->req_depth * MPT_SENSE_BUFFER_ALLOC);
                        pci_free_consistent(this->pcidev, sz,
                                        this->sense_buf_pool, this->sense_buf_pool_dma);
                        this->sense_buf_pool = NULL;
                        this->alloc_total -= sz;
                }
+
+               if (freeup && this->events != NULL){
+                       sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS);
+                       kfree(this->events);
+                       this->events = NULL;
+                       this->alloc_total -= sz;
+               }
+
+               if (freeup && this->cached_fw != NULL) {
+                       int ii = 0;
+
+                       while ((ii < this->num_fw_frags) && (this->cached_fw[ii]!= NULL)) {
+                               sz = this->cached_fw[ii]->size;
+                               pci_free_consistent(this->pcidev, sz,
+                                       this->cached_fw[ii]->fw, this->cached_fw[ii]->fw_dma);
+                               this->cached_fw[ii]->fw = NULL;
+                               this->alloc_total -= sz;
+
+                               kfree(this->cached_fw[ii]);
+                               this->cached_fw[ii] = NULL;
+                               this->alloc_total -= sizeof(fw_image_t);
+
+                               ii++;
+                       }
+
+                       kfree(this->cached_fw);
+                       this->cached_fw = NULL;
+                       sz = this->num_fw_frags * sizeof(void *);
+                       this->alloc_total -= sz;
+               }
+
+               if (freeup && this->spi_data.nvram != NULL) {
+                       kfree(this->spi_data.nvram);
+                       this->spi_data.nvram = NULL;
+               }
+
+               if (freeup && this->spi_data.pIocPg3 != NULL) {
+                       kfree(this->spi_data.pIocPg3);
+                       this->spi_data.pIocPg3 = NULL;
+               }
        }
 }
 
@@ -1575,23 +1957,30 @@ MptDisplayIocCapabilities(MPT_ADAPTER *ioc)
 /*
  *     MakeIocReady - Get IOC to a READY state, using KickStart if needed.
  *     @ioc: Pointer to MPT_ADAPTER structure
- *     @kick: Force hard KickStart of IOC
+ *     @force: Force hard KickStart of IOC
+ *     @sleepFlag: Specifies whether the process can sleep
  *
- *     Returns 0 for already-READY, 1 for hard reset success,
- *     else negative for failure.
+ *     Returns:
+ *              1 - DIAG reset and READY
+ *              0 - READY initially OR soft reset and READY 
+ *             -1 - Any failure on KickStart 
+ *             -2 - Msg Unit Reset Failed
+ *             -3 - IO Unit Reset Failed
+ *             -4 - IOC owned by a PEER
  */
 static int
-MakeIocReady(MPT_ADAPTER *ioc, int force)
+MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
 {
        u32      ioc_state;
        int      statefault = 0;
-       int      cntdn;
+       int      cntdn;
        int      hard_reset_done = 0;
        int      r;
-       int      i;
+       int      ii;
+       int      whoinit;
 
        /* Get current [raw] IOC state  */
-       ioc_state = GetIocState(ioc, 0);
+       ioc_state = mpt_GetIocState(ioc, 0);
        dhsprintk((KERN_INFO MYNAM "::MakeIocReady, %s [raw] state=%08x\n", ioc->name, ioc_state));
 
        /*
@@ -1600,7 +1989,7 @@ MakeIocReady(MPT_ADAPTER *ioc, int force)
         */
        if (ioc_state & MPI_DOORBELL_ACTIVE) {
                statefault = 1;
-               printk(KERN_WARNING MYNAM ": %s: Uh-oh, unexpected doorbell active!\n",
+               printk(MYIOC_s_WARN_FMT "Unexpected doorbell active!\n",
                                ioc->name);
        }
 
@@ -1613,7 +2002,7 @@ MakeIocReady(MPT_ADAPTER *ioc, int force)
         */
        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",
+               printk(MYIOC_s_WARN_FMT "IOC is in FAULT state!!!\n",
                                ioc->name);
                printk(KERN_WARNING "           FAULT code = %04xh\n",
                                ioc_state & MPI_DOORBELL_DATA_MASK);
@@ -1623,28 +2012,49 @@ MakeIocReady(MPT_ADAPTER *ioc, int force)
         *      Hmmm...  Did it get left operational?
         */
        if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL) {
-               statefault = 3;
-               dprintk((KERN_WARNING MYNAM ": %s: Hmmm... IOC operational unexpected\n",
+               dprintk((MYIOC_s_WARN_FMT "IOC operational unexpected\n",
                                ioc->name));
+
+               /* Check WhoInit.
+                * If PCI Peer, exit.
+                * Else, if no fault conditions are present, issue a MessageUnitReset
+                * Else, fall through to KickStart case
+                */
+               whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT;
+               dprintk((KERN_WARNING MYNAM
+                       ": whoinit 0x%x\n statefault %d force %d\n",
+                       whoinit, statefault, force));
+               if (whoinit == MPI_WHOINIT_PCI_PEER)
+                       return -4;
+               else {
+                       if ((statefault == 0 ) && (force == 0)) {
+                               if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) == 0)
+                                       return 0;
+                       }
+                       statefault = 3;
+               }
        }
 
-       hard_reset_done = KickStart(ioc, statefault||force);
+       hard_reset_done = KickStart(ioc, statefault||force, sleepFlag);
        if (hard_reset_done < 0)
                return -1;
 
        /*
         *  Loop here waiting for IOC to come READY.
         */
-       i = 0;
+       ii = 0;
        cntdn = HZ * 15;
-       while ((ioc_state = GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
+       if (sleepFlag != CAN_SLEEP)
+               cntdn *= 10;    /* 1500 iterations @ 1msec per */
+
+       while ((ioc_state = mpt_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.
                         */
-                       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);
+                       if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) != 0) {
+                               printk(MYIOC_s_ERR_FMT "IOC msg unit reset failed!\n", ioc->name);
                                return -2;
                        }
                } else if (ioc_state == MPI_IOC_STATE_RESET) {
@@ -1652,25 +2062,30 @@ MakeIocReady(MPT_ADAPTER *ioc, int force)
                         *  Something is wrong.  Try to get IOC back
                         *  to a known state.
                         */
-                       if ((r = SendIocReset(ioc, MPI_FUNCTION_IO_UNIT_RESET)) != 0) {
-                               printk(KERN_ERR MYNAM ": %s: ERROR - IO unit reset failed!\n", ioc->name);
+                       if ((r = SendIocReset(ioc, MPI_FUNCTION_IO_UNIT_RESET, sleepFlag)) != 0) {
+                               printk(MYIOC_s_ERR_FMT "IO unit reset failed!\n", ioc->name);
                                return -3;
                        }
                }
 
-               i++; cntdn--;
+               ii++; cntdn--;
                if (!cntdn) {
-                       printk(KERN_ERR MYNAM ": %s: ERROR - Wait IOC_READY state timeout(%d)!\n",
-                                       ioc->name, (i+5)/HZ);
+                       printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n",
+                                       ioc->name, (ii+5)/HZ);
                        return -ETIME;
                }
 
-               current->state = TASK_INTERRUPTIBLE;
-               schedule_timeout(1);
+               if (sleepFlag == CAN_SLEEP) {
+                       set_current_state(TASK_INTERRUPTIBLE);
+                       schedule_timeout(1);
+               } else {
+                       mdelay (1);     /* 1 msec delay */
+               }
+
        }
 
        if (statefault < 3) {
-               printk(KERN_WARNING MYNAM ": %s: Whew!  Recovered from %s\n",
+               printk(MYIOC_s_INFO_FMT "Recovered from %s\n",
                                ioc->name,
                                statefault==1 ? "stuck handshake" : "IOC FAULT");
        }
@@ -1680,21 +2095,21 @@ MakeIocReady(MPT_ADAPTER *ioc, int force)
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
- *     GetIocState - Get the current state of a MPT adapter.
+ *     mpt_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
+mpt_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));
+//     dprintk((MYIOC_s_INFO_FMT "raw state = %08x\n", ioc->name, s));
        sc = s & MPI_IOC_STATE_MASK;
 
        /*  Save!  */
@@ -1707,11 +2122,13 @@ GetIocState(MPT_ADAPTER *ioc, int cooked)
 /*
  *     GetIocFacts - Send IOCFacts request to MPT adapter.
  *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @sleepFlag: Specifies whether the process can sleep
+ *     @reason: If recovery, only update facts.
  *
  *     Returns 0 for success, non-zero for failure.
  */
 static int
-GetIocFacts(MPT_ADAPTER *ioc)
+GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
 {
        IOCFacts_t               get_facts;
        IOCFactsReply_t         *facts;
@@ -1741,14 +2158,13 @@ GetIocFacts(MPT_ADAPTER *ioc)
        get_facts.Function = MPI_FUNCTION_IOC_FACTS;
        /* Assert: All other get_facts fields are zero! */
 
-       dprintk((KERN_INFO MYNAM ": %s: Sending get IocFacts request\n", ioc->name));
+       dprintk((MYIOC_s_INFO_FMT "Sending get IocFacts request\n", ioc->name));
 
        /* 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, 3);
+       r = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_facts,
+                       reply_sz, (u16*)facts, 3 /*seconds*/, sleepFlag);
        if (r != 0)
                return r;
 
@@ -1761,14 +2177,17 @@ GetIocFacts(MPT_ADAPTER *ioc)
         */
        /* Did we get a valid reply? */
        if (facts->MsgLength > offsetof(IOCFactsReply_t, RequestFrameSize)/sizeof(u32)) {
-               /*
-                * If not been here, done that, save off first WhoInit value
-                */
-               if (ioc->FirstWhoInit == WHOINIT_UNKNOWN)
-                       ioc->FirstWhoInit = facts->WhoInit;
+               if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
+                       /*
+                        * If not been here, done that, save off first WhoInit value
+                        */
+                       if (ioc->FirstWhoInit == WHOINIT_UNKNOWN)
+                               ioc->FirstWhoInit = facts->WhoInit;
+               }
 
                facts->MsgVersion = le16_to_cpu(facts->MsgVersion);
                facts->MsgContext = le32_to_cpu(facts->MsgContext);
+               facts->IOCExceptions = le16_to_cpu(facts->IOCExceptions);
                facts->IOCStatus = le16_to_cpu(facts->IOCStatus);
                facts->IOCLogInfo = le32_to_cpu(facts->IOCLogInfo);
                status = facts->IOCStatus & MPI_IOCSTATUS_MASK;
@@ -1776,7 +2195,23 @@ GetIocFacts(MPT_ADAPTER *ioc)
 
                facts->ReplyQueueDepth = le16_to_cpu(facts->ReplyQueueDepth);
                facts->RequestFrameSize = le16_to_cpu(facts->RequestFrameSize);
-               facts->FWVersion = le16_to_cpu(facts->FWVersion);
+
+               /*
+                * FC f/w version changed between 1.1 and 1.2 
+                *      Old: u16{Major(4),Minor(4),SubMinor(8)}
+                *      New: u32{Major(8),Minor(8),Unit(8),Dev(8)}
+                */
+               if (facts->MsgVersion < 0x0102) {
+                       /*
+                        *      Handle old FC f/w style, convert to new...
+                        */
+                       u16      oldv = le16_to_cpu(facts->Reserved_0101_FWVersion);
+                       facts->FWVersion.Word =
+                                       ((oldv<<12) & 0xFF000000) |
+                                       ((oldv<<8)  & 0x000FFF00);
+               } else
+                       facts->FWVersion.Word = le32_to_cpu(facts->FWVersion.Word);
+
                facts->ProductID = le16_to_cpu(facts->ProductID);
                facts->CurrentHostMfaHighAddr =
                                le32_to_cpu(facts->CurrentHostMfaHighAddr);
@@ -1791,52 +2226,42 @@ GetIocFacts(MPT_ADAPTER *ioc)
                 * 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) {
+               if (facts->MsgLength >= (offsetof(IOCFactsReply_t,FWImageSize) + 7)/4 &&
+                   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 {
+               if (!facts->RequestFrameSize) {
                        /*  Something is wrong!  */
-                       printk(KERN_ERR MYNAM ": %s: ERROR - IOC reported invalid 0 request size!\n",
+                       printk(MYIOC_s_ERR_FMT "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",
+               if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
+                       /*
+                        * Set values for this IOC's request & reply frame sizes,
+                        * and request & reply queue depths...
+                        */
+                       ioc->req_sz = MIN(MPT_DEFAULT_FRAME_SIZE, facts->RequestFrameSize * 4);
+                       ioc->req_depth = MIN(MPT_MAX_REQ_DEPTH, facts->GlobalCredits);
+                       ioc->reply_sz = ioc->req_sz;
+                       ioc->reply_depth = MIN(MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth);
+
+                       /* 1030 - should we use a smaller DEFAULT_REPLY_DEPTH?
+                        * FIX
+                        */
+                       dprintk((MYIOC_s_INFO_FMT "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",
+                       dprintk((MYIOC_s_INFO_FMT "req_sz  =%3d, req_depth  =%4d\n",
                                ioc->name, ioc->req_sz, ioc->req_depth));
 
-               /* Get port facts! */
-               if ( (r = GetPortFacts(ioc, 0)) != 0 )
-                       return r;
+                       /* Get port facts! */
+                       if ( (r = GetPortFacts(ioc, 0, sleepFlag)) != 0 )
+                               return r;
+               }
        } else {
-               printk(KERN_ERR MYNAM ": %s: ERROR - Invalid IOC facts reply!\n",
+               printk(MYIOC_s_ERR_FMT "Invalid IOC facts reply!\n",
                                ioc->name);
                return -66;
        }
@@ -1849,15 +2274,16 @@ GetIocFacts(MPT_ADAPTER *ioc)
  *     GetPortFacts - Send PortFacts request to MPT adapter.
  *     @ioc: Pointer to MPT_ADAPTER structure
  *     @portnum: Port number
+ *     @sleepFlag: Specifies whether the process can sleep
  *
  *     Returns 0 for success, non-zero for failure.
  */
 static int
-GetPortFacts(MPT_ADAPTER *ioc, int portnum)
+GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
 {
        PortFacts_t              get_pfacts;
        PortFactsReply_t        *pfacts;
-       int                      i;
+       int                      ii;
        int                      req_sz;
        int                      reply_sz;
 
@@ -1883,16 +2309,16 @@ GetPortFacts(MPT_ADAPTER *ioc, int portnum)
        get_pfacts.PortNumber = portnum;
        /* Assert: All other get_pfacts fields are zero! */
 
-       dprintk((KERN_INFO MYNAM ": %s: Sending get PortFacts(%d) request\n",
+       dprintk((MYIOC_s_INFO_FMT "Sending get PortFacts(%d) request\n",
                        ioc->name, portnum));
 
        /* 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, 3);
-       if (i != 0)
-               return i;
+       ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_pfacts,
+                               reply_sz, (u16*)pfacts, 3 /*seconds*/, sleepFlag);
+       if (ii != 0)
+               return ii;
 
        /* Did we get a valid reply? */
 
@@ -1914,13 +2340,14 @@ GetPortFacts(MPT_ADAPTER *ioc, int portnum)
 /*
  *     SendIocInit - Send IOCInit request to MPT adapter.
  *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @sleepFlag: Specifies whether the process can sleep
  *
  *     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)
+SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
 {
        IOCInit_t                ioc_init;
        MPIDefaultReply_t        init_reply;
@@ -1937,20 +2364,47 @@ SendIocInit(MPT_ADAPTER *ioc)
        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;
+       /* If we are in a recovery mode and we uploaded the FW image,
+        * then this pointer is not NULL. Skip the upload a second time.
+        * Set this flag if cached_fw set for either IOC.
+        */
+       ioc->upload_fw = 0;
+       ioc_init.Flags = 0;
+       if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT) {
+               if ((ioc->cached_fw) || (ioc->alt_ioc && ioc->alt_ioc->cached_fw))
+                       ioc_init.Flags = MPI_IOCINIT_FLAGS_DISCARD_FW_IMAGE;
+               else 
+                       ioc->upload_fw = 1;
+       }
+
+       if ((int)ioc->chip_type <= (int)FC929) {
+               ioc_init.MaxDevices = MPT_MAX_FC_DEVICES;
+       } else {
+               ioc_init.MaxDevices = MPT_MAX_SCSI_DEVICES;
+       }
+       ioc_init.MaxBuses = MPT_MAX_BUS;
 
 /*     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));
+       if (sizeof(dma_addr_t) == sizeof(u64)) {
+               /* Save the upper 32-bits of the request
+                * (reply) and sense buffers.
+                */
+               ioc_init.HostMfaHighAddr = cpu_to_le32((u32)((u64)ioc->req_frames_dma >> 32));
+               ioc_init.SenseBufferHighAddr = cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32));
+       } else {
+               /* Force 32-bit addressing */
+               ioc_init.HostMfaHighAddr = cpu_to_le32(0);
+               ioc_init.SenseBufferHighAddr = cpu_to_le32(0);
+       }
+
+       dprintk((MYIOC_s_INFO_FMT "Sending IOCInit (req @ %p)\n",
+                       ioc->name, &ioc_init));
 
-       r = HandShakeReqAndReply(ioc, sizeof(IOCInit_t), (u32*)&ioc_init,
-                       sizeof(MPIDefaultReply_t), (u16*)&init_reply, 10);
+       r = mpt_handshake_req_reply_wait(ioc, sizeof(IOCInit_t), (u32*)&ioc_init,
+                               sizeof(MPIDefaultReply_t), (u16*)&init_reply, 10 /*seconds*/, sleepFlag);
        if (r != 0)
                return r;
 
@@ -1958,7 +2412,7 @@ SendIocInit(MPT_ADAPTER *ioc)
         * since we don't even look at it's contents.
         */
 
-       if ((r = SendPortEnable(ioc, 0)) != 0)
+       if ((r = SendPortEnable(ioc, 0, sleepFlag)) != 0)
                return r;
 
        /* YIKES!  SUPER IMPORTANT!!!
@@ -1967,21 +2421,27 @@ SendIocInit(MPT_ADAPTER *ioc)
         */
        count = 0;
        cntdn = HZ * 60;                                        /* chg'd from 30 to 60 seconds */
-       state = GetIocState(ioc, 1);
+       if (sleepFlag != CAN_SLEEP)
+               cntdn *= 10;                                    /* scale for 1msec delays */
+       state = mpt_GetIocState(ioc, 1);
        while (state != MPI_IOC_STATE_OPERATIONAL && --cntdn) {
-               current->state = TASK_INTERRUPTIBLE;
-               schedule_timeout(1);
+               if (sleepFlag == CAN_SLEEP) {
+                       set_current_state(TASK_INTERRUPTIBLE);
+                       schedule_timeout(1);
+               } else {
+                       mdelay(1);
+               }
 
                if (!cntdn) {
-                       printk(KERN_ERR MYNAM ": %s: ERROR - Wait IOC_OP state timeout(%d)!\n",
+                       printk(MYIOC_s_ERR_FMT "Wait IOC_OP state timeout(%d)!\n",
                                        ioc->name, (count+5)/HZ);
                        return -9;
                }
 
-               state = GetIocState(ioc, 1);
+               state = mpt_GetIocState(ioc, 1);
                count++;
        }
-       dhsprintk((KERN_INFO MYNAM ": %s: INFO - Wait IOC_OPERATIONAL state (cnt=%d)\n",
+       dhsprintk((MYIOC_s_INFO_FMT "INFO - Wait IOC_OPERATIONAL state (cnt=%d)\n",
                        ioc->name, count));
 
        return r;
@@ -1992,17 +2452,18 @@ SendIocInit(MPT_ADAPTER *ioc)
  *     SendPortEnable - Send PortEnable request to MPT adapter port.
  *     @ioc: Pointer to MPT_ADAPTER structure
  *     @portnum: Port number to enable
+ *     @sleepFlag: Specifies whether the process can sleep
  *
  *     Send PortEnable to bring IOC to OPERATIONAL state.
  *
  *     Returns 0 for success, non-zero for failure.
  */
 static int
-SendPortEnable(MPT_ADAPTER *ioc, int portnum)
+SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
 {
        PortEnable_t             port_enable;
        MPIDefaultReply_t        reply_buf;
-       int      i;
+       int      ii;
        int      req_sz;
        int      reply_sz;
 
@@ -2019,13 +2480,21 @@ SendPortEnable(MPT_ADAPTER *ioc, int portnum)
 /*     port_enable.MsgFlags = 0;               */
 /*     port_enable.MsgContext = 0;             */
 
-       dprintk((KERN_INFO MYNAM ": %s: Sending Port(%d)Enable (req @ %p)\n",
+       dprintk((MYIOC_s_INFO_FMT "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, 65);
-       if (i != 0)
-               return i;
+       /* RAID FW may take a long time to enable
+        */
+       if ((int)ioc->chip_type <= (int)FC929) {
+               ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&port_enable,
+                               reply_sz, (u16*)&reply_buf, 65 /*seconds*/, sleepFlag);
+       } else {
+               ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&port_enable,
+                               reply_sz, (u16*)&reply_buf, 300 /*seconds*/, sleepFlag);
+       }
+
+       if (ii != 0)
+               return ii;
 
        /* We do not even look at the reply, so we need not
         * swap the multi-byte fields.
@@ -2034,205 +2503,897 @@ SendPortEnable(MPT_ADAPTER *ioc, int portnum)
        return 0;
 }
 
+/*
+ * Inputs: size - total FW bytes
+ * Outputs: frags - number of fragments needed
+ * Return NULL if failed.
+ */
+void * 
+mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size, int *frags, int *alloc_sz) 
+{
+       fw_image_t      **cached_fw = NULL;
+       u8              *mem = NULL;
+       dma_addr_t      fw_dma;
+       int             alloc_total = 0;
+       int             bytes_left, bytes, num_frags;
+       int             sz, ii;
+
+       /* cached_fw 
+        */
+       sz = ioc->num_fw_frags * sizeof(void *);
+       mem = kmalloc(sz, GFP_ATOMIC);
+       if (mem == NULL)
+               return NULL;
+
+       memset(mem, 0, sz);
+       cached_fw = (fw_image_t **)mem;
+       alloc_total += sz;
+
+       /* malloc fragment memory
+        * fw_image_t struct and dma for fw data
+        */
+       bytes_left = size;
+       ii = 0;
+       num_frags = 0;
+       bytes = bytes_left;
+       while((bytes_left) && (num_frags < ioc->num_fw_frags)) {
+               if (cached_fw[ii] == NULL) {
+                       mem = kmalloc(sizeof(fw_image_t), GFP_ATOMIC);
+                       if (mem == NULL)
+                               break;
+
+                       memset(mem, 0, sizeof(fw_image_t));
+                       cached_fw[ii] = (fw_image_t *)mem;
+                       alloc_total += sizeof(fw_image_t);
+               }
+
+               mem = pci_alloc_consistent(ioc->pcidev, bytes, &fw_dma);
+               if (mem == NULL) {
+                       if (bytes > 0x10000)
+                               bytes = 0x10000;
+                       else if (bytes > 0x8000)
+                               bytes = 0x8000;
+                       else if (bytes > 0x4000)
+                               bytes = 0x4000;
+                       else if (bytes > 0x2000)
+                               bytes = 0x2000;
+                       else if (bytes > 0x1000)
+                               bytes = 0x1000;
+                       else
+                               break;
+
+                       continue;
+               }
+
+               cached_fw[ii]->fw = mem;
+               cached_fw[ii]->fw_dma = fw_dma;
+               cached_fw[ii]->size = bytes;
+               memset(mem, 0, bytes);
+               alloc_total += bytes;
+
+               bytes_left -= bytes;
+
+               num_frags++;
+               ii++;
+       }
+
+       if (bytes_left ) {
+               /* Major Failure.
+                */
+               mpt_free_fw_memory(ioc, cached_fw);
+               return NULL;
+       }
+
+       *frags = num_frags;
+       *alloc_sz = alloc_total;
+
+       return (void *) cached_fw;
+}
+
+/*
+ * If alt_img is NULL, delete from ioc structure.
+ * Else, delete a secondary image in same format.
+ */
+void
+mpt_free_fw_memory(MPT_ADAPTER *ioc, fw_image_t **alt_img)
+{
+       fw_image_t **cached_fw;
+       int ii;
+       int sz;
+       int alloc_freed = 0;
+
+       if (alt_img != NULL)
+               cached_fw = alt_img;
+       else
+               cached_fw = ioc->cached_fw;
+
+       if (cached_fw == NULL)
+               return;
+
+       ii = 0;
+       while ((ii < ioc->num_fw_frags) && (cached_fw[ii]!= NULL)) {
+               sz = cached_fw[ii]->size;
+               if (sz > 0) {
+                       pci_free_consistent(ioc->pcidev, sz,
+                                               cached_fw[ii]->fw, cached_fw[ii]->fw_dma);
+               }
+               cached_fw[ii]->fw = NULL;
+               alloc_freed += sz;
+
+               kfree(cached_fw[ii]);
+               cached_fw[ii] = NULL;
+               alloc_freed += sizeof(fw_image_t);
+
+               ii++;
+       }
+
+       kfree(cached_fw);
+       cached_fw = NULL;
+       sz = ioc->num_fw_frags * sizeof(void *);
+       alloc_freed += sz;
+
+       if (alt_img == NULL)
+               ioc->alloc_total -= alloc_freed;
+
+       return;
+}
+
+
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
- *     KickStart - Perform hard reset of MPT adapter.
+ *     mpt_do_upload - Construct and Send FWUpload request to MPT adapter port.
  *     @ioc: Pointer to MPT_ADAPTER structure
- *     @force: Force hard reset
+ *     @sleepFlag: Specifies whether the process can sleep
  *
- *     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, >0 for handshake failure
+ *             <0 for fw upload failure.
  *
- *     Returns 0 for soft reset success, 1 for hard reset success,
- *     else a negative value for failure.
+ *     Remark: If bound IOC and a successful FWUpload was performed
+ *     on the bound IOC, the second image is discarded
+ *     and memory is free'd. Both channels must upload to prevent
+ *     IOC from running in degraded mode.
  */
 static int
-KickStart(MPT_ADAPTER *ioc, int force)
+mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
 {
-       int hard_reset_done = 0;
-       u32 ioc_state;
-       int cnt = 0;
+       u8                       request[ioc->req_sz];
+       u8                       reply[sizeof(FWUploadReply_t)];
+       FWUpload_t              *prequest;
+       FWUploadReply_t         *preply;
+       FWUploadTCSGE_t         *ptcsge = NULL;
+       int                      sgeoffset;
+       int                      ii, sz, reply_sz;
+       int                      cmdStatus, freeMem = 0;
+       int                      num_frags, alloc_sz;
+
+       /* If the image size is 0 or if the pointer is
+        * not NULL (error), we are done.
+        */
+       if (((sz = ioc->facts.FWImageSize) == 0) || ioc->cached_fw)
+               return 0;
 
-       dprintk((KERN_WARNING MYNAM ": KickStarting %s!\n", ioc->name));
+       ioc->num_fw_frags = ioc->req_sz - sizeof(FWUpload_t) + sizeof(dma_addr_t) + sizeof(u32) -1;
+       ioc->num_fw_frags /= sizeof(dma_addr_t) + sizeof(u32);
 
-       hard_reset_done = mpt_fc9x9_reset(ioc, force);
-#if 0
-       if (ioc->chip_type == FC909 || ioc->chip-type == FC919) {
-               hard_reset_done = mpt_fc9x9_reset(ioc, force);
-       } 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))
-                       hard_reset_done = mpt_fc9x9_reset(ioc, ignore);
-               else {
-                       dprintk((KERN_INFO MYNAM ": %s: Skipping KickStart (delta=%ld)!\n",
-                                       ioc->name, delta));
-                       return 0;
-               }
-       /* 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;
+       ioc->cached_fw = (fw_image_t **) mpt_alloc_fw_memory(ioc, 
+                       ioc->facts.FWImageSize, &num_frags, &alloc_sz); 
+
+       if (ioc->cached_fw == NULL) {
+               /* Major Failure.
+                */
+               mpt_free_fw_memory(ioc, NULL);
+               ioc->cached_fw = NULL;
+               
+               return -ENOMEM;
        }
-#endif
+       ioc->alloc_total += alloc_sz;
 
-       if (hard_reset_done < 0)
-               return hard_reset_done;
+       dprintk((KERN_INFO MYNAM ": FW Image  @ %p, sz=%d bytes\n",
+                (void *)(ulong)ioc->cached_fw, ioc->facts.FWImageSize));
 
-       dprintk((KERN_INFO MYNAM ": %s: Diagnostic reset successful\n",
-                       ioc->name));
+       prequest = (FWUpload_t *)&request;
+       preply = (FWUploadReply_t *)&reply;
 
-       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 hard_reset_done;
+       /*  Destination...  */
+       memset(prequest, 0, ioc->req_sz);
+
+       reply_sz = sizeof(reply);
+       memset(preply, 0, reply_sz);
+
+       prequest->ImageType = MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM;
+       prequest->Function = MPI_FUNCTION_FW_UPLOAD;
+       prequest->MsgContext = 0;               /* anything */
+
+       ptcsge = (FWUploadTCSGE_t *) &prequest->SGL;
+       ptcsge->Reserved = 0;
+       ptcsge->ContextSize = 0;
+       ptcsge->DetailsLength = 12;
+       ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
+       ptcsge->Reserved1 = 0;
+       ptcsge->ImageOffset = 0;
+       ptcsge->ImageSize = cpu_to_le32(sz);
+
+       sgeoffset = sizeof(FWUpload_t) - sizeof(SGE_MPI_UNION) + sizeof(FWUploadTCSGE_t);
+
+       for (ii = 0; ii < (num_frags-1); ii++) {
+               mpt_add_sge(&request[sgeoffset], MPT_SGE_FLAGS_SIMPLE_ELEMENT | 
+                       MPT_SGE_FLAGS_ADDRESSING | MPT_TRANSFER_IOC_TO_HOST |
+                       (u32) ioc->cached_fw[ii]->size, ioc->cached_fw[ii]->fw_dma);
+
+               sgeoffset += sizeof(u32) + sizeof(dma_addr_t);
+       }
+
+       mpt_add_sge(&request[sgeoffset], 
+                       MPT_SGE_FLAGS_SSIMPLE_READ |(u32) ioc->cached_fw[ii]->size, 
+                       ioc->cached_fw[ii]->fw_dma);
+
+       sgeoffset += sizeof(u32) + sizeof(dma_addr_t);
+
+       dprintk((MYIOC_s_INFO_FMT "Sending FW Upload (req @ %p) size %d \n",
+                       ioc->name, prequest, sgeoffset));
+
+       ii = mpt_handshake_req_reply_wait(ioc, sgeoffset, (u32*)prequest,
+                               reply_sz, (u16*)preply, 65 /*seconds*/, sleepFlag);
+
+       cmdStatus = -EFAULT;
+       if (ii == 0) {
+               /* Handshake transfer was complete and successful.
+                * Check the Reply Frame.
+                */
+               int status, transfer_sz;
+               status = le16_to_cpu(preply->IOCStatus);
+               if (status == MPI_IOCSTATUS_SUCCESS) {
+                       transfer_sz = le32_to_cpu(preply->ActualImageSize);
+                       if (transfer_sz == sz)
+                               cmdStatus = 0;
                }
-               /* udelay(10000) ? */
-               current->state = TASK_INTERRUPTIBLE;
-               schedule_timeout(1);
        }
+       dprintk((MYIOC_s_INFO_FMT ": do_upload status %d \n",
+                       ioc->name, cmdStatus));
 
-       printk(KERN_ERR MYNAM ": %s: ERROR - Failed to come READY after reset!\n",
-                       ioc->name);
-       return -1;
+       /* Check to see if we have a copy of this image in
+        * host memory already.
+        */
+       if (cmdStatus == 0) {
+               ioc->upload_fw = 0;
+               if (ioc->alt_ioc && ioc->alt_ioc->cached_fw)
+                       freeMem = 1;
+       }
+
+       /* We already have a copy of this image or
+        * we had some type of an error  - either the handshake
+        * failed (i != 0) or the command did not complete successfully.
+        */
+       if (cmdStatus || freeMem) {
+
+               dprintk((MYIOC_s_INFO_FMT ": do_upload freeing %s image \n",
+                       ioc->name, cmdStatus ? "incomplete" : "duplicate"));
+               mpt_free_fw_memory(ioc, NULL);
+               ioc->cached_fw = NULL;
+       }
+
+       return cmdStatus;
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
- *     mpt_fc9x9_reset - Perform hard reset of FC9x9 adapter.
+ *     mpt_downloadboot - DownloadBoot code
  *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @flag: Specify which part of IOC memory is to be uploaded.
+ *     @sleepFlag: Specifies whether the process can sleep
  *
- *     This routine places FC9x9 adapter in diagnostic mode via the
- *     WriteSequence register, and then performs a hard reset of adapter
- *     via the Diagnostic register.
+ *     FwDownloadBoot requires Programmed IO access.
  *
- *     Returns 0 for success, non-zero for failure.
+ *     Returns 0 for success
+ *             -1 FW Image size is 0
+ *             -2 No valid cached_fw Pointer
+ *             <0 for fw upload failure.
  */
 static int
-mpt_fc9x9_reset(MPT_ADAPTER *ioc, int ignore)
+mpt_downloadboot(MPT_ADAPTER *ioc, int sleepFlag)
 {
-       u32 diag0val;
-       int hard_reset_done = 0;
-
-       /* Use "Diagnostic reset" method! (only thing available!) */
-
-       diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
+       MpiFwHeader_t           *FwHdr = NULL;
+       MpiExtImageHeader_t     *ExtHdr;
+       fw_image_t              **pCached = NULL;
+       int                      fw_sz;
+       u32                      diag0val;
 #ifdef MPT_DEBUG
-{
-       u32 diag1val = 0;
+       u32                      diag1val = 0;
+#endif
+       int                      count = 0;
+       u32                     *ptru32 = NULL;
+       u32                      diagRwData;
+       u32                      nextImage;
+       u32                      ext_offset;
+       u32                      load_addr;
+       int                      max_idx, fw_idx, ext_idx;
+       int                      left_u32s;
+
+       dprintk((MYIOC_s_INFO_FMT "DbGb0: downloadboot entered.\n",
+                               ioc->name));
+#ifdef MPT_DEBUG
+       diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
        if (ioc->alt_ioc)
                diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
-       dprintk((KERN_INFO MYNAM ": %s: DBG1: diag0=%08x, diag1=%08x\n",
-                       ioc->name, diag0val, diag1val));
-}
+       dprintk((MYIOC_s_INFO_FMT "DbGb1: diag0=%08x, diag1=%08x\n",
+                               ioc->name, diag0val, diag1val));
 #endif
-       if (diag0val & MPI_DIAG_DRWE) {
-               dprintk((KERN_INFO MYNAM ": %s: DiagWriteEn bit already set\n",
-                               ioc->name));
-       } else {
-               /* Write magic sequence to WriteSequence register */
+
+       dprintk((MYIOC_s_INFO_FMT "fw size 0x%x, ioc FW Ptr %p\n",
+                               ioc->name, ioc->facts.FWImageSize, ioc->cached_fw));
+       if (ioc->alt_ioc)
+               dprintk((MYIOC_s_INFO_FMT "alt ioc FW Ptr %p\n",
+                               ioc->name, ioc->alt_ioc->cached_fw));
+
+       /* Get dma_addr and data transfer size.
+        */
+       if ((fw_sz = ioc->facts.FWImageSize) == 0)
+               return -1;
+
+       /* Get the DMA from ioc or ioc->alt_ioc */
+       if (ioc->cached_fw == NULL)
+               pCached = (fw_image_t **)ioc->cached_fw;
+       else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw)
+               pCached = (fw_image_t **)ioc->alt_ioc->cached_fw;
+
+       dprintk((MYIOC_s_INFO_FMT "DbGb2: FW Image @ %p\n",
+                       ioc->name, FwHdr));
+       if (!pCached)
+               return -2;
+
+       /* Write magic sequence to WriteSequence register
+        * until enter diagnostic mode
+        */
+       diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
+       while ((diag0val & MPI_DIAG_DRWE) == 0) {
                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 [spot#1]\n",
-                               ioc->name));
+
+               /* wait 100 msec */
+               if (sleepFlag == CAN_SLEEP) {
+                       set_current_state(TASK_INTERRUPTIBLE);
+                       schedule_timeout(100 * HZ / 1000);
+               } else {
+                       mdelay (100);
+               }
+
+               count++;
+               if (count > 20) {
+                       printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
+                                       ioc->name, diag0val);
+                       return -EFAULT;
+
+               }
+
+               diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
+#ifdef MPT_DEBUG
+               if (ioc->alt_ioc)
+                       diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
+               dprintk((MYIOC_s_INFO_FMT "DbGb3: diag0=%08x, diag1=%08x\n",
+                               ioc->name, diag0val, diag1val));
+#endif
+               dprintk((MYIOC_s_INFO_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
+                               ioc->name, diag0val));
        }
 
-       diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
+       /* Set the DiagRwEn and Disable ARM bits */
+       diag0val |= (MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM);
+       CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
+
 #ifdef MPT_DEBUG
-{
-       u32 diag1val = 0;
        if (ioc->alt_ioc)
                diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
-       dprintk((KERN_INFO MYNAM ": %s: DbG2: diag0=%08x, diag1=%08x\n",
+       dprintk((MYIOC_s_INFO_FMT "DbGb3: diag0=%08x, diag1=%08x\n",
                        ioc->name, diag0val, diag1val));
+#endif
+
+       /* Write the LoadStartAddress to the DiagRw Address Register
+        * using Programmed IO
+        */
+       CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, FwHdr->LoadStartAddress);
+       dprintk((MYIOC_s_INFO_FMT "LoadStart addr written 0x%x \n",
+               ioc->name, FwHdr->LoadStartAddress));
+#if 1
+
+       /* max_idx = 1 + maximum valid buffer index
+        */
+       max_idx = 0;
+       while (pCached[max_idx])
+               max_idx++;
+
+       fw_idx = 0;
+       FwHdr = (MpiFwHeader_t *) pCached[fw_idx]->fw;
+       ptru32 = (u32 *) FwHdr;
+       count = (FwHdr->ImageSize + 3)/4;
+       nextImage = FwHdr->NextImageHeaderOffset;
+
+       dprintk((MYIOC_s_INFO_FMT "Write FW Image: 0x%x u32's @ %p\n",
+                               ioc->name, count, ptru32));
+       left_u32s = pCached[fw_idx]->size/4;
+       while (count--) {
+               if (left_u32s == 0) {
+                       fw_idx++;
+                       if (fw_idx >= max_idx) {
+                               /* FIXME
+                               ERROR CASE
+                               */
+                               ;
+                       }
+                       ptru32 = (u32 *) pCached[fw_idx]->fw;
+                       left_u32s = pCached[fw_idx]->size / 4;
+               }
+               left_u32s--;
+               CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptru32);
+               ptru32++;
+       }
+
+       /* left_u32s, fw_idx and ptru32 are all valid
+        */
+       while (nextImage) {
+               ext_idx = 0;
+               ext_offset = nextImage;
+               while (ext_offset > pCached[ext_idx]->size) {
+                       ext_idx++;
+                       if (ext_idx >= max_idx) {
+                               /* FIXME
+                               ERROR CASE
+                               */
+                               ;
+                       }
+                       ext_offset -= pCached[ext_idx]->size;
+               }
+               ptru32 = (u32 *) ((char *)pCached[ext_idx]->fw + ext_offset);
+               left_u32s = pCached[ext_idx]->size - ext_offset;
+
+               if ((left_u32s * 4) >= sizeof(MpiExtImageHeader_t)) {
+                       ExtHdr = (MpiExtImageHeader_t *) ptru32;
+                       count = (ExtHdr->ImageSize + 3 )/4;
+                       nextImage = ExtHdr->NextImageHeaderOffset;
+                       load_addr = ExtHdr->LoadStartAddress;
+               } else {
+                       u32 * ptmp = (u32 *)pCached[ext_idx+1]->fw;
+
+                       switch (left_u32s) {
+                       case 5:
+                               count = *(ptru32 + 2);
+                               nextImage = *(ptru32 + 3);
+                               load_addr = *(ptru32 + 4);
+                               break;
+                       case 4:
+                               count = *(ptru32 + 2);
+                               nextImage = *(ptru32 + 3);
+                               load_addr = *ptmp;
+                               break;
+                       case 3:
+                               count = *(ptru32 + 2);
+                               nextImage = *ptmp;
+                               load_addr = *(ptmp + 1);
+                               break;
+                       case 2:
+                               count = *ptmp;
+                               nextImage = *(ptmp + 1);
+                               load_addr = *(ptmp + 2);
+                               break;
+
+                       case 1:
+                               count = *(ptmp + 1);
+                               nextImage = *(ptmp + 2);
+                               load_addr = *(ptmp + 3);
+                               break;
+
+                       default:
+                               count = 0;
+                               nextImage = 0;
+                               load_addr = 0;
+                               /* FIXME
+                               ERROR CASE
+                               */
+                               ;
+
+                       }
+                       count = (count +3)/4;
+               }
+
+               dprintk((MYIOC_s_INFO_FMT "Write Ext Image: 0x%x u32's @ %p\n",
+                                               ioc->name, count, ptru32));
+               CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, load_addr);
+
+               while (count--) {
+                       if (left_u32s == 0) {
+                               fw_idx++;
+                               if (fw_idx >= max_idx) {
+                                       /* FIXME
+                                       ERROR CASE
+                                       */
+                                       ;
+                               }
+                               ptru32 = (u32 *) pCached[fw_idx]->fw;
+                               left_u32s = pCached[fw_idx]->size / 4;
+                       }
+                       left_u32s--;
+                       CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptru32);
+                       ptru32++;
+               }
+       }
+
+#else
+       while (nextImage) {
+
+               /* Set the pointer to the extended image
+                */
+               ExtHdr = (MpiExtImageHeader_t *) ((char *) FwHdr + nextImage);
+
+               CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, ExtHdr->LoadStartAddress);
+
+               count = (ExtHdr->ImageSize + 3 )/4;
+
+               ptru32 = (u32 *) ExtHdr;
+               dprintk((MYIOC_s_INFO_FMT "Write Ext Image: 0x%x u32's @ %p\n",
+                               ioc->name, count, ptru32));
+               while (count-- ) {
+                       CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptru32);
+                       ptru32++;
+               }
+               nextImage = ExtHdr->NextImageHeaderOffset;
+       }
+#endif
+
+
+       /* Write the IopResetVectorRegAddr */
+       dprintk((MYIOC_s_INFO_FMT "Write IopResetVector Addr! \n", ioc->name));
+       CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, FwHdr->IopResetRegAddr);
+
+       /* Write the IopResetVectorValue */
+       dprintk((MYIOC_s_INFO_FMT "Write IopResetVector Value! \n", ioc->name));
+       CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, FwHdr->IopResetVectorValue);
+
+       /* Clear the internal flash bad bit - autoincrementing register,
+        * so must do two writes.
+        */
+       CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
+       diagRwData = CHIPREG_PIO_READ32(&ioc->pio_chip->DiagRwData);
+       diagRwData |= 0x4000000;
+       CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
+       CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData);
+
+       /* clear the RW enable and DISARM bits */
+       diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
+       diag0val &= ~(MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE | MPI_DIAG_FLASH_BAD_SIG);
+       CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
+
+       /* Write 0xFF to reset the sequencer */
+       CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
+
+       return 0;
 }
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     KickStart - Perform hard reset of MPT adapter.
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @force: Force hard reset
+ *     @sleepFlag: Specifies whether the process can sleep
+ *
+ *     This routine places MPT adapter in diagnostic mode via the
+ *     WriteSequence register, and then performs a hard reset of adapter
+ *     via the Diagnostic register.
+ *
+ *     Inputs:   sleepflag - CAN_SLEEP (non-interrupt thread)
+ *                     or NO_SLEEP (interrupt thread, use mdelay)
+ *               force - 1 if doorbell active, board fault state
+ *                             board operational, IOC_RECOVERY or
+ *                             IOC_BRINGUP and there is an alt_ioc.
+ *                       0 else
+ *
+ *     Returns:
+ *              1 - hard reset, READY  
+ *              0 - no reset due to History bit, READY 
+ *             -1 - no reset due to History bit but not READY  
+ *                  OR reset but failed to come READY
+ *             -2 - no reset, could not enter DIAG mode 
+ *             -3 - reset but bad FW bit 
+ */
+static int
+KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
+{
+       int hard_reset_done = 0;
+       u32 ioc_state;
+       int cnt = 0;
+
+       dprintk((KERN_WARNING MYNAM ": KickStarting %s!\n", ioc->name));
+
+       hard_reset_done = mpt_diag_reset(ioc, force, sleepFlag);
+       if (hard_reset_done < 0)
+               return hard_reset_done;
+
+       dprintk((MYIOC_s_INFO_FMT "Diagnostic reset successful!\n",
+                       ioc->name));
+
+       for (cnt=0; cnt<HZ*20; cnt++) {
+               if ((ioc_state = mpt_GetIocState(ioc, 1)) == MPI_IOC_STATE_READY) {
+                       dprintk((MYIOC_s_INFO_FMT "KickStart successful! (cnt=%d)\n",
+                                       ioc->name, cnt));
+                       return hard_reset_done;
+               }
+               if (sleepFlag == CAN_SLEEP) {
+                       set_current_state(TASK_INTERRUPTIBLE);
+                       schedule_timeout(1);
+               } else {
+                       mdelay (10);
+               }
+       }
+
+       printk(MYIOC_s_ERR_FMT "Failed to come READY after reset!\n",
+                       ioc->name);
+       return -1;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     mpt_diag_reset - Perform hard reset of the adapter.
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @ignore: Set if to honor and clear to ignore
+ *             the reset history bit
+ *     @sleepflag: CAN_SLEEP if called in a non-interrupt thread,
+ *             else set to NO_SLEEP (use mdelay instead)
+ *
+ *     This routine places the adapter in diagnostic mode via the
+ *     WriteSequence register and then performs a hard reset of adapter
+ *     via the Diagnostic register. Adapter should be in ready state
+ *     upon successful completion.
+ *
+ *     Returns:  1  hard reset successful
+ *               0  no reset performed because reset history bit set
+ *              -2  enabling diagnostic mode failed
+ *              -3  diagnostic reset failed
+ */
+static int
+mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
+{
+       u32 diag0val;
+       u32 doorbell;
+       int hard_reset_done = 0;
+       int count = 0;
+#ifdef MPT_DEBUG
+       u32 diag1val = 0;
 #endif
-       if (!ignore && (diag0val & MPI_DIAG_RESET_HISTORY)) {
-               dprintk((KERN_INFO MYNAM ": %s: Skipping due to ResetHistory bit set!\n",
-                               ioc->name));
-       } else {
+
+       /* Clear any existing interrupts */
+       CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
+
+       /* Use "Diagnostic reset" method! (only thing available!) */
+       diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
+
+#ifdef MPT_DEBUG
+       if (ioc->alt_ioc)
+               diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
+       dprintk((MYIOC_s_INFO_FMT "DbG1: diag0=%08x, diag1=%08x\n",
+                       ioc->name, diag0val, diag1val));
+#endif
+
+       /* Do the reset if we are told to ignore the reset history
+        * or if the reset history is 0
+        */
+       if (ignore || !(diag0val & MPI_DIAG_RESET_HISTORY)) {
+               while ((diag0val & MPI_DIAG_DRWE) == 0) {
+                       /* Write magic sequence to WriteSequence register
+                        * Loop until in diagnostic mode
+                        */
+                       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);
+
+                       /* wait 100 msec */
+                       if (sleepFlag == CAN_SLEEP) {
+                               set_current_state(TASK_INTERRUPTIBLE);
+                               schedule_timeout(100 * HZ / 1000);
+                       } else {
+                               mdelay (100);
+                       }
+
+                       count++;
+                       if (count > 20) {
+                               printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
+                                               ioc->name, diag0val);
+                               return -2;
+
+                       }
+
+                       diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
+
+                       dprintk((MYIOC_s_INFO_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
+                                       ioc->name, diag0val));
+               }
+
+#ifdef MPT_DEBUG
+               if (ioc->alt_ioc)
+                       diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
+               dprintk((MYIOC_s_INFO_FMT "DbG2: diag0=%08x, diag1=%08x\n",
+                               ioc->name, diag0val, diag1val));
+#endif
+               /* Write the PreventIocBoot bit */
+               if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT) {
+                       diag0val |= MPI_DIAG_PREVENT_IOC_BOOT;
+                       CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
+               }
+
+               /*
+                * Disable the ARM (Bug fix)
+                * 
+                */
+               CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_DISABLE_ARM);
+               mdelay (1);
+
                /*
                 * Now hit the reset bit in the Diagnostic register
-                * (THE BIG HAMMER!)
+                * (THE BIG HAMMER!) (Clears DRWE bit).
                 */
-               CHIPREG_WRITE32(&ioc->chip->Diagnostic, MPI_DIAG_RESET_ADAPTER);
+               CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
                hard_reset_done = 1;
-               dprintk((KERN_INFO MYNAM ": %s: Diagnostic reset performed\n",
+               dprintk((MYIOC_s_INFO_FMT "Diagnostic reset performed\n",
                                ioc->name));
 
-               /* want udelay(100) */
-               current->state = TASK_INTERRUPTIBLE;
-               schedule_timeout(1);
+               /*
+                * Call each currently registered protocol IOC reset handler
+                * with pre-reset indication.
+                * NOTE: If we're doing _IOC_BRINGUP, there can be no
+                * MptResetHandlers[] registered yet.
+                */
+               {
+                       int      ii;
+                       int      r = 0;
+
+                       for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
+                               if (MptResetHandlers[ii]) {
+                                       dprintk((MYIOC_s_INFO_FMT "Calling IOC pre_reset handler #%d\n",
+                                                       ioc->name, ii));
+                                       r += (*(MptResetHandlers[ii]))(ioc, MPT_IOC_PRE_RESET);
+                                       if (ioc->alt_ioc) {
+                                               dprintk((MYIOC_s_INFO_FMT "Calling alt-%s pre_reset handler #%d\n",
+                                                               ioc->name, ioc->alt_ioc->name, ii));
+                                               r += (*(MptResetHandlers[ii]))(ioc->alt_ioc, MPT_IOC_PRE_RESET);
+                                       }
+                               }
+                       }
+                       /* FIXME?  Examine results here? */
+               }
+
+               if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT) {
+                       /* If the DownloadBoot operation fails, the
+                        * IOC will be left unusable. This is a fatal error
+                        * case.  _diag_reset will return < 0
+                        */
+                       for (count = 0; count < 30; count ++) {
+                               diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
+#ifdef MPT_DEBUG
+                               if (ioc->alt_ioc)
+                                       diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
+                               dprintk((MYIOC_s_INFO_FMT 
+                                       "DbG2b: diag0=%08x, diag1=%08x\n",
+                                       ioc->name, diag0val, diag1val));
+#endif
+                               if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
+                                       break;
+                               }
+
+                               /* wait 1 sec */
+                               if (sleepFlag == CAN_SLEEP) {
+                                       set_current_state(TASK_INTERRUPTIBLE);
+                                       schedule_timeout(HZ);
+                               } else {
+                                       mdelay (1000);
+                               }
+                       }
+                       if ((count = mpt_downloadboot(ioc, sleepFlag)) < 0) {
+                               printk(KERN_WARNING MYNAM 
+                                       ": firmware downloadboot failure (%d)!\n", count);
+                       }
+
+               } else {
+                       /* Wait for FW to reload and for board
+                        * to go to the READY state.
+                        * Maximum wait is 30 seconds.
+                        * If fail, no error will check again
+                        * with calling program.
+                        */
+                       for (count = 0; count < 30; count ++) {
+                               doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
+                               doorbell &= MPI_IOC_STATE_MASK;
+
+                               if (doorbell == MPI_IOC_STATE_READY) {
+                                       break;
+                               }
+
+                               /* wait 1 sec */
+                               if (sleepFlag == CAN_SLEEP) {
+                                       set_current_state(TASK_INTERRUPTIBLE);
+                                       schedule_timeout(HZ);
+                               } else {
+                                       mdelay (1000);
+                               }
+                       }
+               }
+       }
+
+       diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
+#ifdef MPT_DEBUG
+       if (ioc->alt_ioc)
+               diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
+       dprintk((MYIOC_s_INFO_FMT "DbG3: diag0=%08x, diag1=%08x\n",
+               ioc->name, diag0val, diag1val));
+#endif
 
-               /* Write magic sequence to WriteSequence register */
+       /* Clear RESET_HISTORY bit!  Place board in the
+        * diagnostic mode to update the diag register.
+        */
+       diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
+       count = 0;
+       while ((diag0val & MPI_DIAG_DRWE) == 0) {
+               /* Write magic sequence to WriteSequence register
+                * Loop until in diagnostic mode
+                */
                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 [spot#2]\n",
-                               ioc->name));
-       }
 
-       /* Clear RESET_HISTORY bit! */
-       CHIPREG_WRITE32(&ioc->chip->Diagnostic, 0x0);
+               /* wait 100 msec */
+               if (sleepFlag == CAN_SLEEP) {
+                       set_current_state(TASK_INTERRUPTIBLE);
+                       schedule_timeout(100 * HZ / 1000);
+               } else {
+                       mdelay (100);
+               }
 
+               count++;
+               if (count > 20) {
+                       printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
+                                       ioc->name, diag0val);
+                       break;
+               }
+               diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
+       }
+       diag0val &= ~MPI_DIAG_RESET_HISTORY;
+       CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
        diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
-#ifdef MPT_DEBUG
-{
-       u32 diag1val = 0;
-       if (ioc->alt_ioc)
-               diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
-       dprintk((KERN_INFO MYNAM ": %s: DbG3: diag0=%08x, diag1=%08x\n",
-                       ioc->name, diag0val, diag1val));
-}
-#endif
        if (diag0val & MPI_DIAG_RESET_HISTORY) {
-               printk(KERN_WARNING MYNAM ": %s: WARNING - ResetHistory bit failed to clear!\n",
+               printk(MYIOC_s_WARN_FMT "ResetHistory bit failed to clear!\n",
                                ioc->name);
        }
 
+       /* Disable Diagnostic Mode
+        */
+       CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFFFFFFFF);
+
+       /* Check FW reload status flags.
+        */
        diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
+       if (diag0val & (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_RESET_ADAPTER | MPI_DIAG_DISABLE_ARM)) {
+               printk(MYIOC_s_ERR_FMT "Diagnostic reset FAILED! (%02xh)\n",
+                               ioc->name, diag0val);
+               return -3;
+       }
+
 #ifdef MPT_DEBUG
-{
-       u32 diag1val = 0;
        if (ioc->alt_ioc)
                diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
-       dprintk((KERN_INFO MYNAM ": %s: DbG4: diag0=%08x, diag1=%08x\n",
+       dprintk((MYIOC_s_INFO_FMT "DbG4: diag0=%08x, diag1=%08x\n",
                        ioc->name, diag0val, diag1val));
-}
 #endif
-       if (diag0val & (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_RESET_ADAPTER | MPI_DIAG_DISABLE_ARM)) {
-               printk(KERN_ERR MYNAM ": %s: ERROR - Diagnostic reset FAILED! (%02xh)\n",
-                               ioc->name, diag0val);
-               return -3;
-       }
 
        /*
         * Reset flag that says we've enabled event notification
         */
        ioc->facts.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;
-       }
+       if (ioc->alt_ioc)
+               ioc->alt_ioc->facts.EventState = 0;
 
        return hard_reset_done;
 }
@@ -2249,16 +3410,45 @@ mpt_fc9x9_reset(MPT_ADAPTER *ioc, int ignore)
  *     Returns 0 for success, non-zero for failure.
  */
 static int
-SendIocReset(MPT_ADAPTER *ioc, u8 reset_type)
+SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag)
 {
        int r;
+       u32 state;
+       int cntdn, count;
 
        dprintk((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, 2)) < 0)
+       if ((r = WaitForDoorbellAck(ioc, 2, sleepFlag)) < 0)
                return r;
 
+       /* FW ACK'd request, wait for READY state 
+        */
+       cntdn = HZ * 15;
+       count = 0;
+       if (sleepFlag != CAN_SLEEP)
+               cntdn *= 10;    /* 1500 iterations @ 1msec per */
+
+       while ((state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
+               cntdn--;
+               count++;
+               if (!cntdn) {
+                       if (sleepFlag != CAN_SLEEP)
+                               count *= 10;
+
+                       printk(KERN_ERR MYNAM ": %s: ERROR - Wait IOC_READY state timeout(%d)!\n",
+                                       ioc->name, (count+5)/HZ);
+                       return -ETIME;
+               }
+
+               if (sleepFlag == CAN_SLEEP) {
+                       set_current_state(TASK_INTERRUPTIBLE);
+                       schedule_timeout(1);
+               } else {
+                       mdelay (1);     /* 1 msec delay */
+               }
+       }
+
        /* TODO!
         *  Cleanup all event stuff for this IOC; re-issue EventNotification
         *  request if needed.
@@ -2275,7 +3465,8 @@ SendIocReset(MPT_ADAPTER *ioc, u8 reset_type)
  *     @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.
+ *     pools (if necessary), and primes the IOC reply FIFO with
+ *     reply frames.
  *
  *     Returns 0 for success, non-zero for failure.
  */
@@ -2284,6 +3475,7 @@ PrimeIocFifos(MPT_ADAPTER *ioc)
 {
        MPT_FRAME_HDR *mf;
        unsigned long b;
+       unsigned long flags;
        dma_addr_t aligned_mem_dma;
        u8 *mem, *aligned_mem;
        int i, sz;
@@ -2299,8 +3491,8 @@ PrimeIocFifos(MPT_ADAPTER *ioc)
                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));
+               dprintk((KERN_INFO MYNAM ": %s.reply_alloc  @ %p[%p], sz=%d bytes\n",
+                               ioc->name, mem, (void *)(ulong)ioc->reply_alloc_dma, sz));
 
                b = (unsigned long) mem;
                b = (b + (0x80UL - 1UL)) & ~(0x80UL - 1UL); /* round up to 128-byte boundary */
@@ -2308,15 +3500,20 @@ PrimeIocFifos(MPT_ADAPTER *ioc)
                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;
-               }
+               ioc->reply_frames_low_dma = (u32) (ioc->reply_frames_dma & 0xFFFFFFFF);
+       }
+
+       /* Post Reply frames to FIFO
+        */
+       aligned_mem_dma = ioc->reply_frames_dma;
+       dprintk((KERN_INFO MYNAM ": %s.reply_frames @ %p[%p]\n",
+                       ioc->name, ioc->reply_frames, (void *)(ulong)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;
        }
 
 
@@ -2336,8 +3533,8 @@ PrimeIocFifos(MPT_ADAPTER *ioc)
                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));
+               dprintk((KERN_INFO MYNAM ": %s.req_alloc    @ %p[%p], sz=%d bytes\n",
+                               ioc->name, mem, (void *)(ulong)ioc->req_alloc_dma, sz));
 
                b = (unsigned long) mem;
                b = (b + (0x80UL - 1UL)) & ~(0x80UL - 1UL); /* round up to 128-byte boundary */
@@ -2345,17 +3542,16 @@ PrimeIocFifos(MPT_ADAPTER *ioc)
                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;
+               ioc->req_frames_low_dma = (u32) (ioc->req_frames_dma & 0xFFFFFFFF);
 
-                       /*  Queue REQUESTs *internally*!  */
-                       Q_ADD_TAIL(&ioc->FreeQ.head, &mf->u.frame.linkage, MPT_FRAME_HDR);
-                       aligned_mem += ioc->req_sz;
+               if (sizeof(dma_addr_t) == sizeof(u64)) {
+                       /* Check: upper 32-bits of the request and reply frame
+                        * physical addresses must be the same.
+                        */
+                       if (((u64)ioc->req_frames_dma >> 32) != ((u64)ioc->reply_frames_dma >> 32)){
+                               goto out_fail;
+                       }
                }
 
 #if defined(CONFIG_MTRR) && 0
@@ -2367,20 +3563,38 @@ PrimeIocFifos(MPT_ADAPTER *ioc)
                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 ));
+               dprintk((MYIOC_s_INFO_FMT "MTRR region registered (base:size=%08x:%x)\n",
+                               ioc->name, ioc->req_alloc_dma, sz));
 #endif
+       }
+
+       /* Initialize Request frames linked list
+        */
+       aligned_mem_dma = ioc->req_frames_dma;
+       aligned_mem = (u8 *) ioc->req_frames;
+       dprintk((KERN_INFO MYNAM ": %s.req_frames   @ %p[%p]\n",
+                       ioc->name, aligned_mem, (void *)(ulong)aligned_mem_dma));
+
+       spin_lock_irqsave(&ioc->FreeQlock, flags);
+       Q_INIT(&ioc->FreeQ, MPT_FRAME_HDR);
+       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;
        }
+       spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+
 
        if (ioc->sense_buf_pool == NULL) {
-               sz = (ioc->req_depth * 256);
+               sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
                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->sense_buf_low_dma = (u32) (ioc->sense_buf_pool_dma & 0xFFFFFFFF);
                ioc->alloc_total += sz;
        }
 
@@ -2408,7 +3622,7 @@ out_fail:
 #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",
+                       dprintk((MYIOC_s_INFO_FMT "MTRR region de-registered\n",
                                        ioc->name));
                }
 #endif
@@ -2417,7 +3631,7 @@ out_fail:
                ioc->alloc_total -= sz;
        }
        if (ioc->sense_buf_pool != NULL) {
-               sz = (ioc->req_depth * 256);
+               sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
                pci_free_consistent(ioc->pcidev,
                                sz,
                                ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
@@ -2427,8 +3641,8 @@ out_fail:
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*
- *     HandShakeReqAndReply - Send MPT request to and receive reply from
+/**
+ *     mpt_handshake_req_reply_wait - 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
@@ -2436,6 +3650,7 @@ out_fail:
  *     @replyBytes: Expected size of the reply in bytes
  *     @u16reply: Pointer to area where reply should be written
  *     @maxwait: Max wait time for a reply (in seconds)
+ *     @sleepFlag: Specifies whether the process can sleep
  *
  *     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
@@ -2444,8 +3659,9 @@ out_fail:
  *
  *     Returns 0 for success, non-zero for failure.
  */
-static int
-HandShakeReqAndReply(MPT_ADAPTER *ioc, int reqBytes, u32 *req, int replyBytes, u16 *u16reply, int maxwait)
+int
+mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req,
+                               int replyBytes, u16 *u16reply, int maxwait, int sleepFlag)
 {
        MPIDefaultReply_t *mptReply;
        int failcnt = 0;
@@ -2471,57 +3687,61 @@ HandShakeReqAndReply(MPT_ADAPTER *ioc, int reqBytes, u32 *req, int replyBytes, u
        /*
         * Wait for IOC's doorbell handshake int
         */
-       if ((t = WaitForDoorbellInt(ioc, 2)) < 0)
+       if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
                failcnt++;
 
-       dhsprintk((KERN_INFO MYNAM ": %s: HandShake request start, WaitCnt=%d%s\n",
+       dhsprintk((MYIOC_s_INFO_FMT "HandShake request start, WaitCnt=%d%s\n",
                        ioc->name, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
 
+       /* Read doorbell and check for active bit */
+       if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
+                       return -1;
+
        /*
         * 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, 2)) < 0)
+       if (!failcnt && (t = WaitForDoorbellAck(ioc, 2, sleepFlag)) < 0)
                failcnt++;
 
        if (!failcnt) {
-               int      i;
+               int      ii;
                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));
+               for (ii = 0; !failcnt && ii < reqBytes/4; ii++) {
+                       u32 word = ((req_as_bytes[(ii*4) + 0] <<  0) |
+                                   (req_as_bytes[(ii*4) + 1] <<  8) |
+                                   (req_as_bytes[(ii*4) + 2] << 16) |
+                                   (req_as_bytes[(ii*4) + 3] << 24));
 
                        CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
-                       if ((t = WaitForDoorbellAck(ioc, 2)) < 0)
+                       if ((t = WaitForDoorbellAck(ioc, 2, sleepFlag)) < 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",
+               dhsprintk((MYIOC_s_INFO_FMT "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, maxwait)) < 0)
+               if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait, sleepFlag)) < 0)
                        failcnt++;
 
                /*
                 * Copy out the cached reply...
                 */
-               for(i=0; i < MIN(replyBytes/2,mptReply->MsgLength*2); i++)
-                       u16reply[i] = ioc->hs_reply[i];
+               for (ii=0; ii < MIN(replyBytes/2,mptReply->MsgLength*2); ii++)
+                       u16reply[ii] = ioc->hs_reply[ii];
        } else {
                return -99;
        }
@@ -2535,6 +3755,7 @@ HandShakeReqAndReply(MPT_ADAPTER *ioc, int reqBytes, u32 *req, int replyBytes, u
  *     in it's IntStatus register.
  *     @ioc: Pointer to MPT_ADAPTER structure
  *     @howlong: How long to wait (in seconds)
+ *     @sleepFlag: Specifies whether the process can sleep
  *
  *     This routine waits (up to ~2 seconds max) for IOC doorbell
  *     handshake ACKnowledge.
@@ -2542,28 +3763,40 @@ HandShakeReqAndReply(MPT_ADAPTER *ioc, int reqBytes, u32 *req, int replyBytes, u
  *     Returns a negative value on failure, else wait loop count.
  */
 static int
-WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong)
+WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
 {
        int cntdn = HZ * howlong;
        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 (sleepFlag == CAN_SLEEP) {
+               while (--cntdn) {
+                       intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
+                       if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
+                               break;
+                       set_current_state(TASK_INTERRUPTIBLE);
+                       schedule_timeout(1);
+                       count++;
+               }
+       } else {
+               cntdn *= 10; /* convert to msec */
+               while (--cntdn) {
+                       intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
+                       if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
+                               break;
+                       mdelay (1);
+                       count++;
+               }
+               count /= 10;
        }
 
        if (cntdn) {
-               dhsprintk((KERN_INFO MYNAM ": %s: WaitForDoorbell ACK (cnt=%d)\n",
+               dhsprintk((MYIOC_s_INFO_FMT "WaitForDoorbell ACK (cnt=%d)\n",
                                ioc->name, count));
                return count;
        }
 
-       printk(KERN_ERR MYNAM ": %s: ERROR - Doorbell ACK timeout(%d)!\n",
+       printk(MYIOC_s_ERR_FMT "Doorbell ACK timeout(%d)!\n",
                        ioc->name, (count+5)/HZ);
        return -1;
 }
@@ -2574,34 +3807,47 @@ WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong)
  *     in it's IntStatus register.
  *     @ioc: Pointer to MPT_ADAPTER structure
  *     @howlong: How long to wait (in seconds)
+ *     @sleepFlag: Specifies whether the process can sleep
  *
  *     This routine waits (up to ~2 seconds max) for IOC doorbell interrupt.
  *
  *     Returns a negative value on failure, else wait loop count.
  */
 static int
-WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong)
+WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
 {
        int cntdn = HZ * howlong;
        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 (sleepFlag == CAN_SLEEP) {
+               while (--cntdn) {
+                       intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
+                       if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
+                               break;
+                       set_current_state(TASK_INTERRUPTIBLE);
+                       schedule_timeout(1);
+                       count++;
+               }
+       } else {
+               cntdn *= 10; /* convert to msec */
+               while (--cntdn) {
+                       intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
+                       if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
+                               break;
+                       mdelay(1);
+                       count++;
+               }
+               count /= 10;
        }
 
        if (cntdn) {
-               dhsprintk((KERN_INFO MYNAM ": %s: WaitForDoorbell INT (cnt=%d)\n",
+               dhsprintk((MYIOC_s_INFO_FMT "WaitForDoorbell INT (cnt=%d)\n",
                                ioc->name, count));
                return count;
        }
 
-       printk(KERN_ERR MYNAM ": %s: ERROR - Doorbell INT timeout(%d)!\n",
+       printk(MYIOC_s_ERR_FMT "Doorbell INT timeout(%d)!\n",
                        ioc->name, (count+5)/HZ);
        return -1;
 }
@@ -2611,6 +3857,7 @@ WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong)
  *     WaitForDoorbellReply - Wait for and capture a IOC handshake reply.
  *     @ioc: Pointer to MPT_ADAPTER structure
  *     @howlong: How long to wait (in seconds)
+ *     @sleepFlag: Specifies whether the process can sleep
  *
  *     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
@@ -2619,13 +3866,13 @@ WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong)
  *     Returns a negative value on failure, else size of reply in WORDS.
  */
 static int
-WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong)
+WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
 {
        int u16cnt = 0;
        int failcnt = 0;
        int t;
        u16 *hs_reply = ioc->hs_reply;
-       volatile MPIDefaultReply_t *mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
+       volatile MPIDefaultReply_t *mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
        u16 hword;
 
        hs_reply[0] = hs_reply[1] = hs_reply[7] = 0;
@@ -2634,12 +3881,12 @@ WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong)
         * Get first two u16's so we can look at IOC's intended reply MsgLength
         */
        u16cnt=0;
-       if ((t = WaitForDoorbellInt(ioc, howlong)) < 0) {
+       if ((t = WaitForDoorbellInt(ioc, howlong, sleepFlag)) < 0) {
                failcnt++;
        } else {
                hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
                CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
-               if ((t = WaitForDoorbellInt(ioc, 2)) < 0)
+               if ((t = WaitForDoorbellInt(ioc, 2, sleepFlag)) < 0)
                        failcnt++;
                else {
                        hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
@@ -2647,7 +3894,7 @@ WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong)
                }
        }
 
-       dhsprintk((KERN_INFO MYNAM ": %s: First handshake reply word=%08x%s\n",
+       dhsprintk((MYIOC_s_INFO_FMT "First handshake reply word=%08x%s\n",
                        ioc->name, le32_to_cpu(*(u32 *)hs_reply),
                        failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
 
@@ -2656,7 +3903,7 @@ WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong)
         * reply 16 bits at a time.
         */
        for (u16cnt=2; !failcnt && u16cnt < (2 * mptReply->MsgLength); u16cnt++) {
-               if ((t = WaitForDoorbellInt(ioc, 2)) < 0)
+               if ((t = WaitForDoorbellInt(ioc, 2, sleepFlag)) < 0)
                        failcnt++;
                hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
                /* don't overflow our IOC hs_reply[] buffer! */
@@ -2665,12 +3912,12 @@ WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong)
                CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
        }
 
-       if (!failcnt && (t = WaitForDoorbellInt(ioc, 2)) < 0)
+       if (!failcnt && (t = WaitForDoorbellInt(ioc, 2, sleepFlag)) < 0)
                failcnt++;
        CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
 
        if (failcnt) {
-               printk(KERN_ERR MYNAM ": %s: ERROR - Handshake reply failure!\n",
+               printk(MYIOC_s_ERR_FMT "Handshake reply failure!\n",
                                ioc->name);
                return -failcnt;
        }
@@ -2683,10 +3930,10 @@ WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong)
        }
 #endif
 
-       dmfprintk((KERN_INFO MYNAM ": %s: Got Handshake reply:\n", ioc->name));
+       dmfprintk((MYIOC_s_INFO_FMT "Got Handshake reply:\n", ioc->name));
        DBG_DUMP_REPLY_FRAME(mptReply)
 
-       dhsprintk((KERN_INFO MYNAM ": %s: WaitForDoorbell REPLY (sz=%d)\n",
+       dhsprintk((MYIOC_s_INFO_FMT "WaitForDoorbell REPLY (sz=%d)\n",
                        ioc->name, u16cnt/2));
        return u16cnt/2;
 }
@@ -2696,115 +3943,616 @@ WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong)
  *     GetLanConfigPages - Fetch LANConfig pages.
  *     @ioc: Pointer to MPT_ADAPTER structure
  *
- *     Returns 0 for success, non-zero for failure.
+ *     Return: 0 for success
+ *     -ENOMEM if no memory available
+ *             -EPERM if not allowed due to ISR context
+ *             -EAGAIN if no msg frames currently available
+ *             -EFAULT for non-successful reply or no reply (timeout)
+ */
+static int
+GetLanConfigPages(MPT_ADAPTER *ioc)
+{
+       ConfigPageHeader_t       hdr;
+       CONFIGPARMS              cfg;
+       LANPage0_t              *ppage0_alloc;
+       dma_addr_t               page0_dma;
+       LANPage1_t              *ppage1_alloc;
+       dma_addr_t               page1_dma;
+       int                      rc = 0;
+       int                      data_sz;
+       int                      copy_sz;
+
+       /* Get LAN Page 0 header */
+       hdr.PageVersion = 0;
+       hdr.PageLength = 0;
+       hdr.PageNumber = 0;
+       hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
+       cfg.hdr = &hdr;
+       cfg.physAddr = -1;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+       cfg.dir = 0;
+       cfg.pageAddr = 0;
+       cfg.timeout = 0;
+
+       if ((rc = mpt_config(ioc, &cfg)) != 0)
+               return rc;
+
+       if (hdr.PageLength > 0) {
+               data_sz = hdr.PageLength * 4;
+               ppage0_alloc = (LANPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
+               rc = -ENOMEM;
+               if (ppage0_alloc) {
+                       memset((u8 *)ppage0_alloc, 0, data_sz);
+                       cfg.physAddr = page0_dma;
+                       cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+
+                       if ((rc = mpt_config(ioc, &cfg)) == 0) {
+                               /* save the data */
+                               copy_sz = MIN(sizeof(LANPage0_t), data_sz);
+                               memcpy(&ioc->lan_cnfg_page0, ppage0_alloc, copy_sz);
+
+                       }
+
+                       pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
+
+                       /* FIXME!
+                        *      Normalize endianness of structure data,
+                        *      by byte-swapping all > 1 byte fields!
+                        */
+
+               }
+
+               if (rc)
+                       return rc;
+       }
+
+       /* Get LAN Page 1 header */
+       hdr.PageVersion = 0;
+       hdr.PageLength = 0;
+       hdr.PageNumber = 1;
+       hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
+       cfg.hdr = &hdr;
+       cfg.physAddr = -1;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+       cfg.dir = 0;
+       cfg.pageAddr = 0;
+
+       if ((rc = mpt_config(ioc, &cfg)) != 0)
+               return rc;
+
+       if (hdr.PageLength == 0)
+               return 0;
+
+       data_sz = hdr.PageLength * 4;
+       rc = -ENOMEM;
+       ppage1_alloc = (LANPage1_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page1_dma);
+       if (ppage1_alloc) {
+               memset((u8 *)ppage1_alloc, 0, data_sz);
+               cfg.physAddr = page1_dma;
+               cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+
+               if ((rc = mpt_config(ioc, &cfg)) == 0) {
+                       /* save the data */
+                       copy_sz = MIN(sizeof(LANPage1_t), data_sz);
+                       memcpy(&ioc->lan_cnfg_page1, ppage1_alloc, copy_sz);
+               }
+
+               pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage1_alloc, page1_dma);
+
+               /* FIXME!
+                *      Normalize endianness of structure data,
+                *      by byte-swapping all > 1 byte fields!
+                */
+
+       }
+
+       return rc;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     GetFcPortPage0 - Fetch FCPort config Page0.
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @portnum: IOC Port number
+ *
+ *     Return: 0 for success
+ *     -ENOMEM if no memory available
+ *             -EPERM if not allowed due to ISR context
+ *             -EAGAIN if no msg frames currently available
+ *             -EFAULT for non-successful reply or no reply (timeout)
+ */
+static int
+GetFcPortPage0(MPT_ADAPTER *ioc, int portnum)
+{
+       ConfigPageHeader_t       hdr;
+       CONFIGPARMS              cfg;
+       FCPortPage0_t           *ppage0_alloc;
+       FCPortPage0_t           *pp0dest;
+       dma_addr_t               page0_dma;
+       int                      data_sz;
+       int                      copy_sz;
+       int                      rc;
+
+       /* Get FCPort Page 0 header */
+       hdr.PageVersion = 0;
+       hdr.PageLength = 0;
+       hdr.PageNumber = 0;
+       hdr.PageType = MPI_CONFIG_PAGETYPE_FC_PORT;
+       cfg.hdr = &hdr;
+       cfg.physAddr = -1;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+       cfg.dir = 0;
+       cfg.pageAddr = portnum;
+       cfg.timeout = 0;
+
+       if ((rc = mpt_config(ioc, &cfg)) != 0)
+               return rc;
+
+       if (hdr.PageLength == 0)
+               return 0;
+
+       data_sz = hdr.PageLength * 4;
+       rc = -ENOMEM;
+       ppage0_alloc = (FCPortPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
+       if (ppage0_alloc) {
+               memset((u8 *)ppage0_alloc, 0, data_sz);
+               cfg.physAddr = page0_dma;
+               cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+
+               if ((rc = mpt_config(ioc, &cfg)) == 0) {
+                       /* save the data */
+                       pp0dest = &ioc->fc_port_page0[portnum];
+                       copy_sz = MIN(sizeof(FCPortPage0_t), data_sz);
+                       memcpy(pp0dest, ppage0_alloc, copy_sz);
+
+                       /*
+                        *      Normalize endianness of structure data,
+                        *      by byte-swapping all > 1 byte fields!
+                        */
+                       pp0dest->Flags = le32_to_cpu(pp0dest->Flags);
+                       pp0dest->PortIdentifier = le32_to_cpu(pp0dest->PortIdentifier);
+                       pp0dest->WWNN.Low = le32_to_cpu(pp0dest->WWNN.Low);
+                       pp0dest->WWNN.High = le32_to_cpu(pp0dest->WWNN.High);
+                       pp0dest->WWPN.Low = le32_to_cpu(pp0dest->WWPN.Low);
+                       pp0dest->WWPN.High = le32_to_cpu(pp0dest->WWPN.High);
+                       pp0dest->SupportedServiceClass = le32_to_cpu(pp0dest->SupportedServiceClass);
+                       pp0dest->SupportedSpeeds = le32_to_cpu(pp0dest->SupportedSpeeds);
+                       pp0dest->CurrentSpeed = le32_to_cpu(pp0dest->CurrentSpeed);
+                       pp0dest->MaxFrameSize = le32_to_cpu(pp0dest->MaxFrameSize);
+                       pp0dest->FabricWWNN.Low = le32_to_cpu(pp0dest->FabricWWNN.Low);
+                       pp0dest->FabricWWNN.High = le32_to_cpu(pp0dest->FabricWWNN.High);
+                       pp0dest->FabricWWPN.Low = le32_to_cpu(pp0dest->FabricWWPN.Low);
+                       pp0dest->FabricWWPN.High = le32_to_cpu(pp0dest->FabricWWPN.High);
+                       pp0dest->DiscoveredPortsCount = le32_to_cpu(pp0dest->DiscoveredPortsCount);
+                       pp0dest->MaxInitiators = le32_to_cpu(pp0dest->MaxInitiators);
+
+               }
+
+               pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
+       }
+
+       return rc;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     GetIoUnitPage2 - Retrieve BIOS version and boot order information.
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *
+ *     Returns: 0 for success
+ *     -ENOMEM if no memory available
+ *             -EPERM if not allowed due to ISR context
+ *             -EAGAIN if no msg frames currently available
+ *             -EFAULT for non-successful reply or no reply (timeout)
+ */
+static int
+GetIoUnitPage2(MPT_ADAPTER *ioc)
+{
+       ConfigPageHeader_t       hdr;
+       CONFIGPARMS              cfg;
+       IOUnitPage2_t           *ppage_alloc;
+       dma_addr_t               page_dma;
+       int                      data_sz;
+       int                      rc;
+
+       /* Get the page header */
+       hdr.PageVersion = 0;
+       hdr.PageLength = 0;
+       hdr.PageNumber = 2;
+       hdr.PageType = MPI_CONFIG_PAGETYPE_IO_UNIT;
+       cfg.hdr = &hdr;
+       cfg.physAddr = -1;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+       cfg.dir = 0;
+       cfg.pageAddr = 0;
+       cfg.timeout = 0;
+
+       if ((rc = mpt_config(ioc, &cfg)) != 0)
+               return rc;
+
+       if (hdr.PageLength == 0)
+               return 0;
+
+       /* Read the config page */
+       data_sz = hdr.PageLength * 4;
+       rc = -ENOMEM;
+       ppage_alloc = (IOUnitPage2_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page_dma);
+       if (ppage_alloc) {
+               memset((u8 *)ppage_alloc, 0, data_sz);
+               cfg.physAddr = page_dma;
+               cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+
+               /* If Good, save data */
+               if ((rc = mpt_config(ioc, &cfg)) == 0)
+                       ioc->biosVersion = le32_to_cpu(ppage_alloc->BiosVersion);
+
+               pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage_alloc, page_dma);
+       }
+
+       return rc;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*     mpt_GetScsiPortSettings - read SCSI Port Page 0 and 2
+ *     @ioc: Pointer to a Adapter Strucutre
+ *     @portnum: IOC port number
+ *
+ *     Return: -EFAULT if read of config page header fails
+ *                     or if no nvram
+ *     If read of SCSI Port Page 0 fails,
+ *             NVRAM = MPT_HOST_NVRAM_INVALID  (0xFFFFFFFF)
+ *             Adapter settings: async, narrow
+ *             Return 1
+ *     If read of SCSI Port Page 2 fails,
+ *             Adapter settings valid
+ *             NVRAM = MPT_HOST_NVRAM_INVALID  (0xFFFFFFFF)
+ *             Return 1
+ *     Else
+ *             Both valid
+ *             Return 0
+ *     CHECK - what type of locking mechanisms should be used????
+ */
+static int
+mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
+{
+       u8                      *pbuf = NULL;
+       dma_addr_t               buf_dma;
+       CONFIGPARMS              cfg;
+       ConfigPageHeader_t       header;
+       int                      ii;
+       int                      data, rc = 0;
+
+       /* Allocate memory 
+        */
+       if (!ioc->spi_data.nvram) {
+               int      sz;
+               u8      *mem;
+               sz = MPT_MAX_SCSI_DEVICES * sizeof(int);
+               mem = kmalloc(sz, GFP_ATOMIC);
+               if (mem == NULL)
+                       return -EFAULT;
+
+               ioc->spi_data.nvram = (int *) mem;
+
+               dprintk((MYIOC_s_INFO_FMT "SCSI device NVRAM settings @ %p, sz=%d\n",
+                       ioc->name, ioc->spi_data.nvram, sz));
+       }
+
+       /* Invalidate NVRAM information
+        */
+       for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
+               ioc->spi_data.nvram[ii] = MPT_HOST_NVRAM_INVALID;
+       }
+
+       /* Read SPP0 header, allocate memory, then read page.
+        */
+       header.PageVersion = 0;
+       header.PageLength = 0;
+       header.PageNumber = 0;
+       header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
+       cfg.hdr = &header;
+       cfg.physAddr = -1;
+       cfg.pageAddr = portnum;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+       cfg.dir = 0;
+       cfg.timeout = 0;        /* use default */
+       if (mpt_config(ioc, &cfg) != 0)
+                return -EFAULT;
+
+       if (header.PageLength > 0) {
+               pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
+               if (pbuf) {
+                       cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+                       cfg.physAddr = buf_dma;
+                       if (mpt_config(ioc, &cfg) != 0) {
+                               ioc->spi_data.maxBusWidth = MPT_NARROW;
+                               ioc->spi_data.maxSyncOffset = 0;
+                               ioc->spi_data.minSyncFactor = MPT_ASYNC;
+                               ioc->spi_data.busType = MPT_HOST_BUS_UNKNOWN;
+                               rc = 1;
+                       } else {
+                               /* Save the Port Page 0 data
+                                */
+                               SCSIPortPage0_t  *pPP0 = (SCSIPortPage0_t  *) pbuf;
+                               pPP0->Capabilities = le32_to_cpu(pPP0->Capabilities);
+                               pPP0->PhysicalInterface = le32_to_cpu(pPP0->PhysicalInterface);
+
+                               ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0;
+                               data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK;
+                               if (data) {
+                                       ioc->spi_data.maxSyncOffset = (u8) (data >> 16);
+                                       data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK;
+                                       ioc->spi_data.minSyncFactor = (u8) (data >> 8);
+                               } else {
+                                       ioc->spi_data.maxSyncOffset = 0;
+                                       ioc->spi_data.minSyncFactor = MPT_ASYNC;
+                               }
+
+                               ioc->spi_data.busType = pPP0->PhysicalInterface & MPI_SCSIPORTPAGE0_PHY_SIGNAL_TYPE_MASK;
+
+                               /* Update the minSyncFactor based on bus type.
+                                */
+                               if ((ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD) ||
+                                       (ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE))  {
+
+                                       if (ioc->spi_data.minSyncFactor < MPT_ULTRA)
+                                               ioc->spi_data.minSyncFactor = MPT_ULTRA;
+                               }
+                       }
+                       if (pbuf) {
+                               pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
+                               pbuf = NULL;
+                       }
+               }
+       }
+
+       /* SCSI Port Page 2 - Read the header then the page.
+        */
+       header.PageVersion = 0;
+       header.PageLength = 0;
+       header.PageNumber = 2;
+       header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
+       cfg.hdr = &header;
+       cfg.physAddr = -1;
+       cfg.pageAddr = portnum;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+       cfg.dir = 0;
+       if (mpt_config(ioc, &cfg) != 0)
+               return -EFAULT;
+
+       if (header.PageLength > 0) {
+               /* Allocate memory and read SCSI Port Page 2
+                */
+               pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
+               if (pbuf) {
+                       cfg.action = MPI_CONFIG_ACTION_PAGE_READ_NVRAM;
+                       cfg.physAddr = buf_dma;
+                       if (mpt_config(ioc, &cfg) != 0) {
+                               /* Nvram data is left with INVALID mark
+                                */
+                               rc = 1;
+                       } else {
+                               SCSIPortPage2_t *pPP2 = (SCSIPortPage2_t  *) pbuf;
+                               MpiDeviceInfo_t *pdevice = NULL;
+
+                               /* Save the Port Page 2 data
+                                * (reformat into a 32bit quantity)
+                                */
+                               for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
+                                       pdevice = &pPP2->DeviceSettings[ii];
+                                       data = (le16_to_cpu(pdevice->DeviceFlags) << 16) |
+                                               (pdevice->SyncFactor << 8) | pdevice->Timeout;
+                                       ioc->spi_data.nvram[ii] = data;
+                               }
+                       }
+
+                       pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
+                       pbuf = NULL;
+               }
+       }
+
+       /* Update Adapter limits with those from NVRAM
+        * Comment: Don't need to do this. Target performance
+        * parameters will never exceed the adapters limits.
+        */
+
+       return rc;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*     mpt_readScsiDevicePageHeaders - save version and length of SDP1
+ *     @ioc: Pointer to a Adapter Strucutre
+ *     @portnum: IOC port number
+ *
+ *     Return: -EFAULT if read of config page header fails
+ *             or 0 if success.
+ */
+static int
+mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum)
+{
+       CONFIGPARMS              cfg;
+       ConfigPageHeader_t       header;
+
+       /* Read the SCSI Device Page 1 header
+        */
+       header.PageVersion = 0;
+       header.PageLength = 0;
+       header.PageNumber = 1;
+       header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
+       cfg.hdr = &header;
+       cfg.physAddr = -1;
+       cfg.pageAddr = portnum;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+       cfg.dir = 0;
+       cfg.timeout = 0;
+       if (mpt_config(ioc, &cfg) != 0)
+                return -EFAULT;
+
+       ioc->spi_data.sdp1version = cfg.hdr->PageVersion;
+       ioc->spi_data.sdp1length = cfg.hdr->PageLength;
+
+       header.PageVersion = 0;
+       header.PageLength = 0;
+       header.PageNumber = 0;
+       header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
+       if (mpt_config(ioc, &cfg) != 0)
+                return -EFAULT;
+
+       ioc->spi_data.sdp0version = cfg.hdr->PageVersion;
+       ioc->spi_data.sdp0length = cfg.hdr->PageLength;
+
+       return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes 
+ *     @ioc: Pointer to a Adapter Strucutre
+ *     @portnum: IOC port number
+ *
+ *     Return:
+ *     0 on success
+ *     -EFAULT if read of config page header fails or data pointer not NULL
+ *     -ENOMEM if pci_alloc failed
  */
 static int
-GetLanConfigPages(MPT_ADAPTER *ioc)
+mpt_findImVolumes(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;
+       IOCPage2_t              *pIoc2 = NULL;
+       IOCPage3_t              *pIoc3 = NULL;
+       ConfigPageIoc2RaidVol_t *pIocRv = NULL;
+       u8                      *mem;
+       dma_addr_t               ioc2_dma;
+       dma_addr_t               ioc3_dma;
+       CONFIGPARMS              cfg;
+       ConfigPageHeader_t       header;
+       int                      jj;
+       int                      rc = 0;
+       int                      iocpage2sz;
+       int                      iocpage3sz = 0;
+       u8                       nVols, nPhys;
+       u8                       vid, vbus, vioc;
+
+       if (ioc->spi_data.pIocPg3)
+               return -EFAULT; 
+
+       /* Read IOCP2 header then the page.
+        */
+       header.PageVersion = 0;
+       header.PageLength = 0;
+       header.PageNumber = 2;
+       header.PageType = MPI_CONFIG_PAGETYPE_IOC;
+       cfg.hdr = &header;
+       cfg.physAddr = -1;
+       cfg.pageAddr = 0;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+       cfg.dir = 0;
+       cfg.timeout = 0;
+       if (mpt_config(ioc, &cfg) != 0)
+                return -EFAULT;
+
+       if (header.PageLength == 0)
+               return -EFAULT;
+
+       iocpage2sz = header.PageLength * 4;
+       pIoc2 = pci_alloc_consistent(ioc->pcidev, iocpage2sz, &ioc2_dma);
+       if (!pIoc2)
+               return -ENOMEM;
 
-/* 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));
+       cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+       cfg.physAddr = ioc2_dma;
+       if (mpt_config(ioc, &cfg) != 0)
+               goto done_and_free;
 
-       i = HandShakeReqAndReply(ioc, req_sz, (u32*)&config_req,
-                               reply_sz, (u16*)&config_reply, 3);
-       pci_unmap_single(ioc->pcidev, page0_dma, data_sz, PCI_DMA_FROMDEVICE);
-       if (i != 0)
-               return i;
+       /* Identify RAID Volume Id's */
+       nVols = pIoc2->NumActiveVolumes;
+       if ( nVols == 0) {
+               /* No RAID Volumes.  Done.
+                */
+       } else {
+               /* At least 1 RAID Volume
+                */
+               pIocRv = pIoc2->RaidVolume;
+               ioc->spi_data.isRaid = 0;
+               for (jj = 0; jj < nVols; jj++, pIocRv++) {
+                       vid = pIocRv->VolumeID;
+                       vbus = pIocRv->VolumeBus;
+                       vioc = pIocRv->VolumeIOC;
+
+                       /* find the match
+                        */
+                       if (vbus == 0) {
+                               ioc->spi_data.isRaid |= (1 << vid);
+                       } else {
+                               /* Error! Always bus 0
+                                */
+                       }
+               }
+       }
 
-       /*  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));
+       /* Identify Hidden Physical Disk Id's */
+       nPhys = pIoc2->NumActivePhysDisks;
+       if (nPhys == 0) {
+               /* No physical disks. Done.
+                */
+       } else {
+               /* There is at least one physical disk.
+                * Read and save IOC Page 3
+                */
+               header.PageVersion = 0;
+               header.PageLength = 0;
+               header.PageNumber = 3;
+               header.PageType = MPI_CONFIG_PAGETYPE_IOC;
+               cfg.hdr = &header;
+               cfg.physAddr = -1;
+               cfg.pageAddr = 0;
+               cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+               cfg.dir = 0;
+               cfg.timeout = 0;
+               if (mpt_config(ioc, &cfg) != 0)
+                       goto done_and_free;
+
+               if (header.PageLength == 0)
+                       goto done_and_free;
+
+               /* Read Header good, alloc memory
+                */
+               iocpage3sz = header.PageLength * 4;
+               pIoc3 = pci_alloc_consistent(ioc->pcidev, iocpage3sz, &ioc3_dma);
+               if (!pIoc3)
+                       goto done_and_free;
 
-       i = HandShakeReqAndReply(ioc, req_sz, (u32*)&config_req,
-                               reply_sz, (u16*)&config_reply, 3);
-       pci_unmap_single(ioc->pcidev, page1_dma, data_sz, PCI_DMA_FROMDEVICE);
-       if (i != 0)
-               return i;
+               /* Read the Page and save the data
+                * into malloc'd memory.
+                */
+               cfg.physAddr = ioc3_dma;
+               cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+               if (mpt_config(ioc, &cfg) == 0) {
+                       mem = kmalloc(iocpage3sz, GFP_ATOMIC);
+                       if (mem) {
+                               memcpy(mem, (u8 *)pIoc3, iocpage3sz);
+                               ioc->spi_data.pIocPg3 = (IOCPage3_t *) mem;
+                       }
+               }
+       }
 
-       /*  Now byte swap the necessary LANPage1 fields  */
+done_and_free:
+       if (pIoc2) {
+               pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma);
+               pIoc2 = NULL;
+       }
 
-       return 0;
+       if (pIoc3) {
+               pci_free_consistent(ioc->pcidev, iocpage3sz, pIoc3, ioc3_dma);
+               pIoc3 = NULL;
+       }
+
+       return rc;
 }
 
+
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/**
+/*
  *     SendEventNotification - Send EventNotification (on or off) request
  *     to MPT adapter.
  *     @ioc: Pointer to MPT_ADAPTER structure
@@ -2817,13 +4565,13 @@ SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch)
 
        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",
+               dprintk((MYIOC_s_WARN_FMT "Unable to allocate 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));
+       dprintk((MYIOC_s_INFO_FMT "Sending EventNotification(%d)\n", ioc->name, EvSwitch));
 
        evnp->Function = MPI_FUNCTION_EVENT_NOTIFICATION;
        evnp->ChainOffset = 0;
@@ -2847,13 +4595,13 @@ 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",
+               printk(MYIOC_s_WARN_FMT "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));
+       dprintk((MYIOC_s_INFO_FMT "Sending EventAck\n", ioc->name));
 
        pAck->Function     = MPI_FUNCTION_EVENT_ACK;
        pAck->ChainOffset  = 0;
@@ -2866,25 +4614,224 @@ SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp)
        return 0;
 }
 
-#ifdef CONFIG_PROC_FS          /* { */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mpt_config - Generic function to issue config message
+ *     @ioc - Pointer to an adapter structure
+ *     @cfg - Pointer to a configuration structure. Struct contains
+ *             action, page address, direction, physical address
+ *             and pointer to a configuration page header
+ *             Page header is updated.
+ *
+ *     Returns 0 for success
+ *     -EPERM if not allowed due to ISR context
+ *     -EAGAIN if no msg frames currently available
+ *     -EFAULT for non-successful reply or no reply (timeout)
+ */
+int
+mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
+{
+       Config_t        *pReq;
+       MPT_FRAME_HDR   *mf;
+       unsigned long    flags;
+       int              ii, rc;
+       int              flagsLength;
+       int              in_isr;
+
+       /* (Bugzilla:fibrebugs, #513)
+        * Bug fix (part 1)!  20010905 -sralston
+        *      Prevent calling wait_event() (below), if caller happens
+        *      to be in ISR context, because that is fatal!
+        */
+       in_isr = in_interrupt();
+       if (in_isr) {
+               dprintk((MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",
+                               ioc->name));
+               return -EPERM;
+       }
+
+       /* Get and Populate a free Frame
+        */
+       if ((mf = mpt_get_msg_frame(mpt_base_index, ioc->id)) == NULL) {
+               dprintk((MYIOC_s_WARN_FMT "mpt_config: no msg frames!\n",
+                               ioc->name));
+               return -EAGAIN;
+       }
+       pReq = (Config_t *)mf;
+       pReq->Action = pCfg->action;
+       pReq->Reserved = 0;
+       pReq->ChainOffset = 0;
+       pReq->Function = MPI_FUNCTION_CONFIG;
+       pReq->Reserved1[0] = 0;
+       pReq->Reserved1[1] = 0;
+       pReq->Reserved1[2] = 0;
+       pReq->MsgFlags = 0;
+       for (ii=0; ii < 8; ii++)
+               pReq->Reserved2[ii] = 0;
+
+       pReq->Header.PageVersion = pCfg->hdr->PageVersion;
+       pReq->Header.PageLength = pCfg->hdr->PageLength;
+       pReq->Header.PageNumber = pCfg->hdr->PageNumber;
+       pReq->Header.PageType = (pCfg->hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);
+       pReq->PageAddress = cpu_to_le32(pCfg->pageAddr);
+
+       /* Add a SGE to the config request.
+        */
+       if (pCfg->dir)
+               flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
+       else
+               flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
+
+       flagsLength |= pCfg->hdr->PageLength * 4;
+
+       mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr);
+
+       dprintk((MYIOC_s_INFO_FMT "Sending Config request type %d, page %d and action %d\n",
+               ioc->name, pReq->Header.PageType, pReq->Header.PageNumber, pReq->Action));
+
+       /* Append pCfg pointer to end of mf
+        */
+       *((void **) (((u8 *) mf) + (ioc->req_sz - sizeof(void *)))) =  (void *) pCfg;
+
+       /* Initalize the timer
+        */
+       init_timer(&pCfg->timer);
+       pCfg->timer.data = (unsigned long) ioc;
+       pCfg->timer.function = mpt_timer_expired;
+       pCfg->wait_done = 0;
+
+       /* Set the timer; ensure 10 second minimum */
+       if (pCfg->timeout < 10)
+               pCfg->timer.expires = jiffies + HZ*10;
+       else
+               pCfg->timer.expires = jiffies + HZ*pCfg->timeout;
+
+       /* Add to end of Q, set timer and then issue this command */
+       spin_lock_irqsave(&ioc->FreeQlock, flags);
+       Q_ADD_TAIL(&ioc->configQ.head, &pCfg->linkage, Q_ITEM);
+       spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+
+       add_timer(&pCfg->timer);
+       mpt_put_msg_frame(mpt_base_index, ioc->id, mf);
+       wait_event(mpt_waitq, pCfg->wait_done);
+
+       /* mf has been freed - do not access */
+
+       rc = pCfg->status;
+
+       return rc;
+}
+
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
- *     procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff...
+ *     mpt_timer_expired - Call back for timer process.
+ *     Used only internal config functionality.
+ *     @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
+ */
+static void
+mpt_timer_expired(unsigned long data)
+{
+       MPT_ADAPTER *ioc = (MPT_ADAPTER *) data;
+
+       dprintk((MYIOC_s_WARN_FMT "mpt_timer_expired! \n", ioc->name));
+
+       /* Perform a FW reload */
+       if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0)
+               printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", ioc->name);
+
+       /* No more processing.
+        * Hard reset clean-up will wake up
+        * process and free all resources.
+        */
+       dprintk((MYIOC_s_WARN_FMT "mpt_timer_expired complete!\n", ioc->name));
+
+       return;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     mpt_ioc_reset - Base cleanup for hard reset
+ *     @ioc: Pointer to the adapter structure
+ *     @reset_phase: Indicates pre- or post-reset functionality
+ *
+ *     Remark: Free's resources with internally generated commands.
  */
+static int
+mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
+{
+       CONFIGPARMS *pCfg;
+       unsigned long flags;
+
+       dprintk((KERN_WARNING MYNAM
+                       ": IOC %s_reset routed to MPT base driver!\n",
+                       reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post"));
+
+       if (reset_phase == MPT_IOC_PRE_RESET) {
+               /* If the internal config Q is not empty -
+                * delete timer. MF resources will be freed when
+                * the FIFO's are primed.
+                */
+               spin_lock_irqsave(&ioc->FreeQlock, flags);
+               if (! Q_IS_EMPTY(&ioc->configQ)){
+                       pCfg = (CONFIGPARMS *)ioc->configQ.head;
+                       do {
+                               del_timer(&pCfg->timer);
+                               pCfg = (CONFIGPARMS *) (pCfg->linkage.forw);
+                       } while (pCfg != (CONFIGPARMS *)&ioc->configQ);
+               }
+               spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+
+       } else {
+               CONFIGPARMS *pNext;
+
+               /* Search the configQ for internal commands. 
+                * Flush the Q, and wake up all suspended threads.
+                */
+#if 1
+               spin_lock_irqsave(&ioc->FreeQlock, flags);
+               if (! Q_IS_EMPTY(&ioc->configQ)){
+                       pCfg = (CONFIGPARMS *)ioc->configQ.head;
+                       do {
+                               pNext = (CONFIGPARMS *) pCfg->linkage.forw;
+
+                               Q_DEL_ITEM(&pCfg->linkage);
+
+                               pCfg->status = MPT_CONFIG_ERROR;
+                               pCfg->wait_done = 1;
+                               wake_up(&mpt_waitq);
 
-#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;                     \
+                               pCfg = pNext;
+                       } while (pCfg != (CONFIGPARMS *)&ioc->configQ);
+               }
+               spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+#else
+               while (1) {
+                       spin_lock_irqsave(&ioc->FreeQlock, flags);
+                       if (! Q_IS_EMPTY(&ioc->configQ)){
+                               spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+                               break;
+                       }
+                       pCfg = (CONFIGPARMS *)ioc->configQ.head;
+
+                       Q_DEL_ITEM(&pCfg->linkage);
+                       spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+
+                       pCfg->status = MPT_CONFIG_ERROR;
+                       pCfg->wait_done = 1;
+                       wake_up(&mpt_waitq);
+               }
+#endif
+       }
+
+       return 1;               /* currently means nothing really */
 }
 
+
+#ifdef CONFIG_PROC_FS          /* { */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff...
+ */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
  *     procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries.
@@ -2894,71 +4841,62 @@ SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp)
 static int
 procmpt_create(void)
 {
-       MPT_ADAPTER *ioc;
-       struct proc_dir_entry *ent;
-       int errcnt = 0;
+       MPT_ADAPTER             *ioc;
+       struct proc_dir_entry   *ent;
+       int      ii;
 
        /*
-        *      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
+        *      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)
+       mpt_proc_root_dir = proc_mkdir(MPT_PROCFS_MPTBASEDIR, NULL);
+       if (mpt_proc_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++;
+       for (ii=0; ii < MPT_PROC_ENTRIES; ii++) {
+               ent = create_proc_entry(mpt_proc_list[ii].name,
+                               S_IFREG|S_IRUGO, mpt_proc_root_dir);
+               if (!ent) {
+                       printk(KERN_WARNING MYNAM
+                                       ": WARNING - Could not create /proc/mpt/%s entry\n",
+                                       mpt_proc_list[ii].name);
+                       continue;
                }
+               ent->read_proc = mpt_proc_list[ii].f;
+               ent->data      = NULL;
        }
 
+       ioc = mpt_adapter_find_first();
        while (ioc != NULL) {
-               char pname[32];
-               int namelen;
+               struct proc_dir_entry   *dent;
                /*
                 *  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) {
+               if ((dent = proc_mkdir(ioc->name, mpt_proc_root_dir)) != NULL) {
                        /*
-                        *  And populate it with: "summary" and "dbg" file entries.
+                        *  And populate it with mpt_ioc_proc_list[] 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);
+                       for (ii=0; ii < MPT_IOC_PROC_ENTRIES; ii++) {
+                               ent = create_proc_entry(mpt_ioc_proc_list[ii].name,
+                                               S_IFREG|S_IRUGO, dent);
+                               if (!ent) {
+                                       printk(KERN_WARNING MYNAM
+                                                       ": WARNING - Could not create /proc/mpt/%s/%s entry!\n",
+                                                       ioc->name,
+                                                       mpt_ioc_proc_list[ii].name);
+                                       continue;
+                               }
+                               ent->read_proc = mpt_ioc_proc_list[ii].f;
+                               ent->data      = ioc;
                        }
-//#endif
                } else {
-                       errcnt++;
-                       printk(KERN_WARNING MYNAM ": %s: WARNING - Could not create /proc/%s entry!\n",
-                                       ioc->name, pname);
-
+                       printk(MYIOC_s_WARN_FMT "Could not create /proc/mpt/%s subdir entry!\n",
+                                       ioc->name, mpt_ioc_proc_list[ii].name);
                }
-
                ioc = mpt_adapter_find_next(ioc);
        }
 
-       if (errcnt) {
-//             remove_proc_entry("mpt", 0);
-               return -ENOTDIR;
-       }
-
        return 0;
 }
 
@@ -2971,44 +4909,44 @@ procmpt_create(void)
 static int
 procmpt_destroy(void)
 {
-       MPT_ADAPTER *ioc;
+       MPT_ADAPTER     *ioc;
+       int              ii;
 
-       if (!procmpt_root_dir)
+       if (!mpt_proc_root_dir)
                return 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
+        *      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;
+
+               namelen = sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name);
+
                /*
                 *  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);
+               for (ii=0; ii < MPT_IOC_PROC_ENTRIES; ii++) {
+                       (void) sprintf(pname+namelen, "/%s", mpt_ioc_proc_list[ii].name);
+                       remove_proc_entry(pname, NULL);
+               }
+
+               remove_proc_entry(ioc->name, mpt_proc_root_dir);
 
                ioc = mpt_adapter_find_next(ioc);
        }
 
-       if (atomic_read((atomic_t *)&procmpt_root_dir->count) == 0) {
-               remove_proc_entry(MPT_PROCFS_MPTBASEDIR, 0);
-               procmpt_root_dir = NULL;
+       for (ii=0; ii < MPT_PROC_ENTRIES; ii++)
+               remove_proc_entry(mpt_proc_list[ii].name, mpt_proc_root_dir);
+
+       if (atomic_read((atomic_t *)&mpt_proc_root_dir->count) == 0) {
+               remove_proc_entry(MPT_PROCFS_MPTBASEDIR, NULL);
+               mpt_proc_root_dir = NULL;
                return 0;
        }
 
@@ -3016,23 +4954,23 @@ procmpt_destroy(void)
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/**
- *     procmpt_read_summary - Handle read request from /proc/mpt/summary
+/*
+ *     procmpt_summary_read - Handle read request from /proc/mpt/summary
  *     or from /proc/mpt/iocN/summary.
- *     @page: Pointer to area to write information
+ *     @buf: Pointer to area to write information
  *     @start: Pointer to start pointer
- *     @off: Offset to start writing
- *     @count: 
+ *     @offset: Offset to start writing
+ *     @request:
  *     @eof: Pointer to EOF integer
- *     @data: Pointer 
+ *     @data: Pointer
  *
- *     Returns numbers of characters written to process performing the read.
+ *     Returns number 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)
+procmpt_summary_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
 {
        MPT_ADAPTER *ioc;
-       char *out = page;
+       char *out = buf;
        int len;
 
        if (data == NULL)
@@ -3040,84 +4978,196 @@ procmpt_read_summary(char *page, char **start, off_t off, int count, int *eof, v
        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, 1);
 
                out += more;
-               if ((out-page) >= count) {
+               if ((out-buf) >= request) {
                        break;
                }
 
                if (data == NULL)
                        ioc = mpt_adapter_find_next(ioc);
                else
-                       ioc = NULL;                             /* force exit for iocN */
+                       ioc = NULL;             /* force exit for iocN */
        }
-       len = out - page;
+       len = out - buf;
 
-       PROC_MPT_READ_RETURN(page,start,off,count,eof,len);
+       MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
 }
 
-// debug aid!
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/**
- *     procmpt_read_dbg - Handle read request from /proc/mpt/iocN/dbg.
- *     @page: Pointer to area to write information
+/*
+ *     procmpt_version_read - Handle read request from /proc/mpt/version.
+ *     @buf: Pointer to area to write information
  *     @start: Pointer to start pointer
- *     @off: Offset to start writing
- *     @count: 
+ *     @offset: Offset to start writing
+ *     @request:
  *     @eof: Pointer to EOF integer
- *     @data: Pointer 
+ *     @data: Pointer
  *
- *     Returns numbers of characters written to process performing the read.
+ *     Returns number 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)
+procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
 {
-       MPT_ADAPTER *ioc;
-       char *out = page;
-       int len;
+       int      ii;
+       int      scsi, lan, ctl, targ, dmp;
+       char    *drvname;
+       int      len;
+
+       len = sprintf(buf, "%s-%s\n", "mptlinux", MPT_LINUX_VERSION_COMMON);
+       len += sprintf(buf+len, "  Fusion MPT base driver\n");
+
+       scsi = lan = ctl = targ = dmp = 0;
+       for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
+               drvname = NULL;
+               if (MptCallbacks[ii]) {
+                       switch (MptDriverClass[ii]) {
+                       case MPTSCSIH_DRIVER:
+                               if (!scsi++) drvname = "SCSI host";
+                               break;
+                       case MPTLAN_DRIVER:
+                               if (!lan++) drvname = "LAN";
+                               break;
+                       case MPTSTM_DRIVER:
+                               if (!targ++) drvname = "SCSI target";
+                               break;
+                       case MPTCTL_DRIVER:
+                               if (!ctl++) drvname = "ioctl";
+                               break;
+                       case MPTDMP_DRIVER:
+                               if (!dmp++) drvname = "DMP";
+                               break;
+                       }
+
+                       if (drvname)
+                               len += sprintf(buf+len, "  Fusion MPT %s driver\n", drvname);
+                       /*
+                        *      Handle isense special case, because it
+                        *      doesn't do a formal mpt_register call.
+                        */
+                       if (isense_idx == ii)
+                               len += sprintf(buf+len, "  Fusion MPT isense driver\n");
+               } else
+                       break;
+       }
 
-       ioc = data;
+       MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
+}
 
-       while (ioc) {
-               int     more = 0;
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     procmpt_iocinfo_read - Handle read request from /proc/mpt/iocN/info.
+ *     @buf: Pointer to area to write information
+ *     @start: Pointer to start pointer
+ *     @offset: Offset to start writing
+ *     @request:
+ *     @eof: Pointer to EOF integer
+ *     @data: Pointer
+ *
+ *     Returns number of characters written to process performing the read.
+ */
+static int
+procmpt_iocinfo_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
+{
+       MPT_ADAPTER     *ioc = data;
+       int              len;
+       char             expVer[32];
+       int              sz;
+       int              p;
+
+       mpt_get_fw_exp_ver(expVer, ioc);
 
-               mpt_print_ioc_facts(ioc, out, &more, 0);
+       len = sprintf(buf, "%s:", ioc->name);
+       if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
+               len += sprintf(buf+len, "  (f/w download boot flag set)");
+//     if (ioc->facts.IOCExceptions & MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL)
+//             len += sprintf(buf+len, "  CONFIG_CHECKSUM_FAIL!");
+
+       len += sprintf(buf+len, "\n  ProductID = 0x%04x (%s)\n",
+                       ioc->facts.ProductID,
+                       ioc->prod_name);
+       len += sprintf(buf+len, "  FWVersion = 0x%08x%s", ioc->facts.FWVersion.Word, expVer);
+       if (ioc->facts.FWImageSize)
+               len += sprintf(buf+len, " (fw_size=%d)", ioc->facts.FWImageSize);
+       len += sprintf(buf+len, "\n  MsgVersion = 0x%04x\n", ioc->facts.MsgVersion);
+       len += sprintf(buf+len, "  FirstWhoInit = 0x%02x\n", ioc->FirstWhoInit);
+       len += sprintf(buf+len, "  EventState = 0x%02x\n", ioc->facts.EventState);
+
+       len += sprintf(buf+len, "  CurrentHostMfaHighAddr = 0x%08x\n",
+                       ioc->facts.CurrentHostMfaHighAddr);
+       len += sprintf(buf+len, "  CurrentSenseBufferHighAddr = 0x%08x\n",
+                       ioc->facts.CurrentSenseBufferHighAddr);
 
-               out += more;
-               if ((out-page) >= count) {
-                       break;
+       len += sprintf(buf+len, "  MaxChainDepth = 0x%02x frames\n", ioc->facts.MaxChainDepth);
+       len += sprintf(buf+len, "  MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize);
+
+       len += sprintf(buf+len, "  RequestFrames @ 0x%p (Dma @ 0x%p)\n",
+                                       (void *)ioc->req_alloc, (void *)(ulong)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;
+       len += sprintf(buf+len, "    {CurReqSz=%d} x {CurReqDepth=%d} = %d bytes ^= 0x%x\n",
+                                       ioc->req_sz, ioc->req_depth, ioc->req_sz*ioc->req_depth, sz);
+       len += sprintf(buf+len, "    {MaxReqSz=%d}   {MaxReqDepth=%d}\n",
+                                       4*ioc->facts.RequestFrameSize,
+                                       ioc->facts.GlobalCredits);
+
+       len += sprintf(buf+len, "  ReplyFrames   @ 0x%p (Dma @ 0x%p)\n",
+                                       (void *)ioc->reply_alloc, (void *)(ulong)ioc->reply_alloc_dma);
+       sz = (ioc->reply_sz * ioc->reply_depth) + 128;
+       len += sprintf(buf+len, "    {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n",
+                                       ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz);
+       len += sprintf(buf+len, "    {MaxRepSz=%d}   {MaxRepDepth=%d}\n",
+                                       ioc->facts.CurReplyFrameSize,
+                                       ioc->facts.ReplyQueueDepth);
+
+       len += sprintf(buf+len, "  MaxDevices = %d\n",
+                       (ioc->facts.MaxDevices==0) ? 255 : ioc->facts.MaxDevices);
+       len += sprintf(buf+len, "  MaxBuses = %d\n", ioc->facts.MaxBuses);
+
+       /* per-port info */
+       for (p=0; p < ioc->facts.NumberOfPorts; p++) {
+               len += sprintf(buf+len, "  PortNumber = %d (of %d)\n",
+                               p+1,
+                               ioc->facts.NumberOfPorts);
+               if ((int)ioc->chip_type <= (int)FC929) {
+                       if (ioc->pfacts[p].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
+                               u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
+                               len += sprintf(buf+len, "    LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
+                                               a[5], a[4], a[3], a[2], a[1], a[0]);
+                       }
+                       len += sprintf(buf+len, "    WWN = %08X%08X:%08X%08X\n",
+                                       ioc->fc_port_page0[p].WWNN.High,
+                                       ioc->fc_port_page0[p].WWNN.Low,
+                                       ioc->fc_port_page0[p].WWPN.High,
+                                       ioc->fc_port_page0[p].WWPN.Low);
                }
-               ioc = NULL;
        }
-       len = out - page;
 
-       PROC_MPT_READ_RETURN(page,start,off,count,eof,len);
+       MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
 }
+
 #endif         /* CONFIG_PROC_FS } */
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 static void
 mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc)
 {
-       if ((ioc->facts.FWVersion & 0xF000) == 0xE000)
+       buf[0] ='\0';
+       if ((ioc->facts.FWVersion.Word >> 24) == 0x0E) {
                sprintf(buf, " (Exp %02d%02d)",
-                       (ioc->facts.FWVersion & 0x0F00) >> 8,   /* Month */
-                       ioc->facts.FWVersion & 0x001F);         /* Day */
-       else
-               buf[0] ='\0';
+                       (ioc->facts.FWVersion.Word >> 16) & 0x00FF,     /* Month */
+                       (ioc->facts.FWVersion.Word >> 8) & 0x1F);       /* Day */
 
-       /* insider hack! */
-       if (ioc->facts.FWVersion & 0x0080) {
-               strcat(buf, " [MDBG]");
+               /* insider hack! */
+               if ((ioc->facts.FWVersion.Word >> 8) & 0x80)
+                       strcat(buf, " [MDBG]");
        }
 }
 
@@ -3130,8 +5180,8 @@ mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc)
  *     @len: Offset at which to start writing in buffer
  *     @showlan: Display LAN stuff?
  *
- *     This routine writes (english readable) ASCII text, which represents
- *     a summary of IOC information, to a 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, int showlan)
@@ -3144,11 +5194,11 @@ mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int sh
        /*
         *  Shorter summary of attached ioc's...
         */
-       y = sprintf(buffer+len, "%s: %s, %s%04xh%s, Ports=%d, MaxQ=%d",
+       y = sprintf(buffer+len, "%s: %s, %s%08xh%s, Ports=%d, MaxQ=%d",
                        ioc->name,
                        ioc->prod_name,
                        MPT_FW_REV_MAGIC_ID_STRING,     /* "FwRev=" or somesuch */
-                       ioc->facts.FWVersion,
+                       ioc->facts.FWVersion.Word,
                        expVer,
                        ioc->facts.NumberOfPorts,
                        ioc->req_depth);
@@ -3159,8 +5209,11 @@ mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int sh
                        a[5], a[4], a[3], a[2], a[1], a[0]);
        }
 
-       if (ioc->pci_irq < 100)
-               y += sprintf(buffer+len+y, ", IRQ=%d", ioc->pci_irq);
+#ifndef __sparc__
+       y += sprintf(buffer+len+y, ", IRQ=%d", ioc->pci_irq);
+#else
+       y += sprintf(buffer+len+y, ", IRQ=%s", __irq_itoa(ioc->pci_irq));
+#endif
 
        if (!ioc->active)
                y += sprintf(buffer+len+y, " (disabled)");
@@ -3170,76 +5223,67 @@ mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int sh
        *size = y;
 }
 
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     Reset Handling
+ */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
- *     mpt_print_ioc_facts - Write ASCII summary of IOC facts to a buffer.
+ *     mpt_HardResetHandler - Generic reset handler, issue SCSI Task
+ *     Management call based on input arg values.  If TaskMgmt fails,
+ *     return associated SCSI request.
  *     @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
+ *     @sleepFlag: Indicates if sleep or schedule must be called.
+ *
+ *     Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
+ *     or a non-interrupt thread.  In the former, must not call schedule().
+ *
+ *     Remark: A return of -1 is a FATAL error case, as it means a
+ *     FW reload/initialization failed.
  *
- *     This routine writes (english readable) ASCII text, which represents
- *     a summary of the IOC facts, to a buffer.
+ *     Returns 0 for SUCCESS or -1 if FAILED.
  */
-void
-mpt_print_ioc_facts(MPT_ADAPTER *ioc, char *buffer, int *size, int len)
+int
+mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
 {
-       char expVer[32];
-       char iocName[16];
-       int sz;
-       int y;
-       int p;
-
-       mpt_get_fw_exp_ver(expVer, ioc);
+       int              rc;
+       unsigned long    flags;
 
-       strcpy(iocName, ioc->name);
-       y = sprintf(buffer+len, "%s:\n", iocName);
+       dprintk((MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name));
+#ifdef MFCNT
+       printk(MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name);
+       printk("MF count 0x%x !\n", ioc->mfcnt);
+#endif
 
-       y += sprintf(buffer+len+y, "  ProductID = 0x%04x\n", ioc->facts.ProductID);
-       for (p=0; p < ioc->facts.NumberOfPorts; p++) {
-               y += sprintf(buffer+len+y, "  PortNumber = %d (of %d)\n",
-                       p+1,
-                       ioc->facts.NumberOfPorts);
-               if (ioc->pfacts[p].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->facts.FWVersion, expVer);
-       y += sprintf(buffer+len+y, "  MsgVersion = 0x%04x\n", ioc->facts.MsgVersion);
-       y += sprintf(buffer+len+y, "  FirstWhoInit = 0x%02x\n", ioc->FirstWhoInit);
-       y += sprintf(buffer+len+y, "  EventState = 0x%02x\n", ioc->facts.EventState);
-       y += sprintf(buffer+len+y, "  CurrentHostMfaHighAddr = 0x%08x\n",
-                       ioc->facts.CurrentHostMfaHighAddr);
-       y += sprintf(buffer+len+y, "  CurrentSenseBufferHighAddr = 0x%08x\n",
-                       ioc->facts.CurrentSenseBufferHighAddr);
-       y += sprintf(buffer+len+y, "  MaxChainDepth = 0x%02x frames\n", ioc->facts.MaxChainDepth);
-       y += sprintf(buffer+len+y, "  MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize);
+       /* Reset the adapter. Prevent more than 1 call to
+        * mpt_do_ioc_recovery at any instant in time.
+        */
+       spin_lock_irqsave(&ioc->diagLock, flags);
+       if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)){
+               spin_unlock_irqrestore(&ioc->diagLock, flags);
+               return 0;
+       } else {
+               ioc->diagPending = 1;
+       }
+       spin_unlock_irqrestore(&ioc->diagLock, flags);
 
-       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...
+       /* FIXME: If do_ioc_recovery fails, repeat....
         */
-       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->facts.RequestFrameSize,
-                                       ioc->facts.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->facts.CurReplyFrameSize,
-                                       ioc->facts.ReplyQueueDepth);
+       if ((rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag)) != 0) {
+               printk(KERN_WARNING MYNAM ": WARNING - (%d) Cannot recover %s\n",
+                       rc, ioc->name);
+       }
 
-       *size = y;
+       spin_lock_irqsave(&ioc->diagLock, flags);
+       ioc->diagPending = 0;
+       if (ioc->alt_ioc)
+               ioc->alt_ioc->diagPending = 0;
+       spin_unlock_irqrestore(&ioc->diagLock, flags);
+
+       dprintk((MYIOC_s_INFO_FMT "HardResetHandler rc = %d!\n", ioc->name, rc));
+
+       return rc;
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -3268,7 +5312,7 @@ EventDescriptionStr(u8 event, u32 evData0)
                ds = "External Bus Reset";
                break;
        case MPI_EVENT_RESCAN:
-               ds = "Bus Rescan Event"; 
+               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. */
@@ -3296,6 +5340,9 @@ EventDescriptionStr(u8 event, u32 evData0)
                else
                        ds = "Events(OFF) Change";
                break;
+       case MPI_EVENT_INTEGRATED_RAID:
+               ds = "Integrated Raid";
+               break;
        /*
         *  MPT base "custom" events may be added here...
         */
@@ -3307,7 +5354,7 @@ EventDescriptionStr(u8 event, u32 evData0)
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/**
+/*
  *     ProcessEventNotification - Route a received EventNotificationReply to
  *     all currently regeistered event handlers.
  *     @ioc: Pointer to MPT_ADAPTER structure
@@ -3322,7 +5369,7 @@ ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply
        u16 evDataLen;
        u32 evData0 = 0;
 //     u32 evCtx;
-       int i;
+       int ii;
        int r = 0;
        int handlers = 0;
        char *evStr;
@@ -3339,15 +5386,15 @@ ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply
        }
 
        evStr = EventDescriptionStr(event, evData0);
-       dprintk((KERN_INFO MYNAM ": %s: MPT event (%s=%02Xh) detected!\n",
+       dprintk((MYIOC_s_INFO_FMT "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]));
+       for (ii = 0; ii < evDataLen; ii++)
+               printk(" %08x", le32_to_cpu(pEventReply->Data[ii]));
        printk("\n");
 #endif
 
@@ -3365,6 +5412,8 @@ ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply
        case MPI_EVENT_LINK_STATUS_CHANGE:      /* 07 */
        case MPI_EVENT_LOOP_STATE_CHANGE:       /* 08 */
        case MPI_EVENT_LOGOUT:                  /* 09 */
+       case MPI_EVENT_INTEGRATED_RAID:         /* 0B */
+       case MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE:       /* 0C */
        default:
                break;
        case MPI_EVENT_EVENT_CHANGE:            /* 0A */
@@ -3381,14 +5430,37 @@ ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply
                break;
        }
 
+       /*
+        * Should this event be logged? Events are written sequentially.
+        * When buffer is full, start again at the top.
+        */
+       if (ioc->events && (ioc->eventTypes & ( 1 << event))) {
+               int idx;
+
+               idx = ioc->eventContext % ioc->eventLogSize;
+
+               ioc->events[idx].event = event;
+               ioc->events[idx].eventContext = ioc->eventContext;
+
+               for (ii = 0; ii < 2; ii++) {
+                       if (ii < evDataLen)
+                               ioc->events[idx].data[ii] = le32_to_cpu(pEventReply->Data[ii]);
+                       else
+                               ioc->events[idx].data[ii] =  0;
+               }
+
+               ioc->eventContext++;
+       }
+
+
        /*
         *  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);
+       for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
+               if (MptEvHandlers[ii]) {
+                       dprintk((MYIOC_s_INFO_FMT "Routing Event to event handler #%d\n",
+                                       ioc->name, ii));
+                       r += (*(MptEvHandlers[ii]))(ioc, pEventReply);
                        handlers++;
                }
        }
@@ -3398,7 +5470,9 @@ ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply
         *  If needed, send (a single) EventAck.
         */
        if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) {
-               if ((i = SendEventAck(ioc, pEventReply)) != 0) {
+               if ((ii = SendEventAck(ioc, pEventReply)) != 0) {
+                       printk(MYIOC_s_WARN_FMT "SendEventAck returned %d\n",
+                                       ioc->name, ii);
                }
        }
 
@@ -3427,7 +5501,7 @@ mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info)
 
        switch(log_info) {
 /* FCP Initiator */
-       case MPI_IOCLOGINFO_FC_INIT_ERROR_OUT_OF_ORDER_FRAME:
+       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:
@@ -3483,7 +5557,7 @@ mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info)
                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";
+               desc = "Cleared from the outbound queue after a logout";
                break;
        case MPI_IOCLOGINFO_FC_TARGET_WAITING_FOR_DATA_IN:
                desc = "Cleared waiting for data after a logout";
@@ -3516,7 +5590,7 @@ mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info)
                break;
        }
 
-       printk(KERN_INFO MYNAM ": %s: LogInfo(0x%08x): SubCl={%s}",
+       printk(MYIOC_s_INFO_FMT "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);
@@ -3539,7 +5613,7 @@ 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);
+       printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x)\n", ioc->name, log_info);
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -3553,7 +5627,7 @@ mpt_sp_log_info(MPT_ADAPTER *ioc, u32 log_info)
  *     Specialized driver registration routine for the isense driver.
  */
 int
-mpt_register_ascqops_strings(/*ASCQ_Table_t*/void *ascqTable, int ascqtbl_sz, const char **opsTable)
+mpt_register_ascqops_strings(void *ascqTable, int ascqtbl_sz, const char **opsTable)
 {
        int r = 0;
 
@@ -3562,6 +5636,7 @@ mpt_register_ascqops_strings(/*ASCQ_Table_t*/void *ascqTable, int ascqtbl_sz, co
                mpt_ASCQ_TableSz = ascqtbl_sz;
                mpt_ScsiOpcodesPtr = opsTable;
                printk(KERN_INFO MYNAM ": English readable SCSI-3 strings enabled:-)\n");
+               isense_idx = last_drv_idx;
                r = 1;
        }
        MOD_INC_USE_COUNT;
@@ -3582,11 +5657,15 @@ mpt_deregister_ascqops_strings(void)
        mpt_ASCQ_TableSz = 0;
        mpt_ScsiOpcodesPtr = NULL;
        printk(KERN_INFO MYNAM ": English readable SCSI-3 strings disabled)-:\n");
+       isense_idx = -1;
        MOD_DEC_USE_COUNT;
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 
+EXPORT_SYMBOL(mpt_adapters);
+EXPORT_SYMBOL(mpt_proc_root_dir);
+EXPORT_SYMBOL(DmpService);
 EXPORT_SYMBOL(mpt_register);
 EXPORT_SYMBOL(mpt_deregister);
 EXPORT_SYMBOL(mpt_event_register);
@@ -3596,13 +5675,21 @@ EXPORT_SYMBOL(mpt_reset_deregister);
 EXPORT_SYMBOL(mpt_get_msg_frame);
 EXPORT_SYMBOL(mpt_put_msg_frame);
 EXPORT_SYMBOL(mpt_free_msg_frame);
+EXPORT_SYMBOL(mpt_add_sge);
+EXPORT_SYMBOL(mpt_add_chain);
 EXPORT_SYMBOL(mpt_send_handshake_request);
+EXPORT_SYMBOL(mpt_handshake_req_reply_wait);
 EXPORT_SYMBOL(mpt_adapter_find_first);
 EXPORT_SYMBOL(mpt_adapter_find_next);
 EXPORT_SYMBOL(mpt_verify_adapter);
+EXPORT_SYMBOL(mpt_GetIocState);
 EXPORT_SYMBOL(mpt_print_ioc_summary);
 EXPORT_SYMBOL(mpt_lan_index);
 EXPORT_SYMBOL(mpt_stm_index);
+EXPORT_SYMBOL(mpt_HardResetHandler);
+EXPORT_SYMBOL(mpt_config);
+EXPORT_SYMBOL(mpt_alloc_fw_memory);
+EXPORT_SYMBOL(mpt_free_fw_memory);
 
 EXPORT_SYMBOL(mpt_register_ascqops_strings);
 EXPORT_SYMBOL(mpt_deregister_ascqops_strings);
@@ -3611,12 +5698,13 @@ 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 __init
+fusion_init(void)
 {
        int i;
 
@@ -3636,12 +5724,22 @@ int __init fusion_init(void)
                MptResetHandlers[i] = NULL;
        }
 
+       DmpService = NULL;
+
        /* NEW!  20010120 -sralston
         *  Register ourselves (mptbase) in order to facilitate
         *  EventNotification handling.
         */
        mpt_base_index = mpt_register(mpt_base_reply, MPTBASE_DRIVER);
 
+       /* Register for hard reset handling callbacks.
+        */
+       if (mpt_reset_register(mpt_base_index, mpt_ioc_reset) == 0) {
+               dprintk((KERN_INFO MYNAM ": Register for IOC reset notification\n"));
+       } else {
+               /* FIXME! */
+       }
+
        if ((i = mpt_pci_scan()) < 0)
                return i;
 
@@ -3649,13 +5747,14 @@ int __init fusion_init(void)
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/**
+/*
  *     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)
+static void
+fusion_exit(void)
 {
        MPT_ADAPTER *this;
 
@@ -3665,7 +5764,7 @@ static void fusion_exit(void)
         *  Moved this *above* removal of all MptAdapters!
         */
 #ifdef CONFIG_PROC_FS
-       procmpt_destroy();
+       (void) procmpt_destroy();
 #endif
 
        while (! Q_IS_EMPTY(&MptAdapters)) {
@@ -3673,6 +5772,8 @@ static void fusion_exit(void)
                Q_DEL_ITEM(this);
                mpt_adapter_dispose(this);
        }
+
+       mpt_reset_deregister(mpt_base_index);
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
index b0f988a238da97fa5d642c22caa9801c6ce6a939..9b5f558a5043844cae51621c46497db90c4ef4cb 100644 (file)
@@ -8,11 +8,12 @@
  *  Credits:
  *     (see mptbase.c)
  *
- *  Copyright (c) 1999-2001 LSI Logic Corporation
+ *  Copyright (c) 1999-2002 LSI Logic Corporation
  *  Originally By: Steven J. Ralston
- *  (mailto:Steve.Ralston@lsil.com)
+ *  (mailto:sjralston1@netscape.net)
+ *  (mailto:Pam.Delaney@lsil.com)
  *
- *  $Id: mptbase.h,v 1.46.2.2.2.2 2001/09/18 03:22:29 sralston Exp $
+ *  $Id: mptbase.h,v 1.123 2002/06/20 13:28:16 pdelaney Exp $
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -55,6 +56,7 @@
 /*{-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 
 #include "linux_compat.h"      /* linux-2.2.x (vs. -2.4.x) tweaks */
+#include "scsi3.h"             /* SCSI defines */
 
 #include "lsi/mpi_type.h"
 #include "lsi/mpi.h"           /* Fusion MPI(nterface) basic defs */
@@ -62,6 +64,7 @@
 #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_raid.h"      /* Integrated Mirroring support */
 
 #include "lsi/mpi_fc.h"                /* Fibre Channel (lowlevel) support */
 #include "lsi/mpi_targ.h"      /* SCSI/FCP Target protcol support */
 #endif
 
 #ifndef COPYRIGHT
-#define COPYRIGHT      "Copyright (c) 1999-2001 " MODULEAUTHOR
+#define COPYRIGHT      "Copyright (c) 1999-2002 " MODULEAUTHOR
 #endif
 
-#define MPT_LINUX_VERSION_COMMON       "1.02.02"
-#define MPT_LINUX_PACKAGE_NAME         "@(#)mptlinux-1.02.02"
+#define MPT_LINUX_VERSION_COMMON       "2.01.06"
+#define MPT_LINUX_PACKAGE_NAME         "@(#)mptlinux-2.01.06"
 #define WHAT_MAGIC_STRING              "@" "(" "#" ")"
 
 #define show_mptmod_ver(s,ver)  \
  *  Fusion MPT(linux) driver configurable stuff...
  */
 #define MPT_MAX_ADAPTERS               16
-#define MPT_MAX_PROTOCOL_DRIVERS       8
+#define MPT_MAX_PROTOCOL_DRIVERS       16
+#define MPT_MAX_BUS                    1
 #define MPT_MAX_FC_DEVICES             255
+#define MPT_MAX_SCSI_DEVICES           16
+#define MPT_LAST_LUN                   31
+#define MPT_SENSE_BUFFER_ALLOC         64
+       /* allow for 256 max sense alloc, but only 255 max request */
+#if MPT_SENSE_BUFFER_ALLOC >= 256
+#      undef MPT_SENSE_BUFFER_ALLOC
+#      define MPT_SENSE_BUFFER_ALLOC   256
+#      define MPT_SENSE_BUFFER_SIZE    255
+#else
+#      define MPT_SENSE_BUFFER_SIZE    MPT_SENSE_BUFFER_ALLOC
+#endif
 
-#define MPT_MISCDEV_BASENAME           "mptctl"
-#define MPT_MISCDEV_PATHNAME           "/dev/" MPT_MISCDEV_BASENAME
+#define MPT_NAME_LENGTH                        32
 
 #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="
+#define MPT_PROCFS_SUMMARY_ALL_NODE            MPT_PROCFS_MPTBASEDIR "/summary"
+#define MPT_PROCFS_SUMMARY_ALL_PATHNAME                "/proc/" MPT_PROCFS_SUMMARY_ALL_NODE
+#define MPT_FW_REV_MAGIC_ID_STRING             "FwRev="
 
-#ifdef __KERNEL__      /* { */
 #define  MPT_MAX_REQ_DEPTH             1023
-#define  MPT_REQ_DEPTH                 256
+#define  MPT_DEFAULT_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_DEFAULT_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_DEFAULT_FRAME_SIZE                128
 
-#define  MPT_SG_BUCKETS_PER_HUNK       1
+#define  MPT_SG_REQ_128_SCALE          1
+#define  MPT_SG_REQ_96_SCALE           2
+#define  MPT_SG_REQ_64_SCALE           4
 
-#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
+#define         CAN_SLEEP                      1
+#define  NO_SLEEP                      0
+
+/* 
+ * SCSI transfer rate defines. 
+ */
+#define MPT_ULTRA320                   0x08
+#define MPT_ULTRA160                   0x09
+#define MPT_ULTRA2                     0x0A
+#define MPT_ULTRA                      0x0C
+#define MPT_FAST                       0x19
+#define MPT_SCSI                       0x32
+#define MPT_ASYNC                      0xFF
+
+#define MPT_NARROW                     0
+#define MPT_WIDE                       1
+
+#ifdef __KERNEL__      /* { */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+#include <linux/proc_fs.h>
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * Attempt semi-consistent error & warning msgs across
+ * MPT drivers.  NOTE: Users of these macro defs must
+ * themselves define their own MYNAM.
+ */
+#define MYIOC_s_INFO_FMT               KERN_INFO MYNAM ": %s: "
+#define MYIOC_s_NOTE_FMT               KERN_NOTICE MYNAM ": %s: "
+#define MYIOC_s_WARN_FMT               KERN_WARNING MYNAM ": %s: WARNING - "
+#define MYIOC_s_ERR_FMT                        KERN_ERR MYNAM ": %s: ERROR - "
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -133,6 +174,7 @@ typedef enum {
        MPTSCSIH_DRIVER,        /* MPT SCSI host (initiator) class */
        MPTLAN_DRIVER,          /* MPT LAN class */
        MPTSTM_DRIVER,          /* MPT SCSI target mode class */
+       MPTDMP_DRIVER,          /* MPT Dynamic Multi-pathing class */
        MPTUNKNOWN_DRIVER
 } MPT_DRIVER_CLASS;
 
@@ -145,10 +187,21 @@ typedef union _MPT_FRAME_TRACKER {
                struct _MPT_FRAME_HDR   *forw;
                struct _MPT_FRAME_HDR   *back;
                u32                      arg1;
+               u32                      pad;
                void                    *argp1;
+#ifndef MPT_SCSI_USE_NEW_EH
+               void                    *argp2;
+#endif
        } linkage;
        /*
-        * NOTE: On non-32-bit systems, where pointers are LARGE,
+        * NOTE: When request frames are free, on the linkage structure
+        * contets are valid.  All other values are invalid.
+        * In particular, do NOT reply on offset [2]
+        * (in words) being the * message context.
+        * The message context must be reset (computed via base address
+        * + an offset) prior to issuing any command.
+        *
+        * NOTE2: 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
@@ -169,6 +222,12 @@ typedef union _MPT_FRAME_TRACKER {
                        } fld;
                } msgctxu;
        } hwhdr;
+       /*
+        * Remark: 32 bit identifier:
+        *  31-24: reserved
+        *  23-16: call back index
+        *  15-0 : request index
+        */
 } MPT_FRAME_TRACKER;
 
 /*
@@ -189,6 +248,11 @@ typedef struct _MPT_FRAME_HDR {
        } u;
 } MPT_FRAME_HDR;
 
+#define MPT_REQ_MSGFLAGS_DROPME                0x80
+
+/* Used for tracking the free request frames
+ * and free reply frames.
+ */
 typedef struct _MPT_Q_TRACKER {
        MPT_FRAME_HDR   *head;
        MPT_FRAME_HDR   *tail;
@@ -214,12 +278,25 @@ typedef struct _Q_TRACKER {
        struct _Q_ITEM  *tail;
 } Q_TRACKER;
 
+typedef struct _MPT_DONE_Q {
+       struct _MPT_DONE_Q      *forw;
+       struct _MPT_DONE_Q      *back;
+       void                    *argp;
+} MPT_DONE_Q;
+
+typedef struct _DONE_Q_TRACKER {
+       MPT_DONE_Q      *head;
+       MPT_DONE_Q      *tail;
+} DONE_Q_TRACKER;
 
 /*
- *  Chip-specific stuff...
+ *  Chip-specific stuff... FC929 delineates break between
+ *  FC and Parallel SCSI parts. Do NOT re-order.
  */
 
 typedef enum {
+       FC919X = 0x0819,
+       FC929X = 0x0829,
        FC909 = 0x0909,
        FC919 = 0x0919,
        FC929 = 0x0929,
@@ -237,7 +314,9 @@ typedef struct _SYSIF_REGS
        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     DiagRwData;     /* 10     Read Write Data (fw download)   */
+       u32     DiagRwAddress;  /* 14     Read Write Address (fw download)*/
+       u32     Reserved1[6];   /* 18-2F  reserved for future use    */
        u32     IntStatus;      /* 30     Interrupt Status           */
        u32     IntMask;        /* 34     Interrupt Mask             */
        u32     Reserved2[2];   /* 38-3F  reserved for future use    */
@@ -256,60 +335,294 @@ typedef struct _SYSIF_REGS
  */
 
 
+/*
+ *     Dynamic Multi-Pathing specific stuff...
+ */
+#define DMP_MAX_PATHS  8
+
+typedef struct _PathInfo {
+       u8               ioc;
+       u8               target;
+       u8               pad;
+       u8               pflags;
+} PathInfo;
+
+#define PATHINFO_FLAGS_OWNED           0x01
+#define PATHINFO_FLAGS_EXISTS          0x02
+#define PATHINFO_FLAGS_AVAILABLE       0x04
+#define PATHINFO_FLAGS_SECONDARY       0x08
+
+#define PFLAGS_EXISTS_AND_AVAIL                (PATHINFO_FLAGS_EXISTS|PATHINFO_FLAGS_AVAILABLE)
+#define PFLAGS_AVAIL_AND_OWNED         (PATHINFO_FLAGS_AVAILABLE|PATHINFO_FLAGS_OWNED)
+
+typedef struct _ScsiCmndTracker {
+       void                    *head;
+       void                    *tail;
+} ScsiCmndTracker;
+
+
+/*
+ *     VirtDevice - FC LUN device or SCSI target device
+ *     (used to be FCSCSI_TARGET)
+ */
+typedef struct _VirtDevice {
+       struct _VirtDevice      *forw;
+       struct _VirtDevice      *back;
+       rwlock_t                 VdevLock;
+       int                      ref_cnt;
+       u8                       tflags;
+       u8                       ioc_id;
+       u8                       target_id;
+       u8                       bus_id;
+       u8                       minSyncFactor; /* 0xFF is async */
+       u8                       maxOffset;     /* 0 if async */
+       u8                       maxWidth;      /* 0 if narrow, 1 if wide*/
+       u8                       negoFlags;     /* bit field, 0 if WDTR/SDTR/QAS allowed */
+       u8                       raidVolume;    /* set, if RAID Volume */
+       u8                       rsvd;
+       u16                      rsvd1raid;
+       int                      npaths;
+       u16                      fc_phys_lun;
+       u16                      fc_xlat_lun;
+       int                      stall_detected;
+       PathInfo                 path[DMP_MAX_PATHS];
+       struct timer_list        stall_timer;
+       struct timer_list        retry_timer;
+       struct timer_list        gone_timer;
+       ScsiCmndTracker          WaitQ;
+       ScsiCmndTracker          SentQ;
+       ScsiCmndTracker          DoneQ;
+//--- LUN split here?
+       u8                       sense[SCSI_STD_SENSE_BYTES];           /* 18 */
+       u8                       rsvd2[2];      /* alignment */
+       u32                      luns;          /* Max LUNs is 32 */
+       u8                       inq_data[SCSI_STD_INQUIRY_BYTES];      /* 36 */
+       u8                       pad0[4];
+       u8                       inq00_data[20];
+       u8                       pad1[4];
+               /* IEEE Registered Extended Identifier
+                  obtained via INQUIRY VPD page 0x83 */
+               /* NOTE: Do not separate uniq_prepad and uniq_data
+                  as they are treateed as a single entity in the code */
+       u8                       uniq_prepad[8];
+       u8                       uniq_data[20];
+       u8                       pad2[4];
+       u8                       inqC3_data[12];
+       u8                       pad3[4];
+       u8                       inqC9_data[12];
+       u8                       pad4[4];
+       u8                       dev_vol_name[64];
+} VirtDevice;
+
+/*
+ *  Fibre Channel (SCSI) target device and associated defines...
+ */
+#define MPT_TARGET_DEFAULT_DV_STATUS   0
+#define MPT_TARGET_FLAGS_VALID_NEGO    0x01
+#define MPT_TARGET_FLAGS_VALID_INQUIRY 0x02
+#define MPT_TARGET_FLAGS_VALID_SENSE   0x04
+#define MPT_TARGET_FLAGS_Q_YES         0x08
+
+#define MPT_TARGET_NO_NEGO_WIDE                0x01
+#define MPT_TARGET_NO_NEGO_SYNC                0x02
+#define MPT_TARGET_NO_NEGO_QAS         0x04
+
+typedef struct _VirtDevTracker {
+       struct _VirtDevice      *head;
+       struct _VirtDevice      *tail;
+       rwlock_t                 VlistLock;
+       int                      pad;
+} VirtDevTracker;
+
+
+/*
+ *     /proc/mpt interface
+ */
+typedef struct {
+       const char      *name;
+       mode_t           mode;
+       int              pad;
+       read_proc_t     *read_proc;
+       write_proc_t    *write_proc;
+} mpt_proc_entry_t;
+
+#define MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len) \
+do { \
+       len -= offset;                  \
+       if (len < request) {            \
+               *eof = 1;               \
+               if (len <= 0)           \
+                       return 0;       \
+       } else                          \
+               len = request;          \
+       *start = buf + offset;          \
+       return len;                     \
+} while (0)
+
+
+/*
+ *     IOCTL structure and associated defines
+ */
+
+#define MPT_IOCTL_STATUS_DID_IOCRESET  0x01    /* IOC Reset occurred on the current*/
+#define MPT_IOCTL_STATUS_RF_VALID      0x02    /* The Reply Frame is VALID */
+#define MPT_IOCTL_STATUS_TIMER_ACTIVE  0x04    /* The timer is running */
+#define MPT_IOCTL_STATUS_SENSE_VALID   0x08    /* Sense data is valid */
+#define MPT_IOCTL_STATUS_COMMAND_GOOD  0x10    /* Command Status GOOD */
+#define MPT_IOCTL_STATUS_TMTIMER_ACTIVE        0x20    /* The TM timer is running */
+#define MPT_IOCTL_STATUS_TM_FAILED     0x40    /* User TM request failed */
+
+#define MPTCTL_RESET_OK                        0x01    /* Issue Bus Reset */
+
+typedef struct _MPT_IOCTL {
+       struct _MPT_ADAPTER     *ioc;
+       struct timer_list        timer;         /* timer function for this adapter */
+       u8                       ReplyFrame[MPT_DEFAULT_FRAME_SIZE];    /* reply frame data */
+       u8                       sense[MPT_SENSE_BUFFER_ALLOC];
+       int                      wait_done;     /* wake-up value for this ioc */
+       u8                       rsvd;
+       u8                       status;        /* current command status */
+       u8                       reset;         /* 1 if bus reset allowed */
+       u8                       target;        /* target for reset */
+       void                    *tmPtr;
+       struct timer_list        TMtimer;       /* timer function for this adapter */
+} MPT_IOCTL;
+
+/*
+ *  Event Structure and define
+ */
+#define MPTCTL_EVENT_LOG_SIZE          (0x0000000A)
+typedef struct _mpt_ioctl_events {
+       u32     event;          /* Specified by define above */
+       u32     eventContext;   /* Index or counter */
+       int     data[2];        /* First 8 bytes of Event Data */
+} MPT_IOCTL_EVENTS;
+
+/*
+ * CONFIGPARM status  defines
+ */
+#define MPT_CONFIG_GOOD                MPI_IOCSTATUS_SUCCESS
+#define MPT_CONFIG_ERROR       0x002F
+
+/*
+ *     Substructure to store SCSI specific configuration page data
+ */
+                                               /* dvStatus defines: */
+#define MPT_SCSICFG_NEGOTIATE          0x01    /* Negotiate on next IO */
+#define MPT_SCSICFG_NEED_DV            0x02    /* Schedule DV */
+#define MPT_SCSICFG_DV_PENDING         0x04    /* DV on this physical id pending */
+#define MPT_SCSICFG_DV_DONE            0x08    /* DV on this physical id complete */
+#define MPT_SCSICFG_BLK_NEGO           0x10    /* WriteSDP1 with WDTR and SDTR disabled */
+
+                                               /* Args passed to writeSDP1: */
+#define MPT_SCSICFG_USE_NVRAM          0x01    /* WriteSDP1 using NVRAM */
+#define MPT_SCSICFG_ALL_IDS            0x02    /* WriteSDP1 to all IDS */
+/* #define MPT_SCSICFG_BLK_NEGO                0x10       WriteSDP1 with WDTR and SDTR disabled */
+
+typedef        struct _ScsiCfgData {
+       int             *nvram;                 /* table of device NVRAM values */
+       IOCPage3_t      *pIocPg3;               /* table of physical disks */
+       u8               dvStatus[MPT_MAX_SCSI_DEVICES];
+       int              isRaid;                /* bit field, 1 if RAID */
+       u8               minSyncFactor;         /* 0xFF if async */
+       u8               maxSyncOffset;         /* 0 if async */
+       u8               maxBusWidth;           /* 0 if narrow, 1 if wide */
+       u8               busType;               /* SE, LVD, HD */
+       u8               sdp1version;           /* SDP1 version */
+       u8               sdp1length;            /* SDP1 length  */
+       u8               sdp0version;           /* SDP0 version */
+       u8               sdp0length;            /* SDP0 length  */
+       u8               dvScheduled;           /* 1 if scheduled */
+       u8               forceDv;               /* 1 to force DV scheduling */
+       u8               noQas;                 /* Disable QAS for this adapter */
+       u8               rsvd[2];
+} ScsiCfgData;
+
+typedef struct _fw_image {
+       char            *fw;
+       dma_addr_t       fw_dma;
+       u32              size;
+       u32              rsvd;
+} fw_image_t;
+
+/*
+ *  Adapter Structure - pci_dev specific. Maximum: MPT_MAX_ADAPTERS
+ */
 typedef struct _MPT_ADAPTER
 {
        struct _MPT_ADAPTER     *forw;
        struct _MPT_ADAPTER     *back;
-       int                      id;            /* Unique adapter id {0,1,2,...} */
-       int                      pci_irq;
-       char                     name[32];      /* "iocN"             */
+       int                      id;            /* Unique adapter id {0,1,2,...} */
+       int                      pci_irq;       /* This irq           */
+       char                     name[MPT_NAME_LENGTH]; /* "iocN"             */
        char                    *prod_name;     /* "LSIFC9x9"         */
-       u32                      mem_phys;      /* == f4020000 (mmap) */
        volatile SYSIF_REGS     *chip;          /* == c8817000 (mmap) */
-       CHIP_TYPE                chip_type;
-       int                      mem_size;
+       volatile SYSIF_REGS     *pio_chip;      /* Programmed IO (downloadboot) */
+       u32                      mem_phys;      /* == f4020000 (mmap) */
+       u32                      pio_mem_phys;  /* Programmed IO (downloadboot) */
+       int                      mem_size;      /* mmap memory size */
        int                      alloc_total;
        u32                      last_state;
        int                      active;
-       int                      sod_reset;
-       unsigned long            last_kickstart;
-       u8                      *reply_alloc;           /* Reply frames alloc ptr */
+       u8                      *reply_alloc;   /* Reply frames alloc ptr */
        dma_addr_t               reply_alloc_dma;
-       MPT_FRAME_HDR           *reply_frames;          /* Reply frames - rounded up! */
+       MPT_FRAME_HDR           *reply_frames;  /* Reply msg frames - rounded up! */
        dma_addr_t               reply_frames_dma;
-       int                      reply_depth;
-       int                      reply_sz;
+       u32                      reply_frames_low_dma;
+       int                      reply_depth;   /* Num Allocated reply frames */
+       int                      reply_sz;      /* Reply frame size */
+       CHIP_TYPE                chip_type;
                /* We (host driver) get to manage our own RequestQueue! */
-       u8                      *req_alloc;             /* Request frames alloc ptr */
+       u8                      *req_alloc;     /* Request frames alloc ptr */
        dma_addr_t               req_alloc_dma;
-       MPT_FRAME_HDR           *req_frames;            /* Request msg frames for PULL mode! */
+       MPT_FRAME_HDR           *req_frames;    /* Request msg frames - rounded up! */
        dma_addr_t               req_frames_dma;
-       int                      req_depth;
-       int                      req_sz;
-       MPT_Q_TRACKER            FreeQ;
+       u32                      req_frames_low_dma;
+       int                      req_depth;     /* Number of request frames */
+       int                      req_sz;        /* Request frame size (bytes) */
        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;
-       struct pci_dev          *pcidev;
-/*     atomic_t                 userCnt;       */
-       u8                      *memmap;
+       u32                      sense_buf_low_dma;
        int                      mtrr_reg;
-       struct Scsi_Host        *sh;
+       void                    *pcidev;        /* struct pci_dev pointer */
+       u8                      *memmap;        /* mmap address */
+       struct Scsi_Host        *sh;            /* Scsi Host pointer */
+       ScsiCfgData             spi_data;       /* Scsi config. data */
+       MPT_IOCTL               *ioctl;         /* ioctl data pointer */
        struct proc_dir_entry   *ioc_dentry;
-       struct _MPT_ADAPTER     *alt_ioc;
+       struct _MPT_ADAPTER     *alt_ioc;       /* ptr to 929 bound adapter port */
+       spinlock_t               diagLock;      /* diagnostic reset lock */
+       int                      diagPending;
+       u32                      biosVersion;   /* BIOS version from IO Unit Page 2 */
+       int                      eventTypes;    /* Event logging parameters */
+       int                      eventContext;  /* Next event context */
+       int                      eventLogSize;  /* Max number of cached events */
+       struct _mpt_ioctl_events *events;       /* pointer to event log */
+       fw_image_t              **cached_fw;    /* Pointer to FW SG List */
+       Q_TRACKER                configQ;       /* linked list of config. requests */
+       int                      num_fw_frags;  /* Number of SGE in FW SG List */
        int                      hs_reply_idx;
+#ifndef MFCNT
+       u32                      pad0;
+#else
+       u32                      mfcnt;
+#endif
        u32                      hs_req[MPT_MAX_FRAME_SIZE/sizeof(u32)];
        u16                      hs_reply[MPT_MAX_FRAME_SIZE/sizeof(u16)];
        IOCFactsReply_t          facts;
        PortFactsReply_t         pfacts[2];
+       FCPortPage0_t            fc_port_page0[2];
        LANPage0_t               lan_cnfg_page0;
        LANPage1_t               lan_cnfg_page1;
        u8                       FirstWhoInit;
-       u8                       pad1[3];
+       u8                       upload_fw;     /* If set, do a fw upload */
+       u8                       pad1[6];
 } MPT_ADAPTER;
 
 
@@ -324,7 +637,6 @@ typedef struct _MPT_ADAPTER_TRACKER {
  *    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);
 typedef int (*MPT_RESETHANDLER)(MPT_ADAPTER *ioc, int reset_phase);
 /* reset_phase defs */
@@ -344,6 +656,22 @@ typedef struct _MPT_HOST_EVENT {
 #define MPT_HOSTEVENT_IOC_BRINGUP      0x91
 #define MPT_HOSTEVENT_IOC_RECOVER      0x92
 
+/* Define the generic types based on the size
+ * of the dma_addr_t type.
+ */
+typedef struct _mpt_sge {
+       u32             FlagsLength;
+       dma_addr_t      Address;
+} MptSge_t;
+
+#define mpt_addr_size() \
+       ((sizeof(dma_addr_t) == sizeof(u64)) ? MPI_SGE_FLAGS_64_BIT_ADDRESSING : \
+               MPI_SGE_FLAGS_32_BIT_ADDRESSING)
+
+#define mpt_msg_flags() \
+       ((sizeof(dma_addr_t) == sizeof(u64)) ? MPI_SCSIIO_MSGFLGS_SENSE_WIDTH_64 : \
+               MPI_SCSIIO_MSGFLGS_SENSE_WIDTH_32)
+
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
  *  Funky (private) macros...
@@ -360,7 +688,8 @@ typedef struct _MPT_HOST_EVENT {
 #define dhsprintk(x)
 #endif
 
-#if defined(MPT_DEBUG) || defined(MPT_DEBUG_MSG_FRAME)
+//#if defined(MPT_DEBUG) || defined(MPT_DEBUG_MSG_FRAME)
+#if defined(MPT_DEBUG_MSG_FRAME)
 #define dmfprintk(x)  printk x
 #else
 #define dmfprintk(x)
@@ -372,24 +701,41 @@ typedef struct _MPT_HOST_EVENT {
 #define dirqprintk(x)
 #endif
 
-#ifdef MPT_DEBUG_EVENTS
-#define deventprintk(x)  printk x
+#ifdef MPT_DEBUG_SG
+#define dsgprintk(x)  printk x
 #else
-#define deventprintk(x)
+#define dsgprintk(x)
 #endif
 
-#ifdef MPT_DEBUG_SPINLOCK
-#define dslprintk(x)  printk x
+#ifdef MPT_DEBUG_DV
+#define ddvprintk(x)  printk x
 #else
-#define dslprintk(x)
+#define ddvprintk(x)
 #endif
 
-#ifdef MPT_DEBUG_SG
-#define dsgprintk(x)  printk x
+#if defined(MPT_DEBUG_DV) || defined(MPT_DEBUG_DV_TINY)
+#define ddvtprintk(x)  printk x
 #else
-#define dsgprintk(x)
+#define ddvtprintk(x)
+#endif
+
+#ifdef MPT_DEBUG_IOCTL
+#define dctlprintk(x) printk x
+#else
+#define dctlprintk(x)
 #endif
 
+#ifdef MPT_DEBUG_RESET
+#define dtmprintk(x) printk x
+#else
+#define dtmprintk(x)
+#endif
+
+#ifdef MPT_DEBUG_NEH
+#define nehprintk(x) printk x
+#else
+#define nehprintk(x)
+#endif
 
 #define MPT_INDEX_2_MFPTR(ioc,idx) \
        (MPT_FRAME_HDR*)( (u8*)(ioc)->req_frames + (ioc)->req_sz * (idx) )
@@ -397,6 +743,9 @@ typedef struct _MPT_HOST_EVENT {
 #define MFPTR_2_MPT_INDEX(ioc,mf) \
        (int)( ((u8*)mf - (u8*)(ioc)->req_frames) / (ioc)->req_sz )
 
+#define MPT_INDEX_2_RFPTR(ioc,idx) \
+       (MPT_FRAME_HDR*)( (u8*)(ioc)->reply_frames + (ioc)->req_sz * (idx) )
+
 #define Q_INIT(q,type)  (q)->head = (q)->tail = (type*)(q)
 #define Q_IS_EMPTY(q)   ((Q_ITEM*)(q)->head == (Q_ITEM*)(q))
 
@@ -425,7 +774,6 @@ typedef struct _MPT_HOST_EVENT {
        _forw->back = _back; \
 }
 
-
 #define SWAB4(value) \
        (u32)(   (((value) & 0x000000ff) << 24) \
               | (((value) & 0x0000ff00) << 8)  \
@@ -457,64 +805,157 @@ typedef struct _MPT_HOST_EVENT {
 
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-#endif         /* } __KERNEL__ */
 
+/*
+ * MPT_SCSI_HOST defines - Used by the IOCTL and the SCSI drivers
+ * Private to the driver.
+ */
+/* LOCAL structure and fields used when processing
+ * internally generated commands. These include:
+ * bus scan, dv and config requests.
+ */
+typedef struct _MPT_LOCAL_REPLY {
+       ConfigPageHeader_t header;
+       int     completion;
+       u8      sense[SCSI_STD_SENSE_BYTES];
+       u8      scsiStatus;
+       u8      skip;
+       u32     pad;
+} MPT_LOCAL_REPLY;
+
+#define MPT_HOST_BUS_UNKNOWN           (0xFF)
+#define MPT_HOST_TOO_MANY_TM           (0x05)
+#define MPT_HOST_NVRAM_INVALID         (0xFFFFFFFF)
+#define MPT_HOST_NO_CHAIN              (0xFFFFFFFF)
+#define MPT_NVRAM_MASK_TIMEOUT         (0x000000FF)
+#define MPT_NVRAM_SYNC_MASK            (0x0000FF00)
+#define MPT_NVRAM_SYNC_SHIFT           (8)
+#define MPT_NVRAM_DISCONNECT_ENABLE    (0x00010000)
+#define MPT_NVRAM_ID_SCAN_ENABLE       (0x00020000)
+#define MPT_NVRAM_LUN_SCAN_ENABLE      (0x00040000)
+#define MPT_NVRAM_TAG_QUEUE_ENABLE     (0x00080000)
+#define MPT_NVRAM_WIDE_DISABLE         (0x00100000)
+#define MPT_NVRAM_BOOT_CHOICE          (0x00200000)
+
+#ifdef MPT_SCSI_USE_NEW_EH
+/* The TM_STATE variable is used to provide strict single threading of TM
+ * requests as well as communicate TM error conditions.
+ */
+#define TM_STATE_NONE          (0)
+#define        TM_STATE_IN_PROGRESS   (1)
+#define        TM_STATE_ERROR         (2)
+#endif
+
+typedef struct _MPT_SCSI_HOST {
+       MPT_ADAPTER              *ioc;
+       int                       port;
+       u32                       pad0;
+       struct scsi_cmnd        **ScsiLookup;
+               /* Pool of buffers for chaining. ReqToChain
+                * and ChainToChain track index of chain buffers.
+                * ChainBuffer (DMA) virt/phys addresses.
+                * FreeChainQ (lock) locking mechanisms.
+                */
+       int                      *ReqToChain;
+       int                      *ChainToChain;
+       u8                       *ChainBuffer;
+       dma_addr_t                ChainBufferDMA;
+       MPT_Q_TRACKER             FreeChainQ;
+       spinlock_t                FreeChainQlock;
+       u32                       qtag_tick;
+       VirtDevice              **Targets;
+       MPT_LOCAL_REPLY          *pLocal;               /* used for internal commands */
+       struct timer_list         timer;
+       struct timer_list         TMtimer;              /* Timer for TM commands ONLY */
+               /* Pool of memory for holding SCpnts before doing
+                * OS callbacks. freeQ is the free pool.
+                */
+       u8                       *memQ;
+       DONE_Q_TRACKER            freeQ;
+       DONE_Q_TRACKER            doneQ;                /* Holds Linux formmatted requests */
+       DONE_Q_TRACKER            pendingQ;             /* Holds MPI formmatted requests */
+       MPT_Q_TRACKER             taskQ;                /* TM request Q */
+       spinlock_t                freedoneQlock;
+       int                       taskQcnt;
+       u8                        numTMrequests;
+       u8                        tmPending;
+       u8                        resetPending;
+       u8                        is_spi;               /* Parallel SCSI i/f */
+       u8                        negoNvram;            /* DV disabled, nego NVRAM */
+       u8                        is_multipath;         /* Multi-path compatible */
+#ifdef MPT_SCSI_USE_NEW_EH
+       u8                        tmState;
+       u8                        rsvd[1];
+#else
+       u8                        rsvd[2];
+#endif
+       MPT_FRAME_HDR            *tmPtr;                /* Ptr to TM request*/
+       MPT_FRAME_HDR            *cmdPtr;               /* Ptr to nonOS request */
+       struct scsi_cmnd         *abortSCpnt;
+       MPT_LOCAL_REPLY           localReply;           /* internal cmd reply struct */
+} MPT_SCSI_HOST;
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     Structure for overlaying onto scsi_cmnd->SCp area
+ *     NOTE: SCp area is 36 bytes min, 44 bytes max?
+ */
+typedef struct _scPrivate {
+       struct scsi_cmnd        *forw;
+       struct scsi_cmnd        *back;
+       void                    *p1;
+       void                    *p2;
+       u8                       io_path_id;    /* DMP */
+       u8                       pad[7];
+} scPrivate;
 
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
- *  MPT Control IOCTLs and structures
+ *     More Dynamic Multi-Pathing stuff...
  */
-#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)
+
+/* Forward decl, a strange C thing, to prevent gcc compiler warnings */
+struct scsi_cmnd;
 
 /*
- *  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;
-};
+ *     DMP service layer structure / API interface
+ */
+typedef struct _DmpServices {
+       VirtDevTracker    VdevList;
+       struct semaphore *Daemon;
+       int             (*ScsiPathSelect)
+                               (struct scsi_cmnd *, MPT_SCSI_HOST **hd, int *target, int *lun);
+       int             (*DmpIoDoneChk)
+                               (MPT_SCSI_HOST *, struct scsi_cmnd *,
+                                SCSIIORequest_t *,
+                                SCSIIOReply_t *);
+       void            (*mptscsih_scanVlist)
+                               (MPT_SCSI_HOST *, int portnum);
+       int             (*ScsiAbort)
+                               (struct scsi_cmnd *);
+       int             (*ScsiBusReset)
+                               (struct scsi_cmnd *);
+} DmpServices_t;
 
-#ifdef __KERNEL__      /* { */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * Generic structure passed to the base mpt_config function.
+ */
+typedef struct _x_config_parms {
+       Q_ITEM                   linkage;       /* linked list */
+       struct timer_list        timer;         /* timer function for this request  */
+       ConfigPageHeader_t      *hdr;
+       dma_addr_t               physAddr;
+       int                      wait_done;     /* wait for this request */
+       u32                      pageAddr;      /* properly formatted */
+       u8                       action;
+       u8                       dir;
+       u8                       timeout;       /* seconds */
+       u8                       pad1;
+       u16                      status;
+       u16                      pad2;
+} CONFIGPARMS;
 
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
  *  Public entry points...
  */
@@ -524,21 +965,33 @@ extern int         mpt_event_register(int cb_idx, MPT_EVHANDLER ev_cbfunc);
 extern void     mpt_event_deregister(int cb_idx);
 extern int      mpt_reset_register(int cb_idx, MPT_RESETHANDLER reset_func);
 extern void     mpt_reset_deregister(int cb_idx);
-extern int      mpt_register_ascqops_strings(/*ASCQ_Table_t*/void *ascqTable, int ascqtbl_sz, const char **opsTable);
+extern int      mpt_register_ascqops_strings(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 void     mpt_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr);
+extern void     mpt_add_chain(char *pAddr, u8 next, u16 length, dma_addr_t dma_addr);
+
+extern int      mpt_send_handshake_request(int handle, int iocid, int reqBytes, u32 *req, int sleepFlag);
+extern int      mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req, int replyBytes, u16 *u16reply, int maxwait, int sleepFlag);
 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 u32      mpt_GetIocState(MPT_ADAPTER *ioc, int cooked);
 extern void     mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buf, int *size, int len, int showlan);
-extern void     mpt_print_ioc_facts(MPT_ADAPTER *ioc, char *buf, int *size, int len);
+extern int      mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag);
+extern int      mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *cfg);
+extern void    *mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size, int *frags, int *alloc_sz);
+extern void     mpt_free_fw_memory(MPT_ADAPTER *ioc, fw_image_t **alt_img);
 
 /*
  *  Public data decl's...
  */
+extern MPT_ADAPTER             *mpt_adapters[MPT_MAX_ADAPTERS];
+extern struct proc_dir_entry   *mpt_proc_root_dir;
+extern DmpServices_t           *DmpService;
+
 extern int               mpt_lan_index;        /* needed by mptlan.c */
 extern int               mpt_stm_index;        /* needed by mptstm.c */
 
@@ -563,7 +1016,7 @@ extern int           mpt_ASCQ_TableSz;
 #define offsetof(t, m) ((size_t) (&((t *)0)->m))
 #endif
 
-#if defined(__alpha__) || defined(__sparc_v9__)
+#if defined(__alpha__) || defined(__sparc_v9__) || defined(__ia64__)
 #define CAST_U32_TO_PTR(x)     ((void *)(u64)x)
 #define CAST_PTR_TO_U32(x)     ((u32)(u64)x)
 #else
@@ -577,6 +1030,40 @@ extern int                  mpt_ASCQ_TableSz;
        ((pflags) & MPI_PORTFACTS_PROTOCOL_LAN)         ? 'L' : 'l',    \
        ((pflags) & MPI_PORTFACTS_PROTOCOL_LOGBUSADDR)  ? 'B' : 'b'
 
+/*
+ *  Shifted SGE Defines - Use in SGE with FlagsLength member.
+ *  Otherwise, use MPI_xxx defines (refer to "lsi/mpi.h" header).
+ *  Defaults: 32 bit SGE, SYSTEM_ADDRESS if direction bit is 0, read
+ */
+#define MPT_TRANSFER_IOC_TO_HOST               (0x00000000)
+#define MPT_TRANSFER_HOST_TO_IOC               (0x04000000)
+#define MPT_SGE_FLAGS_LAST_ELEMENT             (0x80000000)
+#define MPT_SGE_FLAGS_END_OF_BUFFER            (0x40000000)
+#define MPT_SGE_FLAGS_LOCAL_ADDRESS            (0x08000000)
+#define MPT_SGE_FLAGS_DIRECTION                        (0x04000000)
+#define MPT_SGE_FLAGS_ADDRESSING               (mpt_addr_size() << MPI_SGE_FLAGS_SHIFT)
+#define MPT_SGE_FLAGS_END_OF_LIST              (0x01000000)
+
+#define MPT_SGE_FLAGS_TRANSACTION_ELEMENT      (0x00000000)
+#define MPT_SGE_FLAGS_SIMPLE_ELEMENT           (0x10000000)
+#define MPT_SGE_FLAGS_CHAIN_ELEMENT            (0x30000000)
+#define MPT_SGE_FLAGS_ELEMENT_MASK             (0x30000000)
+
+#define MPT_SGE_FLAGS_SSIMPLE_READ \
+       (MPT_SGE_FLAGS_LAST_ELEMENT |   \
+        MPT_SGE_FLAGS_END_OF_BUFFER |  \
+        MPT_SGE_FLAGS_END_OF_LIST |    \
+        MPT_SGE_FLAGS_SIMPLE_ELEMENT | \
+        MPT_SGE_FLAGS_ADDRESSING | \
+        MPT_TRANSFER_IOC_TO_HOST)
+#define MPT_SGE_FLAGS_SSIMPLE_WRITE \
+       (MPT_SGE_FLAGS_LAST_ELEMENT |   \
+        MPT_SGE_FLAGS_END_OF_BUFFER |  \
+        MPT_SGE_FLAGS_END_OF_LIST |    \
+        MPT_SGE_FLAGS_SIMPLE_ELEMENT | \
+        MPT_SGE_FLAGS_ADDRESSING | \
+        MPT_TRANSFER_HOST_TO_IOC)
+
 /*}-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 #endif
 
index 7db731e51885e311f3b357f1a800043e05290f08..4e1b0b0f9876f42dc79a04041591874202524ae5 100644 (file)
@@ -9,6 +9,12 @@
  *      This driver would not exist if not for Alan Cox's development
  *      of the linux i2o driver.
  *
+ *      A special thanks to Pamela Delaney (LSI Logic) for tons of work
+ *      and countless enhancements while adding support for the 1030
+ *      chip family.  Pam has been instrumental in the development of
+ *      of the 2.xx.xx series fusion drivers, and her contributions are
+ *      far too numerous to hope to list in one place.
+ *
  *      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!
  *      (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(),
+ *      a potential memory leak in mptctl_do_fw_download(),
  *      and for some kmalloc insight:-)
  *
  *      (see also mptbase.c)
  *
- *  Copyright (c) 1999-2001 LSI Logic Corporation
+ *  Copyright (c) 1999-2002 LSI Logic Corporation
  *  Originally By: Steven J. Ralston, Noah Romer
- *  (mailto:Steve.Ralston@lsil.com)
+ *  (mailto:sjralston1@netscape.net)
+ *  (mailto:Pam.Delaney@lsil.com)
  *
- *  $Id: mptctl.c,v 1.25.4.1 2001/08/24 20:07:06 sralston Exp $
+ *  $Id: mptctl.c,v 1.55 2002/06/20 13:28:16 pdelaney Exp $
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -69,7 +76,6 @@
 #include <linux/version.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/major.h>
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
 
-#include <linux/proc_fs.h>
+#include <linux/kdev_t.h>      /* needed for access to Scsi_Host struct */
+#include <linux/blkdev.h>
+#include <linux/blk.h>          /* for io_request_lock (spinlock) decl */
+#include "../../scsi/scsi.h"
+#include "../../scsi/hosts.h"
 
 #define COPYRIGHT      "Copyright (c) 1999-2001 LSI Logic Corporation"
-#define MODULEAUTHOR   "Steven J. Ralston, Noah Romer"
+#define MODULEAUTHOR   "Steven J. Ralston, Noah Romer, Pamela Delaney"
 #include "mptbase.h"
+#include "mptctl.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);
 MODULE_LICENSE("GPL");
 
-
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 
 static int mptctl_id = -1;
-static int rwperf_reset = 0;
 static struct semaphore mptctl_syscall_sem_ioc[MPT_MAX_ADAPTERS];
 
+static DECLARE_WAIT_QUEUE_HEAD ( mptctl_wait );
+
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 
-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);
+struct buflist {
+       u8      *kptr;
+       int      len;
+};
+
+/*
+ * Function prototypes. Called from OS entry point mptctl_ioctl.
+ * arg contents specific to function.
+ */
+static int mptctl_fw_download(unsigned long arg);
+static int mptctl_getiocinfo (unsigned long arg, unsigned int cmd);
+static int mptctl_gettargetinfo (unsigned long arg);
+static int mptctl_readtest (unsigned long arg);
+static int mptctl_mpt_command (unsigned long arg);
+static int mptctl_eventquery (unsigned long arg);
+static int mptctl_eventenable (unsigned long arg);
+static int mptctl_eventreport (unsigned long arg);
+static int mptctl_replace_fw (unsigned long arg);
+
+static int mptctl_do_reset(unsigned long arg);
+
+static int mptctl_compaq_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
+static int mptctl_cpq_getpciinfo(unsigned long arg);
+static int mptctl_cpq_getdriver(unsigned long arg);
+static int mptctl_cpq_ctlr_status(unsigned long arg);
+static int mptctl_cpq_target_address(unsigned long arg);
+static int mptctl_cpq_passthru(unsigned long arg);
+static int mptctl_compaq_scsiio(VENDOR_IOCTL_REQ *pVenReq, cpqfc_passthru_t *pPass);
+
+/*
+ * Private function calls.
+ */
+static int mptctl_do_mpt_command (struct mpt_ioctl_command karg, char *mfPtr, int local);
+static int mptctl_do_fw_download(int ioc, char *ufwbuf, size_t fwlen);
+static MptSge_t *kbuf_alloc_2_sgl( int bytes, u32 dir, int sge_offset, int *frags,
+               struct buflist **blp, dma_addr_t *sglbuf_dma, MPT_ADAPTER *ioc);
+static void kfree_sgl( MptSge_t *sgl, dma_addr_t sgl_dma,
+               struct buflist *buflist, MPT_ADAPTER *ioc);
+static void mptctl_timer_expired (unsigned long data);
+static int  mptctl_bus_reset(MPT_IOCTL *ioctl);
+static int mptctl_set_tm_flags(MPT_SCSI_HOST *hd);
+static void mptctl_free_tm_flags(MPT_ADAPTER *ioc);
+
+/*
+ * Reset Handler cleanup function
+ */
+static int  mptctl_ioc_reset(MPT_ADAPTER *ioc, int reset_phase);
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -132,34 +185,18 @@ static int mpt_ioctl_scsi_cmd(unsigned long arg);
 /* 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}};
+#define MPT_IOCTL_DEFAULT_TIMEOUT 10   /* Default timeout value (seconds) */
 
 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
+ *     All of the ioctl 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.
@@ -167,16 +204,32 @@ static void kfree_sgl( SGESimple32_t *sgl, dma_addr_t sgl_dma,
 static inline int
 mptctl_syscall_down(MPT_ADAPTER *ioc, int nonblock)
 {
-       dprintk((KERN_INFO MYNAM "::mpt_syscall_down(%p,%d) called\n", ioc, nonblock));
+       int rc = 0;
+       dctlprintk((KERN_INFO MYNAM "::mptctl_syscall_down(%p,%d) called\n", ioc, nonblock));
+
+       if (ioc->ioctl->tmPtr != NULL) {
+               dctlprintk((KERN_INFO MYNAM "::mptctl_syscall_down BUSY\n"));
+               return -EBUSY;
+       }
 
+#if defined(__sparc__) && defined(__sparc_v9__)                /*{*/
+       if (!nonblock) {
+               if (down_interruptible(&mptctl_syscall_sem_ioc[ioc->id]))
+                       rc = -ERESTARTSYS;
+       } else {
+               rc = -EPERM;
+       }
+#else
        if (nonblock) {
                if (down_trylock(&mptctl_syscall_sem_ioc[ioc->id]))
-                       return -EAGAIN;
+                       rc = -EAGAIN;
        } else {
                if (down_interruptible(&mptctl_syscall_sem_ioc[ioc->id]))
-                       return -ERESTARTSYS;
+                       rc = -ERESTARTSYS;
        }
-       return 0;
+#endif
+       dctlprintk((KERN_INFO MYNAM "::mptctl_syscall_down return %d\n", rc));
+       return rc;
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -189,18 +242,323 @@ mptctl_syscall_down(MPT_ADAPTER *ioc, int nonblock)
 static int
 mptctl_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply)
 {
-       u8 targ;
+       char *sense_data;
+       int sz, req_index;
+       u16 iocStatus;
+       u8 cmd;
+
+       dctlprintk((MYIOC_s_INFO_FMT ": mptctl_reply()!\n", ioc->name));
+       if (req)
+                cmd = req->u.hdr.Function;
+       else
+               return 1;
+
+       if (ioc->ioctl) {
+               /* If timer is not running, then an error occurred.
+                * A timeout will call the reset routine to reload the messaging
+                * queues.
+                * Main callback will free message and reply frames.
+                */
+               if (reply && (cmd == MPI_FUNCTION_SCSI_TASK_MGMT) &&
+                   (ioc->ioctl->status & MPT_IOCTL_STATUS_TMTIMER_ACTIVE)) {
+                       /* This is internally generated TM
+                        */
+                       del_timer (&ioc->ioctl->TMtimer);
+                       ioc->ioctl->status &= ~MPT_IOCTL_STATUS_TMTIMER_ACTIVE;
+
+                       mptctl_free_tm_flags(ioc);
+
+                       /* If TM failed, reset the timer on the existing command,
+                        * will trigger an adapter reset.
+                        */
+                       iocStatus = reply->u.reply.IOCStatus & MPI_IOCSTATUS_MASK;
+                       if (iocStatus == MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED) {
+                               if (ioc->ioctl->status & MPT_IOCTL_STATUS_TIMER_ACTIVE) {
+                                       del_timer (&ioc->ioctl->timer);
+                                       ioc->ioctl->timer.expires = jiffies + HZ;
+                                       add_timer(&ioc->ioctl->timer);
+                               }
+                       }
+                       ioc->ioctl->tmPtr = NULL;
+
+               } else if (ioc->ioctl->status & MPT_IOCTL_STATUS_TIMER_ACTIVE) {
+                       /* Delete this timer
+                        */
+                       del_timer (&ioc->ioctl->timer);
+                       ioc->ioctl->status &= ~MPT_IOCTL_STATUS_TIMER_ACTIVE;
+
+                       /* Set the overall status byte.  Good if:
+                        * IOC status is good OR if no reply and a SCSI IO request
+                        */
+                       if (reply) {
+                               /* Copy the reply frame (which much exist
+                                * for non-SCSI I/O) to the IOC structure.
+                                */
+                               dctlprintk((MYIOC_s_INFO_FMT ": Copying Reply Frame @%p to IOC!\n",
+                                               ioc->name, reply));
+                               memcpy(ioc->ioctl->ReplyFrame, reply,
+                                       MIN(ioc->reply_sz, 4*reply->u.reply.MsgLength));
+                               ioc->ioctl->status |= MPT_IOCTL_STATUS_RF_VALID;
+
+                               /* Set the command status to GOOD if IOC Status is GOOD
+                                * OR if SCSI I/O cmd and data underrun or recovered error.
+                                */
+                               iocStatus = reply->u.reply.IOCStatus & MPI_IOCSTATUS_MASK;
+                               if (iocStatus  == MPI_IOCSTATUS_SUCCESS)
+                                       ioc->ioctl->status |= MPT_IOCTL_STATUS_COMMAND_GOOD;
+
+                               if ((cmd == MPI_FUNCTION_SCSI_IO_REQUEST) ||
+                                       (cmd == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) {
+                                       ioc->ioctl->reset &= ~MPTCTL_RESET_OK;
+
+                                       if ((iocStatus == MPI_IOCSTATUS_SCSI_DATA_UNDERRUN) ||
+                                               (iocStatus == MPI_IOCSTATUS_SCSI_RECOVERED_ERROR)) {
+                                               ioc->ioctl->status |= MPT_IOCTL_STATUS_COMMAND_GOOD;
+                                       }
+                               }
+
+                               /* Copy the sense data - if present
+                                */
+                               if ((cmd == MPI_FUNCTION_SCSI_IO_REQUEST) &&
+                                       (reply->u.sreply.SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID)){
+
+                                       sz = req->u.scsireq.SenseBufferLength;
+                                       req_index = le16_to_cpu(req->u.frame.hwhdr.msgctxu.fld.req_idx);
+                                       sense_data = ((u8 *)ioc->sense_buf_pool + (req_index * MPT_SENSE_BUFFER_ALLOC));
+                                       memcpy(ioc->ioctl->sense, sense_data, sz);
+                                       ioc->ioctl->status |= MPT_IOCTL_STATUS_SENSE_VALID;
+                               }
+
+                               if (cmd == MPI_FUNCTION_SCSI_TASK_MGMT)
+                                       mptctl_free_tm_flags(ioc);
+
+
+                       } else if ((cmd == MPI_FUNCTION_SCSI_IO_REQUEST) ||
+                                       (cmd == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) {
+                               ioc->ioctl->status |= MPT_IOCTL_STATUS_COMMAND_GOOD;
+                               ioc->ioctl->reset &= ~MPTCTL_RESET_OK;
+                       }
+
+                       /* We are done, issue wake up
+                        */
+                       ioc->ioctl->wait_done = 1;
+                       wake_up (&mptctl_wait);
+               } else if (reply && cmd == MPI_FUNCTION_FW_DOWNLOAD) {
+                       /* Two paths to FW DOWNLOAD! */
+                       // NOTE: Expects/requires non-Turbo reply!
+                       dctlprintk((MYIOC_s_INFO_FMT ":Caching MPI_FUNCTION_FW_DOWNLOAD reply!\n",
+                               ioc->name));
+                       memcpy(fwReplyBuffer, reply, MIN(sizeof(fwReplyBuffer), 4*reply->u.reply.MsgLength));
+                       ReplyMsg = (pMPIDefaultReply_t) fwReplyBuffer;
+               }
+       }
+       return 1;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/* mptctl_timer_expired
+ *
+ * Call back for timer process. Used only for ioctl functionality.
+ *
+ */
+static void mptctl_timer_expired (unsigned long data)
+{
+       MPT_IOCTL *ioctl = (MPT_IOCTL *) data;
+       int rc = 1;
+
+       dctlprintk((KERN_NOTICE MYNAM ": Timer Expired! Host %d\n",
+                               ioctl->ioc->id));
+       if (ioctl == NULL)
+               return;
+
+       if (ioctl->reset & MPTCTL_RESET_OK)
+               rc = mptctl_bus_reset(ioctl);
+
+       if (rc) {
+               /* Issue a reset for this device.
+                * The IOC is not responding.
+                */
+               mpt_HardResetHandler(ioctl->ioc, NO_SLEEP);
+       }
+       return;
+
+}
+
+/* mptctl_bus_reset
+ *
+ * Bus reset code.
+ *
+ */
+static int mptctl_bus_reset(MPT_IOCTL *ioctl)
+{
+       MPT_FRAME_HDR   *mf;
+       SCSITaskMgmt_t  *pScsiTm;
+       MPT_SCSI_HOST   *hd;
+       int              ii;
+       int              retval;
+
+
+       ioctl->reset &= ~MPTCTL_RESET_OK;
+
+       if (ioctl->ioc->sh == NULL)
+               return -EPERM;
+       
+       hd = (MPT_SCSI_HOST *) ioctl->ioc->sh->hostdata;
+       if (hd == NULL)
+               return -EPERM;
+
+       /* Single threading ....
+        */
+       if (mptctl_set_tm_flags(hd) != 0)
+               return -EPERM;
+
+       /* Send request
+        */
+       if ((mf = mpt_get_msg_frame(mptctl_id, ioctl->ioc->id)) == NULL) {
+               dtmprintk((MYIOC_s_WARN_FMT "IssueTaskMgmt, no msg frames!!\n",
+                               ioctl->ioc->name));
+
+               mptctl_free_tm_flags(ioctl->ioc);
+               return -ENOMEM;
+       }
+
+       dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt request @ %p\n",
+                       ioctl->ioc->name, mf));
+
+       pScsiTm = (SCSITaskMgmt_t *) mf;
+       pScsiTm->TargetID = ioctl->target;
+       pScsiTm->Bus = hd->port;        /* 0 */
+       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 = MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION;
+
+       for (ii= 0; ii < 8; ii++)
+               pScsiTm->LUN[ii] = 0;
+
+       for (ii=0; ii < 7; ii++)
+               pScsiTm->Reserved2[ii] = 0;
+
+       pScsiTm->TaskMsgContext = 0;
+       dtmprintk((MYIOC_s_INFO_FMT "mptctl_bus_reset: issued.\n", ioctl->ioc->name));
+
+       ioctl->tmPtr = mf;
+       ioctl->TMtimer.expires = jiffies + HZ * 20;     /* 20 seconds */
+       ioctl->status |= MPT_IOCTL_STATUS_TMTIMER_ACTIVE;
+       add_timer(&ioctl->TMtimer);
+
+       retval = mpt_send_handshake_request(mptctl_id, ioctl->ioc->id,
+                       sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, NO_SLEEP);
+
+       if (retval != 0) {
+               dtmprintk((MYIOC_s_WARN_FMT "_send_handshake FAILED!"
+                       " (hd %p, ioc %p, mf %p) \n", ioctl->ioc->name, hd, hd->ioc, mf));
+
+               mptctl_free_tm_flags(ioctl->ioc);
+               del_timer(&ioctl->TMtimer);
+               mpt_free_msg_frame(mptctl_id, ioctl->ioc->id, mf);
+               ioctl->tmPtr = NULL;
+       }
+
+       return retval;
+}
+
+static int
+mptctl_set_tm_flags(MPT_SCSI_HOST *hd) {
+       unsigned long flags;
+
+       spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
+#ifdef MPT_SCSI_USE_NEW_EH
+       if (hd->tmState == TM_STATE_NONE) {
+               hd->tmState = TM_STATE_IN_PROGRESS;
+               hd->tmPending = 1;
+               spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+       } else {
+               spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+               return -EBUSY;
+       }
+#else
+       if (hd->tmPending) {
+               spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+               return -EBUSY;
+       } else {
+               hd->tmPending = 1;
+               spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+       }
+#endif
+       return 0;
+}
+
+static void
+mptctl_free_tm_flags(MPT_ADAPTER *ioc)
+{
+       MPT_SCSI_HOST * hd;
+       unsigned long flags;
+
+       hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
+       if (hd == NULL)
+               return;
+
+       spin_lock_irqsave(&ioc->FreeQlock, flags);
+#ifdef MPT_SCSI_USE_NEW_EH
+       hd->tmState = TM_STATE_ERROR;
+       hd->tmPending = 0;
+       spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+#else
+       hd->tmPending = 0;
+       spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+#endif
+
+       return;
+}
 
-       //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;
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/* mptctl_ioc_reset
+ *
+ * Clean-up functionality. Used only if there has been a
+ * reload of the FW due.
+ *
+ */
+static int
+mptctl_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
+{
+       MPT_IOCTL *ioctl = ioc->ioctl;
+       dctlprintk((KERN_INFO MYNAM ": IOC %s_reset routed to IOCTL driver!\n",
+                       reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post"));
+
+       if (reset_phase == MPT_IOC_PRE_RESET){
+
+               /* Someone has called the reset handler to
+                * do a hard reset. No more replies from the FW.
+                * Delete the timer. TM flags cleaned up by SCSI driver.
+                * Do not need to free msg frame, as re-initialized
+                */
+               if (ioctl && (ioctl->status & MPT_IOCTL_STATUS_TIMER_ACTIVE)){
+                       del_timer(&ioctl->timer);
+               }
+               if (ioctl && (ioctl->status & MPT_IOCTL_STATUS_TMTIMER_ACTIVE)){
+                       ioctl->status &= ~MPT_IOCTL_STATUS_TMTIMER_ACTIVE;
+                       del_timer(&ioctl->TMtimer);
+                       mpt_free_msg_frame(mptctl_id, ioc->id, ioctl->tmPtr);
+               }
+
+       } else {
+               /* Set the status and continue IOCTL
+                * processing. All memory will be free'd
+                * by originating thread after wake_up is
+                * called.
+                */
+               if (ioctl && (ioctl->status & MPT_IOCTL_STATUS_TIMER_ACTIVE)){
+                       ioctl->status = MPT_IOCTL_STATUS_DID_IOCRESET;
+
+                       /* Wake up the calling process
+                        */
+                       ioctl->wait_done = 1;
+                       wake_up(&mptctl_wait);
+               }
        }
 
        return 1;
@@ -208,7 +566,7 @@ mptctl_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply)
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
- *  struct file_operations functionality. 
+ *  struct file_operations functionality.
  *  Members:
  *     llseek, write, read, ioctl, open, release
  */
@@ -234,63 +592,96 @@ mptctl_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
 static ssize_t
 mptctl_read(struct file *file, char *buf, size_t count, loff_t *ptr)
 {
+       printk(KERN_ERR MYNAM ": ioctl READ not yet supported\n");
        return 0;
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
  *  MPT ioctl handler
+ *  cmd - specify the particular IOCTL command to be issued
+ *  arg - data specific to the command. Must not be null.
  */
 static int
-mpt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+mptctl_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;
+       mpt_ioctl_header        *uhdr = (mpt_ioctl_header *) arg;
+       mpt_ioctl_header         khdr;
        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"));
+       dctlprintk(("mptctl_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);
+       if (copy_from_user(&khdr, uhdr, sizeof(khdr))) {
+               printk(KERN_ERR "%s::mptctl_ioctl() @%d - "
+                               "Unable to copy mpt_ioctl_header data @ %p\n",
+                               __FILE__, __LINE__, (void*)uhdr);
                return -EFAULT;
        }
        ret = -ENXIO;                           /* (-6) No such device or address */
 
-       /* Verify intended MPT adapter */
-       iocnumX = ksanity.iocnum & 0xFF;
+
+       /* Test for Compaq-specific IOCTL's.
+        */
+       if ((cmd == CPQFCTS_GETPCIINFO) || (cmd == CPQFCTS_CTLR_STATUS) ||
+               (cmd == CPQFCTS_GETDRIVER) || (cmd == CPQFCTS_SCSI_PASSTHRU) ||
+               (cmd == CPQFCTS_SCSI_IOCTL_FC_TARGET_ADDRESS))
+               return mptctl_compaq_ioctl(file, cmd, arg);
+
+       /* Verify intended MPT adapter - set iocnum and the adapter
+        * pointer (iocp)
+        */
+       iocnumX = khdr.iocnum & 0xFF;
        if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) ||
            (iocp == NULL)) {
-               printk(KERN_ERR "%s::mpt_ioctl() @%d - ioc%d not found!\n",
+               printk(KERN_ERR "%s::mptctl_ioctl() @%d - ioc%d not found!\n",
                                __FILE__, __LINE__, iocnumX);
                return -ENODEV;
        }
 
+
+
+       /* Handle those commands that are just returning
+        * information stored in the driver.
+        * These commands should never time out and are unaffected
+        * by TM and FW reloads.
+        */
+       if ((cmd & ~IOCSIZE_MASK) == (MPTIOCINFO & ~IOCSIZE_MASK)) {
+               return mptctl_getiocinfo(arg, _IOC_SIZE(cmd));
+       } else if (cmd == MPTTARGETINFO) {
+               return mptctl_gettargetinfo(arg);
+       } else if (cmd == MPTTEST) {
+               return mptctl_readtest(arg);
+       } else if (cmd == MPTEVENTQUERY) {
+               return mptctl_eventquery(arg);
+       } else if (cmd == MPTEVENTENABLE) {
+               return mptctl_eventenable(arg);
+       } else if (cmd == MPTEVENTREPORT) {
+               return mptctl_eventreport(arg);
+       } else if (cmd == MPTFWREPLACE) {
+               return mptctl_replace_fw(arg);
+       }
+
+       /* All of these commands require an interrupt or
+        * are unknown/illegal.
+        */
        if ((ret = mptctl_syscall_down(iocp, nonblock)) != 0)
                return ret;
 
-       dprintk((KERN_INFO MYNAM "::mpt_ioctl() - Using %s\n", iocp->name));
+       dctlprintk((MYIOC_s_INFO_FMT ": mptctl_ioctl()\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);
+               ret = mptctl_fw_download(arg);
+               break;
+       case MPTCOMMAND:
+               ret = mptctl_mpt_command(arg);
                break;
-       case MPTSCSICMD:
-               ret = mpt_ioctl_scsi_cmd(arg);
+       case MPTHARDRESET:
+               ret = mptctl_do_reset(arg);
                break;
        default:
                ret = -EINVAL;
@@ -301,6 +692,36 @@ mpt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned lon
        return ret;
 }
 
+static int mptctl_do_reset(unsigned long arg)
+{
+       struct mpt_ioctl_diag_reset *urinfo = (struct mpt_ioctl_diag_reset *) arg;
+       struct mpt_ioctl_diag_reset krinfo;
+       MPT_ADAPTER             *iocp;
+
+       dctlprintk((KERN_INFO "mptctl_do_reset called.\n"));
+
+       if (copy_from_user(&krinfo, urinfo, sizeof(struct mpt_ioctl_diag_reset))) {
+               printk(KERN_ERR "%s@%d::mptctl_do_reset - "
+                               "Unable to copy mpt_ioctl_diag_reset struct @ %p\n",
+                               __FILE__, __LINE__, (void*)urinfo);
+               return -EFAULT;
+       }
+
+       if (mpt_verify_adapter(krinfo.hdr.iocnum, &iocp) < 0) {
+               printk(KERN_ERR "%s@%d::mptctl_do_reset - ioc%d not found!\n",
+                               __FILE__, __LINE__, krinfo.hdr.iocnum);
+               return -ENXIO; /* (-6) No such device or address */
+       }
+
+       if (mpt_HardResetHandler(iocp, NO_SLEEP) != 0) {
+               printk (KERN_ERR "%s@%d::mptctl_do_reset - reset failed.\n",
+                       __FILE__, __LINE__);
+               return -1;
+       }
+
+       return 0;
+}
+
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 static int mptctl_open(struct inode *inode, struct file *file)
 {
@@ -317,13 +738,29 @@ static int mptctl_release(struct inode *inode, struct file *file)
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * MPT FW download function.  Cast the arg into the mpt_fw_xfer structure.
+ * This structure contains: iocnum, firmware length (bytes),
+ *      pointer to user space memory where the fw image is stored.
+ *
+ * Outputs:    None.
+ * Return:     0 if successful
+ *             -EFAULT if data unavailable
+ *             -ENXIO  if no such device
+ *             -EAGAIN if resource problem
+ *             -ENOMEM if no memory for SGE
+ *             -EMLINK if too many chain buffers required
+ *             -EBADRQC if adapter does not support FW download
+ *             -EBUSY if adapter is busy
+ *             -ENOMSG if FW upload returned bad status
+ */
 static int
-mpt_ioctl_fw_download(unsigned long arg)
+mptctl_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
+       dctlprintk((KERN_INFO "mptctl_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",
@@ -331,44 +768,52 @@ mpt_ioctl_fw_download(unsigned long arg)
                return -EFAULT;
        }
 
-       return mpt_ioctl_do_fw_download(kfwdl.iocnum, kfwdl.bufp, kfwdl.fwlen);
+       return mptctl_do_fw_download(kfwdl.iocnum, kfwdl.bufp, kfwdl.fwlen);
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
- * MPT FW Download
+ * FW Download engine.
+ * Outputs:    None.
+ * Return:     0 if successful
+ *             -EFAULT if data unavailable
+ *             -ENXIO  if no such device
+ *             -EAGAIN if resource problem
+ *             -ENOMEM if no memory for SGE
+ *             -EMLINK if too many chain buffers required
+ *             -EBADRQC if adapter does not support FW download
+ *             -EBUSY if adapter is busy
+ *             -ENOMSG if FW upload returned bad status
  */
 static int
-mpt_ioctl_do_fw_download(int ioc, char *ufwbuf, size_t fwlen)
+mptctl_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;
+       FWDownloadTCSGE_t       *ptsge;
+       MptSge_t                *sgl, *sgIn;
+       char                    *sgOut;
+       struct buflist          *buflist;
+       struct buflist          *bl;
+       dma_addr_t               sgl_dma;
        int                      ret;
-
-       SGESimple32_t   *sgl;
-       SGESimple32_t   *sgOut, *sgIn;
-       dma_addr_t       sgl_dma;
-       struct buflist  *buflist = NULL;
-       struct buflist  *bl = NULL;
-       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));
+       int                      numfrags = 0;
+       int                      maxfrags;
+       int                      n = 0;
+       u32                      sgdir;
+       u32                      nib;
+       int                      fw_bytes_copied = 0;
+       int                      i;
+       int                      cntdn;
+       int                      sge_offset = 0;
+       u16                      iocstat;
+
+       dctlprintk((KERN_INFO "mptctl_do_fwdl called. mptctl_id = %xh.\n", mptctl_id));
+
+       dctlprintk((KERN_INFO "DbG: kfwdl.bufp  = %p\n", ufwbuf));
+       dctlprintk((KERN_INFO "DbG: kfwdl.fwlen = %d\n", (int)fwlen));
+       dctlprintk((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",
@@ -376,11 +821,13 @@ mpt_ioctl_do_fw_download(int ioc, char *ufwbuf, size_t fwlen)
                return -ENXIO; /* (-6) No such device or address */
        }
 
+       /*  Valid device. Get a message frame and construct the FW download message.
+        */
        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);
+       ptsge = (FWDownloadTCSGE_t *) &dlmsg->SGL;
+       sgOut = (char *) (ptsge + 1);
 
        /*
         * Construct f/w download request
@@ -392,27 +839,36 @@ mpt_ioctl_do_fw_download(int ioc, char *ufwbuf, size_t fwlen)
        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);
+       /* Set up the Transaction SGE.
+        */
+       ptsge->Reserved = 0;
+       ptsge->ContextSize = 0;
+       ptsge->DetailsLength = 12;
+       ptsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
+       ptsge->Reserved_0100_Checksum = 0;
+       ptsge->ImageOffset = 0;
+       ptsge->ImageSize = cpu_to_le32(fwlen);
+
+       /* Add the SGL
+        */
 
        /*
         * 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:)
+        *
+        * Set the sge_offset to the start of the sgl (bytes).
         */
        sgdir = 0x04000000;             /* IOC will READ from sys mem */
-       if ((sgl = kbuf_alloc_2_sgl(fwlen, sgdir, &numfrags, &buflist, &sgl_dma, iocp)) == NULL)
+       sge_offset = sizeof(MPIHeader_t) + sizeof(FWDownloadTCSGE_t);
+       if ((sgl = kbuf_alloc_2_sgl(fwlen, sgdir, sge_offset,
+                                   &numfrags, &buflist, &sgl_dma, iocp)) == NULL)
                return -ENOMEM;
 
        /*
@@ -420,16 +876,20 @@ mpt_ioctl_do_fw_download(int ioc, char *ufwbuf, size_t fwlen)
         * 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 = (Request Size - FWdownload Size ) / Size of 32 bit SGE
+        *      Request         maxfrags
+        *      128             12
+        *      96              8
+        *      64              4
         */
-       maxfrags = (iocp->req_sz - sizeof(MPIHeader_t) - sizeof(FWDownloadTCSGE_t)) / sizeof(SGESimple32_t);
+       maxfrags = (iocp->req_sz - sizeof(MPIHeader_t) - sizeof(FWDownloadTCSGE_t)) 
+                       / (sizeof(dma_addr_t) + sizeof(u32));
        if (numfrags > maxfrags) {
                ret = -EMLINK;
                goto fwdl_out;
        }
 
-       dprintk((KERN_INFO "DbG: sgl buffer  = %p, sgfrags = %d\n", sgl, numfrags));
+       dctlprintk((KERN_INFO "DbG: sgl buffer  = %p, sgfrags = %d\n", sgl, numfrags));
 
        /*
         * Parse SG list, copying sgl itself,
@@ -439,12 +899,18 @@ mpt_ioctl_do_fw_download(int ioc, char *ufwbuf, size_t fwlen)
        sgIn = sgl;
        bl = buflist;
        for (i=0; i < numfrags; i++) {
-               nib = (le32_to_cpu(sgIn->FlagsLength) & 0xF0000000) >> 28;
-               /* skip ignore/chain. */
+
+               /* Get the SGE type: 0 - TCSGE, 3 - Chain, 1 - Simple SGE
+                * Skip everything but Simple. If simple, copy from
+                *      user space into kernel space.
+                * Note: we should not have anything but Simple as
+                *      Chain SGE are illegal.
+                */
+               nib = (sgIn->FlagsLength & 0x30000000) >> 28;
                if (nib == 0 || nib == 3) {
                        ;
                } else if (sgIn->Address) {
-                       *sgOut = *sgIn;
+                       mpt_add_sge(sgOut, sgIn->FlagsLength, sgIn->Address);
                        n++;
                        if (copy_from_user(bl->kptr, ufwbuf+fw_bytes_copied, bl->len)) {
                                printk(KERN_ERR "%s@%d::_ioctl_fwdl - "
@@ -456,7 +922,7 @@ mpt_ioctl_do_fw_download(int ioc, char *ufwbuf, size_t fwlen)
                }
                sgIn++;
                bl++;
-               sgOut++;
+               sgOut += (sizeof(dma_addr_t) + sizeof(u32));
        }
 
 #ifdef MPT_DEBUG
@@ -478,26 +944,24 @@ mpt_ioctl_do_fw_download(int ioc, char *ufwbuf, size_t fwlen)
        /*
         *  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
-                       }
+       for (cntdn=HZ*60, i=1; ReplyMsg == NULL; cntdn--, i++) {
+               if (!cntdn) {
                        ret = -ETIME;
-                       if (++foo > 60000000)
-                               goto fwdl_out;
-                       mb();
-                       schedule();
-                       barrier();
+                       goto fwdl_out;
+               }
+
+               if (!(i%HZ)) {
+                       dctlprintk((KERN_INFO "DbG::_do_fwdl: "
+                                  "In ReplyMsg loop - iteration %d\n",
+                                  i));
                }
+
+               set_current_state(TASK_INTERRUPTIBLE);
+               schedule_timeout(1);
        }
 
        if (sgl)
-               kfree_sgl(sgl, sgl_dma, buflist, iocp);
+               kfree_sgl(sgl, sgl_dma, buflist, iocp);
 
        iocstat = le16_to_cpu(ReplyMsg->IOCStatus) & MPI_IOCSTATUS_MASK;
        if (iocstat == MPI_IOCSTATUS_SUCCESS) {
@@ -527,32 +991,43 @@ fwdl_out:
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
- *  NEW rwperf (read/write performance) stuff starts here...
+ * SGE Allocation routine
+ *
+ * Inputs:     bytes - number of bytes to be transferred
+ *             sgdir - data direction
+ *             sge_offset - offset (in bytes) from the start of the request
+ *                     frame to the first SGE
+ *             ioc - pointer to the mptadapter
+ * Outputs:    frags - number of scatter gather elements
+ *             blp - point to the buflist pointer
+ *             sglbuf_dma - pointer to the (dma) sgl
+ * Returns:    Null if failes
+ *             pointer to the (virtual) sgl if successful.
  */
-
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-static SGESimple32_t *
-kbuf_alloc_2_sgl(int bytes, u32 sgdir, int *frags,
+static MptSge_t *
+kbuf_alloc_2_sgl(int bytes, u32 sgdir, int sge_offset, int *frags,
                 struct buflist **blp, dma_addr_t *sglbuf_dma, MPT_ADAPTER *ioc)
 {
-       SGESimple32_t   *sglbuf = NULL;
-       struct buflist  *buflist = NULL;
+       MptSge_t        *sglbuf = NULL;         /* pointer to array of SGE */
+                                               /* and chain buffers */
+       struct buflist  *buflist = NULL;        /* kernel routine */
+       MptSge_t        *sgl;
        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;
+       dma_addr_t       pa;                                    // phys addr
        int              i, buflist_ent;
        int              sg_spill = MAX_FRAGS_SPILL1;
        int              dir;
-
+       /* initialization */
        *frags = 0;
        *blp = NULL;
+
+       /* Allocate and initialize an array of kernel
+        * structures for the SG elements.
+        */
        i = MAX_SGL_BYTES / 8;
        buflist = kmalloc(i, GFP_USER);
        if (buflist == NULL)
@@ -560,6 +1035,11 @@ kbuf_alloc_2_sgl(int bytes, u32 sgdir, int *frags,
        memset(buflist, 0, i);
        buflist_ent = 0;
 
+       /* Allocate a single block of memory to store the sg elements and
+        * the chain buffers.  The calling routine is responsible for
+        * copying the data in this array into the correct place in the
+        * request and chain buffers.
+        */
        sglbuf = pci_alloc_consistent(ioc->pcidev, MAX_SGL_BYTES, sglbuf_dma);
        if (sglbuf == NULL)
                goto free_and_fail;
@@ -569,7 +1049,15 @@ kbuf_alloc_2_sgl(int bytes, u32 sgdir, int *frags,
        else
                dir = PCI_DMA_FROMDEVICE;
 
+       /* At start:
+        *      sgl = sglbuf = point to beginning of sg buffer
+        *      buflist_ent = 0 = first kernel structure
+        *      sg_spill = number of SGE that can be written before the first
+        *              chain element.
+        *
+        */
        sgl = sglbuf;
+       sg_spill = ((ioc->req_sz - sge_offset)/(sizeof(dma_addr_t) + sizeof(u32))) - 1;
        while (bytes_allocd < bytes) {
                this_alloc = MIN(alloc_sz, bytes-bytes_allocd);
                buflist[buflist_ent].len = this_alloc;
@@ -590,11 +1078,9 @@ kbuf_alloc_2_sgl(int bytes, u32 sgdir, int *frags,
                        dma_addr_t dma_addr;
 
                        bytes_allocd += this_alloc;
-
-                       /* Write one SIMPLE sge */
-                       sgl->FlagsLength = cpu_to_le32(0x10000000|sgdir|this_alloc);
+                       sgl->FlagsLength = (0x10000000|MPT_SGE_FLAGS_ADDRESSING|sgdir|this_alloc);
                        dma_addr = pci_map_single(ioc->pcidev, buflist[buflist_ent].kptr, this_alloc, dir);
-                       sgl->Address = cpu_to_le32(dma_addr);
+                       sgl->Address = dma_addr;
 
                        fragcnt++;
                        numfrags++;
@@ -607,33 +1093,13 @@ kbuf_alloc_2_sgl(int bytes, u32 sgdir, int *frags,
 
                /* 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++;
+                       printk(KERN_WARNING MYNAM "-SG: No can do - " "Chain required!   :-(\n");
+                       printk(KERN_WARNING MYNAM "(freeing %d frags)\n", numfrags);
+                       goto free_and_fail;
                }
 
                /* overflow check... */
-               if (numfrags*8 > MAX_SGL_BYTES) {
+               if (numfrags*8 > MAX_SGL_BYTES){
                        /* GRRRRR... */
                        printk(KERN_WARNING MYNAM "-SG: No can do - "
                                            "too many SG frags!   :-(\n");
@@ -644,20 +1110,16 @@ kbuf_alloc_2_sgl(int bytes, u32 sgdir, int *frags,
        }
 
        /* 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);
+       sgl[-1].FlagsLength |= 0xC1000000;
 
        *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":""));
+       dctlprintk((KERN_INFO MYNAM "-SG: kbuf_alloc_2_sgl() - "
+                          "%d SG frags generated!\n",
+                          numfrags));
 
-       dprintk((KERN_INFO MYNAM "-SG: kbuf_alloc_2_sgl() - "
+       dctlprintk((KERN_INFO MYNAM "-SG: kbuf_alloc_2_sgl() - "
                           "last (big) alloc_sz=%d\n",
                           alloc_sz));
 
@@ -672,10 +1134,10 @@ free_and_fail:
                        u8 *kptr;
                        int len;
 
-                       if ((le32_to_cpu(sglbuf[i].FlagsLength) >> 24) == 0x30)
+                       if ((sglbuf[i].FlagsLength >> 24) == 0x30)
                                continue;
 
-                       dma_addr = le32_to_cpu(sglbuf[i].Address);
+                       dma_addr = sglbuf[i].Address;
                        kptr = buflist[i].kptr;
                        len = buflist[i].len;
 
@@ -688,21 +1150,24 @@ free_and_fail:
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * Routine to free the SGL elements.
+ */
 static void
-kfree_sgl(SGESimple32_t *sgl, dma_addr_t sgl_dma, struct buflist *buflist, MPT_ADAPTER *ioc)
+kfree_sgl(MptSge_t *sgl, dma_addr_t sgl_dma, struct buflist *buflist, MPT_ADAPTER *ioc)
 {
-       SGESimple32_t   *sg = sgl;
+       MptSge_t        *sg = sgl;
        struct buflist  *bl = buflist;
        u32              nib;
        int              dir;
        int              n = 0;
 
-       if (le32_to_cpu(sg->FlagsLength) & 0x04000000)
+       if (sg->FlagsLength & 0x04000000)
                dir = PCI_DMA_TODEVICE;
        else
                dir = PCI_DMA_FROMDEVICE;
 
-       nib = (le32_to_cpu(sg->FlagsLength) & 0xF0000000) >> 28;
+       nib = (sg->FlagsLength & 0xF0000000) >> 28;
        while (! (nib & 0x4)) { /* eob */
                /* skip ignore/chain. */
                if (nib == 0 || nib == 3) {
@@ -712,7 +1177,7 @@ kfree_sgl(SGESimple32_t *sgl, dma_addr_t sgl_dma, struct buflist *buflist, MPT_A
                        void *kptr;
                        int len;
 
-                       dma_addr = le32_to_cpu(sg->Address);
+                       dma_addr = sg->Address;
                        kptr = bl->kptr;
                        len = bl->len;
                        pci_unmap_single(ioc->pcidev, dma_addr, len, dir);
@@ -730,7 +1195,7 @@ kfree_sgl(SGESimple32_t *sgl, dma_addr_t sgl_dma, struct buflist *buflist, MPT_A
                void *kptr;
                int len;
 
-               dma_addr = le32_to_cpu(sg->Address);
+               dma_addr = sg->Address;
                kptr = bl->kptr;
                len = bl->len;
                pci_unmap_single(ioc->pcidev, dma_addr, len, dir);
@@ -740,363 +1205,1711 @@ kfree_sgl(SGESimple32_t *sgl, dma_addr_t sgl_dma, struct buflist *buflist, MPT_A
 
        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));
+       dctlprintk((KERN_INFO MYNAM "-SG: Free'd 1 SGL buf + %d kbufs!\n", n));
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     mptctl_getiocinfo - Query the host adapter for IOC information.
+ *     @arg: User space argument
+ *
+ * Outputs:    None.
+ * Return:     0 if successful
+ *             -EFAULT if data unavailable
+ *             -ENODEV  if no such device/adapter
+ */
 static int
-mpt_ioctl_rwperf_init(struct mpt_raw_r_w *dest, unsigned long src,
-                     char *caller, MPT_ADAPTER **iocpp)
+mptctl_getiocinfo (unsigned long arg, unsigned int data_size)
 {
-       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));
-               }
-       }
+       struct mpt_ioctl_iocinfo *uarg = (struct mpt_ioctl_iocinfo *) arg;
+       struct mpt_ioctl_iocinfo karg;
+       MPT_ADAPTER             *ioc;
+       struct pci_dev          *pdev;
+       struct Scsi_Host        *sh;
+       MPT_SCSI_HOST           *hd;
+       int                     iocnum;
+       int                     numDevices = 0;
+       unsigned int            max_id;
+       int                     ii;
+       int                     port;
+       int                     cim_rev;
+       u8                      revision;
+
+       dctlprintk((": mptctl_getiocinfo called.\n"));
+       if (data_size == sizeof(struct mpt_ioctl_iocinfo))
+               cim_rev = 1;
+       else if (data_size == (sizeof(struct mpt_ioctl_iocinfo) - sizeof(struct mpt_ioctl_pci_info)))
+               cim_rev = 0;
+       else
+               return -EFAULT;
 
-       return ioc;
-}
+       if (copy_from_user(&karg, uarg, data_size)) {
+               printk(KERN_ERR "%s@%d::mptctl_getiocinfo - "
+                       "Unable to read in mpt_ioctl_iocinfo struct @ %p\n",
+                               __FILE__, __LINE__, (void*)uarg);
+               return -EFAULT;
+       }
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+       if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
+           (ioc == NULL)) {
+               printk(KERN_ERR "%s::mptctl_getiocinfo() @%d - ioc%d not found!\n",
+                               __FILE__, __LINE__, iocnum);
+               return -ENODEV;
+       }
 
-/*  Treat first N blocks of disk as sacred!  */
-#define SACRED_BLOCKS  100
+       /* Verify the data transfer size is correct.
+        * Ignore the port setting.
+        */
+       if (karg.hdr.maxDataSize != data_size) {
+               printk(KERN_ERR "%s@%d::mptctl_getiocinfo - "
+                       "Structure size mismatch. Command not completed.\n",
+                               __FILE__, __LINE__);
+               return -EFAULT;
+       }
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-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));
+       /* Fill in the data and return the structure to the calling
+        * program
+        */
+       if (ioc->chip_type == C1030)
+               karg.adapterType = MPT_IOCTL_INTERFACE_SCSI;
+       else
+               karg.adapterType = MPT_IOCTL_INTERFACE_FC;
 
-    /* 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;
+       port = karg.hdr.port;
 
-            if (blkno > blkhi)
-                blkhi = blkno;
+       karg.port = port;
+       pdev = (struct pci_dev *) ioc->pcidev;
 
-            DevIosCount[targetM][lunM]++;
+       karg.pciId = pdev->device;
+       pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
+       karg.hwRev = revision;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+       karg.subSystemDevice = pdev->subsystem_device;
+       karg.subSystemVendor = pdev->subsystem_vendor;
+#endif
 
-            /*
-             *  Finally, post the request
-             */
-            mpt_put_msg_frame(mptctl_id, ioc, mf);
+       if (cim_rev == 1) {
+               /* Get the PCI bus, device, and function numbers for the IOC
+                */
+               karg.pciInfo.u.bits.busNumber = pdev->bus->number;
+               karg.pciInfo.u.bits.deviceNumber = PCI_SLOT( pdev->devfn );
+               karg.pciInfo.u.bits.functionNumber = PCI_FUNC( pdev->devfn );
+       }
 
+       /* Get number of devices
+         */
+       if ((sh = ioc->sh) != NULL) {
+                /* sh->max_id = maximum target ID + 1
+                */
+               max_id = sh->max_id - 1;
+               hd = (MPT_SCSI_HOST *) sh->hostdata;
+
+               /* Check all of the target structures and
+                * keep a counter.
+                */
+               if (hd && hd->Targets) {
+                       for (ii = 0; ii <= max_id; ii++) {
+                               if (hd->Targets[ii])
+                                       numDevices++;
+                       }
+               }
+       }
+       karg.numDevices = numDevices;
 
-            /* let linux breath! */
-            mb();
-            schedule();
-            barrier();
+       /* Set the BIOS and FW Version
+        */
+       karg.FWVersion = ioc->facts.FWVersion.Word;
+       karg.BIOSVersion = ioc->biosVersion;
 
-            //dprintk((KERN_DEBUG MYNAM "-perf: inner-loop, cnt=%d\n", iters));
+       /* Set the Version Strings.
+        */
+       strncpy (karg.driverVersion, MPT_LINUX_PACKAGE_NAME, MPT_IOCTL_VERSION_LENGTH);
 
-        } while ((--iters > 0) && !rwperf_reset);
+       karg.busChangeEvent = 0;
+       karg.hostId = ioc->pfacts[port].PortSCSIID;
+       karg.rsvd[0] = karg.rsvd[1] = 0;
 
-        dprintk((KERN_INFO MYNAM "-perf: DbG: blklo=%d, blkhi=%d\n", blklo, blkhi));
-        dprintk((KERN_INFO MYNAM "-perf: target-loop, thisTarget=%d\n", target));
+       /* Copy the data from kernel memory to user memory
+        */
+       if (copy_to_user((char *)arg, &karg, data_size)) {
+               printk(KERN_ERR "%s@%d::mptctl_getiocinfo - "
+                       "Unable to write out mpt_ioctl_iocinfo struct @ %p\n",
+                               __FILE__, __LINE__, (void*)uarg);
+               return -EFAULT;
+       }
 
-//        //  TEMPORARY!
-//        target = 0;
+       return 0;
+}
 
-//    } while (target);
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     mptctl_gettargetinfo - Query the host adapter for target information.
+ *     @arg: User space argument
+ *
+ * Outputs:    None.
+ * Return:     0 if successful
+ *             -EFAULT if data unavailable
+ *             -ENODEV  if no such device/adapter
+ */
+static int
+mptctl_gettargetinfo (unsigned long arg)
+{
+       struct mpt_ioctl_targetinfo *uarg = (struct mpt_ioctl_targetinfo *) arg;
+       struct mpt_ioctl_targetinfo karg;
+       MPT_ADAPTER             *ioc;
+       struct Scsi_Host        *sh;
+       MPT_SCSI_HOST           *hd;
+       char                    *pmem;
+       int                     *pdata;
+       int                     iocnum;
+       int                     numDevices = 0;
+       unsigned int            max_id;
+       int                     ii, jj, lun;
+       int                     maxWordsLeft;
+       int                     numBytes;
+       u8                      port;
+
+       dctlprintk(("mptctl_gettargetinfo called.\n"));
+       if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_targetinfo))) {
+               printk(KERN_ERR "%s@%d::mptctl_gettargetinfo - "
+                       "Unable to read in mpt_ioctl_targetinfo struct @ %p\n",
+                               __FILE__, __LINE__, (void*)uarg);
+               return -EFAULT;
+       }
 
+       if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
+           (ioc == NULL)) {
+               printk(KERN_ERR "%s::mptctl_gettargetinfo() @%d - ioc%d not found!\n",
+                               __FILE__, __LINE__, iocnum);
+               return -ENODEV;
+       }
 
-    if (DevIosCount[targetM][lunM]) {
-        dprintk((KERN_INFO "  DbG: DevIosCount[%d][%d]=%d\n",
-                targetM, lunM, DevIosCount[targetM][lunM]));
-    }
+       /* Get the port number and set the maximum number of bytes
+        * in the returned structure.
+        * Ignore the port setting.
+        */
+       numBytes = karg.hdr.maxDataSize - sizeof(mpt_ioctl_header);
+       maxWordsLeft = numBytes/sizeof(int);
+       port = karg.hdr.port;
 
-    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;
+       if (maxWordsLeft <= 0) {
+               printk(KERN_ERR "%s::mptctl_gettargetinfo() @%d - no memory available!\n",
+                               __FILE__, __LINE__);
+               return -ENOMEM;
+       }
 
-    pci_free_consistent(iocp->pcidev, 256, SenseBuf, SenseBufDMA);
+       /* Fill in the data and return the structure to the calling
+        * program
+        */
 
-    if (sgl)
-        kfree_sgl(sgl, sgl_dma, buflist, iocp);
+       /* struct mpt_ioctl_targetinfo does not contain sufficient space
+        * for the target structures so when the IOCTL is called, there is
+        * not sufficient stack space for the structure. Allocate memory,
+        * populate the memory, copy back to the user, then free memory.
+        * targetInfo format:
+        * bits 31-24: reserved
+        *      23-16: LUN
+        *      15- 8: Bus Number
+        *       7- 0: Target ID
+        */
+       pmem = kmalloc(numBytes, GFP_KERNEL);
+       if (pmem == NULL) {
+               printk(KERN_ERR "%s::mptctl_gettargetinfo() @%d - no memory available!\n",
+                               __FILE__, __LINE__);
+               return -ENOMEM;
+       }
+       memset(pmem, 0, numBytes);
+       pdata =  (int *) pmem;
+
+       /* Get number of devices
+         */
+       if ( (sh = ioc->sh) != NULL) {
+
+               max_id = sh->max_id - 1;
+               hd = (MPT_SCSI_HOST *) sh->hostdata;
+
+               /* Check all of the target structures.
+                * Save the Id and increment the counter,
+                * if ptr non-null.
+                * sh->max_id = maximum target ID + 1
+                */
+               if (hd && hd->Targets) {
+                       ii = 0;
+                       while (ii <= max_id) {
+                               if (hd->Targets[ii]) {
+                                       for (jj = 0; jj <= MPT_LAST_LUN; jj++) {
+                                               lun = (1 << jj);
+                                               if (hd->Targets[ii]->luns & lun) {
+                                                       numDevices++;
+                                                       *pdata = (jj << 16) | ii;
+                                                       --maxWordsLeft;
+
+                                                       pdata++;
+
+                                                       if (maxWordsLeft <= 0) {
+                                                               break;
+                                                       }
+                                               }
+                                       }
+                               }
+                               ii++;
+                       }
+               }
+       }
+       karg.numDevices = numDevices;
 
-    dprintk((KERN_INFO "  *** done ***\n"));
+       /* Copy part of the data from kernel memory to user memory
+        */
+       if (copy_to_user((char *)arg, &karg,
+                               sizeof(struct mpt_ioctl_targetinfo))) {
+               printk(KERN_ERR "%s@%d::mptctl_gettargetinfo - "
+                       "Unable to write out mpt_ioctl_targetinfo struct @ %p\n",
+                               __FILE__, __LINE__, (void*)uarg);
+               kfree(pmem);
+               return -EFAULT;
+       }
 
-    return 0;
-}
+       /* Copy the remaining data from kernel memory to user memory
+        */
+       if (copy_to_user((char *) uarg->targetInfo, pmem, numBytes)) {
+               printk(KERN_ERR "%s@%d::mptctl_gettargetinfo - "
+                       "Unable to write out mpt_ioctl_targetinfo struct @ %p\n",
+                               __FILE__, __LINE__, (void*)pdata);
+               kfree(pmem);
+               return -EFAULT;
+       }
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-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] );
-                       }
+       kfree(pmem);
 
        return 0;
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/* MPT IOCTL Test function.
+ *
+ * Outputs:    None.
+ * Return:     0 if successful
+ *             -EFAULT if data unavailable
+ *             -ENODEV  if no such device/adapter
+ */
 static int
-mpt_ioctl_rwperf_reset(unsigned long arg)
+mptctl_readtest (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;
-                       }
+       struct mpt_ioctl_test   *uarg = (struct mpt_ioctl_test *) arg;
+       struct mpt_ioctl_test    karg;
+       MPT_ADAPTER *ioc;
+       int iocnum;
+
+       dctlprintk(("mptctl_readtest called.\n"));
+       if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_test))) {
+               printk(KERN_ERR "%s@%d::mptctl_readtest - "
+                       "Unable to read in mpt_ioctl_test struct @ %p\n",
+                               __FILE__, __LINE__, (void*)uarg);
+               return -EFAULT;
+       }
+
+       if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
+           (ioc == NULL)) {
+               printk(KERN_ERR "%s::mptctl_readtest() @%d - ioc%d not found!\n",
+                               __FILE__, __LINE__, iocnum);
+               return -ENODEV;
+       }
+
+       /* Fill in the data and return the structure to the calling
+        * program
+        */
+
+#ifdef MFCNT
+       karg.chip_type = ioc->mfcnt;
+#else
+       karg.chip_type = ioc->chip_type;
+#endif
+       strncpy (karg.name, ioc->name, MPT_MAX_NAME);
+       strncpy (karg.product, ioc->prod_name, MPT_PRODUCT_LENGTH);
+
+       /* Copy the data from kernel memory to user memory
+        */
+       if (copy_to_user((char *)arg, &karg, sizeof(struct mpt_ioctl_test))) {
+               printk(KERN_ERR "%s@%d::mptctl_readtest - "
+                       "Unable to write out mpt_ioctl_test struct @ %p\n",
+                               __FILE__, __LINE__, (void*)uarg);
+               return -EFAULT;
+       }
+
+       return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     mptctl_eventquery - Query the host adapter for the event types
+ *     that are being logged.
+ *     @arg: User space argument
+ *
+ * Outputs:    None.
+ * Return:     0 if successful
+ *             -EFAULT if data unavailable
+ *             -ENODEV  if no such device/adapter
+ */
+static int
+mptctl_eventquery (unsigned long arg)
+{
+       struct mpt_ioctl_eventquery     *uarg = (struct mpt_ioctl_eventquery *) arg;
+       struct mpt_ioctl_eventquery      karg;
+       MPT_ADAPTER *ioc;
+       int iocnum;
+
+       dctlprintk(("mptctl_eventquery called.\n"));
+       if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_eventquery))) {
+               printk(KERN_ERR "%s@%d::mptctl_eventquery - "
+                       "Unable to read in mpt_ioctl_eventquery struct @ %p\n",
+                               __FILE__, __LINE__, (void*)uarg);
+               return -EFAULT;
+       }
+
+       if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
+           (ioc == NULL)) {
+               printk(KERN_ERR "%s::mptctl_eventquery() @%d - ioc%d not found!\n",
+                               __FILE__, __LINE__, iocnum);
+               return -ENODEV;
+       }
+
+       karg.eventEntries = ioc->eventLogSize;
+       karg.eventTypes = ioc->eventTypes;
+
+       /* Copy the data from kernel memory to user memory
+        */
+       if (copy_to_user((char *)arg, &karg, sizeof(struct mpt_ioctl_eventquery))) {
+               printk(KERN_ERR "%s@%d::mptctl_eventquery - "
+                       "Unable to write out mpt_ioctl_eventquery struct @ %p\n",
+                               __FILE__, __LINE__, (void*)uarg);
+               return -EFAULT;
+       }
+       return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+mptctl_eventenable (unsigned long arg)
+{
+       struct mpt_ioctl_eventenable    *uarg = (struct mpt_ioctl_eventenable *) arg;
+       struct mpt_ioctl_eventenable     karg;
+       MPT_ADAPTER *ioc;
+       int iocnum;
+
+       dctlprintk(("mptctl_eventenable called.\n"));
+       if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_eventenable))) {
+               printk(KERN_ERR "%s@%d::mptctl_eventenable - "
+                       "Unable to read in mpt_ioctl_eventenable struct @ %p\n",
+                               __FILE__, __LINE__, (void*)uarg);
+               return -EFAULT;
+       }
+
+       if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
+           (ioc == NULL)) {
+               printk(KERN_ERR "%s::mptctl_eventenable() @%d - ioc%d not found!\n",
+                               __FILE__, __LINE__, iocnum);
+               return -ENODEV;
+       }
+
+       if (ioc->events == NULL) {
+               /* Have not yet allocated memory - do so now.
+                */
+               int sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS);
+               ioc->events = kmalloc(sz, GFP_KERNEL);
+               if (ioc->events == NULL) {
+                       printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n");
+                       return -ENOMEM;
+               }
+               memset(ioc->events, 0, sz);
+               ioc->alloc_total += sz;
+
+               ioc->eventLogSize = MPTCTL_EVENT_LOG_SIZE;
+               ioc->eventContext = 0;
+        }
+
+       /* Update the IOC event logging flag.
+        */
+       ioc->eventTypes = karg.eventTypes;
+
+       return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+mptctl_eventreport (unsigned long arg)
+{
+       struct mpt_ioctl_eventreport    *uarg = (struct mpt_ioctl_eventreport *) arg;
+       struct mpt_ioctl_eventreport     karg;
+       MPT_ADAPTER              *ioc;
+       int                      iocnum;
+       int                      numBytes, maxEvents, max;
+
+       dctlprintk(("mptctl_eventreport called.\n"));
+       if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_eventreport))) {
+               printk(KERN_ERR "%s@%d::mptctl_eventreport - "
+                       "Unable to read in mpt_ioctl_eventreport struct @ %p\n",
+                               __FILE__, __LINE__, (void*)uarg);
+               return -EFAULT;
+       }
+
+       if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
+           (ioc == NULL)) {
+               printk(KERN_ERR "%s::mptctl_eventreport() @%d - ioc%d not found!\n",
+                               __FILE__, __LINE__, iocnum);
+               return -ENODEV;
+       }
+
+       numBytes = karg.hdr.maxDataSize - sizeof(mpt_ioctl_header);
+       maxEvents = numBytes/sizeof(MPT_IOCTL_EVENTS);
+
+
+       max = ioc->eventLogSize < maxEvents ? ioc->eventLogSize : maxEvents;
+
+       /* If fewer than 1 event is requested, there must have
+        * been some type of error.
+        */
+       if ((max < 1) || !ioc->events)
+               return -ENODATA;
+
+       /* Copy the data from kernel memory to user memory
+        */
+       numBytes = max * sizeof(MPT_IOCTL_EVENTS);
+       if (copy_to_user((char *) uarg->eventData, ioc->events, numBytes)) {
+               printk(KERN_ERR "%s@%d::mptctl_eventreport - "
+                       "Unable to write out mpt_ioctl_eventreport struct @ %p\n",
+                               __FILE__, __LINE__, (void*)ioc->events);
+               return -EFAULT;
+       }
 
        return 0;
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 static int
-mpt_ioctl_scsi_cmd(unsigned long arg)
+mptctl_replace_fw (unsigned long arg)
 {
-       return -ENOSYS;
+       struct mpt_ioctl_replace_fw     *uarg = (struct mpt_ioctl_replace_fw *) arg;
+       struct mpt_ioctl_replace_fw      karg;
+       MPT_ADAPTER              *ioc;
+       fw_image_t               **fwmem = NULL;
+       int                      iocnum;
+       int                      newFwSize;
+       int                      num_frags, alloc_sz;
+       int                      ii;
+       u32                      offset;
+
+       dctlprintk(("mptctl_replace_fw called.\n"));
+       if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_replace_fw))) {
+               printk(KERN_ERR "%s@%d::mptctl_replace_fw - "
+                       "Unable to read in mpt_ioctl_replace_fw struct @ %p\n",
+                               __FILE__, __LINE__, (void*)uarg);
+               return -EFAULT;
+       }
+
+       if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
+           (ioc == NULL)) {
+               printk(KERN_ERR "%s::mptctl_replace_fw() @%d - ioc%d not found!\n",
+                               __FILE__, __LINE__, iocnum);
+               return -ENODEV;
+       }
+
+       /* If not caching FW, return 0
+        */
+       if ((ioc->cached_fw == NULL) && (ioc->alt_ioc) && (ioc->alt_ioc->cached_fw == NULL))
+               return 0;
+
+       /* Allocate memory for the new FW image
+        */
+       newFwSize = karg.newImageSize;
+       fwmem = mpt_alloc_fw_memory(ioc, newFwSize, &num_frags, &alloc_sz); 
+       if (fwmem == NULL)
+               return -ENOMEM;
+
+       offset = 0;
+       for (ii = 0; ii < num_frags; ii++) {
+               /* Copy the data from user memory to kernel space
+                */
+               if (copy_from_user(fwmem[ii]->fw, uarg->newImage + offset, fwmem[ii]->size)) {
+                       printk(KERN_ERR "%s@%d::mptctl_replace_fw - "
+                               "Unable to read in mpt_ioctl_replace_fw image @ %p\n",
+                                       __FILE__, __LINE__, (void*)uarg);
+
+                       mpt_free_fw_memory(ioc, fwmem);
+                       return -EFAULT;
+               }
+               offset += fwmem[ii]->size;
+       }
+
+
+       /* Free the old FW image 
+        */
+       if (ioc->cached_fw) {
+               mpt_free_fw_memory(ioc, 0);
+               ioc->cached_fw = fwmem;
+               ioc->alloc_total += alloc_sz;
+       } else if ((ioc->alt_ioc) && (ioc->alt_ioc->cached_fw)) {
+               mpt_free_fw_memory(ioc->alt_ioc, 0);
+               ioc->alt_ioc->cached_fw = fwmem;
+               ioc->alt_ioc->alloc_total += alloc_sz;
+       }
+
+       /* Update IOCFactsReply
+        */
+       ioc->facts.FWImageSize = newFwSize;
+       if (ioc->alt_ioc)
+               ioc->alt_ioc->facts.FWImageSize = newFwSize;
+
+       return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/* MPT IOCTL MPTCOMMAND function.
+ * Cast the arg into the mpt_ioctl_mpt_command structure.
+ *
+ * Outputs:    None.
+ * Return:     0 if successful
+ *             -EBUSY  if previous command timout and IOC reset is not complete.
+ *             -EFAULT if data unavailable
+ *             -ENODEV if no such device/adapter
+ *             -ETIME  if timer expires
+ *             -ENOMEM if memory allocation error
+ */
+static int
+mptctl_mpt_command (unsigned long arg)
+{
+       struct mpt_ioctl_command *uarg = (struct mpt_ioctl_command *) arg;
+       struct mpt_ioctl_command  karg;
+       MPT_ADAPTER     *ioc;
+       int             iocnum;
+       int             rc;
+
+       dctlprintk(("mptctl_command called.\n"));
+
+       if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_command))) {
+               printk(KERN_ERR "%s@%d::mptctl_mpt_command - "
+                       "Unable to read in mpt_ioctl_command struct @ %p\n",
+                               __FILE__, __LINE__, (void*)uarg);
+               return -EFAULT;
+       }
+
+       if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
+           (ioc == NULL)) {
+               printk(KERN_ERR "%s::mptctl_mpt_command() @%d - ioc%d not found!\n",
+                               __FILE__, __LINE__, iocnum);
+               return -ENODEV;
+       }
+
+       rc = mptctl_do_mpt_command (karg, (char *) &uarg->MF, 0);
+
+       return rc;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/* Worker routine for the IOCTL MPTCOMMAND and MPTCOMMAND32 (sparc) commands.
+ *
+ * Outputs:    None.
+ * Return:     0 if successful
+ *             -EBUSY  if previous command timout and IOC reset is not complete.
+ *             -EFAULT if data unavailable
+ *             -ENODEV if no such device/adapter
+ *             -ETIME  if timer expires
+ *             -ENOMEM if memory allocation error
+ *             -EPERM if SCSI I/O and target is untagged
+ */
+static int
+mptctl_do_mpt_command (struct mpt_ioctl_command karg, char *mfPtr, int local)
+{
+       MPT_ADAPTER     *ioc;
+       MPT_FRAME_HDR   *mf = NULL;
+       MPIHeader_t     *hdr;
+       char            *psge;
+       MptSge_t        *this_sge = NULL;
+       MptSge_t        *sglbuf = NULL;
+       struct buflist  bufIn;  /* data In buffer */
+       struct buflist  bufOut; /* data Out buffer */
+       dma_addr_t      sglbuf_dma;
+       dma_addr_t      dma_addr;
+       int             dir;    /* PCI data direction */
+       int             sgSize = 0;     /* Num SG elements */
+       int             this_alloc;
+       int              iocnum, flagsLength;
+       int              sz, rc = 0;
+       int              msgContext;
+       int             tm_flags_set = 0;
+       u16             req_idx;
+
+       dctlprintk(("mptctl_do_mpt_command called.\n"));
+
+       if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
+           (ioc == NULL)) {
+               printk(KERN_ERR "%s::mptctl_do_mpt_command() @%d - ioc%d not found!\n",
+                               __FILE__, __LINE__, iocnum);
+               return -ENODEV;
+       }
+       if (!ioc->ioctl) {
+               printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
+                       "No memory available during driver init.\n",
+                               __FILE__, __LINE__);
+               return -ENOMEM;
+       } else if (ioc->ioctl->status & MPT_IOCTL_STATUS_DID_IOCRESET) {
+               printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
+                       "Busy with IOC Reset \n", __FILE__, __LINE__);
+               return -EBUSY;
+       }
+
+       /* Verify that the final request frame will not be too large.
+        */
+       sz = karg.dataSgeOffset * 4;
+       if (karg.dataInSize > 0)
+               sz += sizeof(dma_addr_t) + sizeof(u32);
+       if (karg.dataOutSize > 0)
+               sz += sizeof(dma_addr_t) + sizeof(u32);
+
+       if ( sz > ioc->req_sz) {
+               printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
+                       "Request frame too large (%d) maximum (%d)\n",
+                               __FILE__, __LINE__, sz, ioc->req_sz);
+               return -EFAULT;
+       }
+
+       /* Get a free request frame and save the message context.
+        */
+        if ((mf = mpt_get_msg_frame(mptctl_id, ioc->id)) == NULL)
+                return -EAGAIN;
+
+       hdr = (MPIHeader_t *) mf;
+       msgContext = le32_to_cpu(hdr->MsgContext);
+       req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
+
+       /* Copy the request frame
+        * Reset the saved message context.
+        */
+        if (local) {
+               /* Request frame in kernel space
+                */
+               memcpy((char *)mf, (char *) mfPtr, karg.dataSgeOffset * 4);
+        } else {
+               /* Request frame in user space
+                */
+               if (copy_from_user((char *)mf, (char *) mfPtr,
+                                       karg.dataSgeOffset * 4)){
+                       printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
+                               "Unable to read MF from mpt_ioctl_command struct @ %p\n",
+                               __FILE__, __LINE__, (void*)mfPtr);
+                       rc = -EFAULT;
+                       goto done_free_mem;
+               }
+        }
+       hdr->MsgContext = cpu_to_le32(msgContext);
+
+
+       /* Verify that this request is allowed.
+        */
+       switch (hdr->Function) {
+       case MPI_FUNCTION_IOC_FACTS:
+       case MPI_FUNCTION_PORT_FACTS:
+       case MPI_FUNCTION_CONFIG:
+       case MPI_FUNCTION_FC_COMMON_TRANSPORT_SEND:
+       case MPI_FUNCTION_FC_EX_LINK_SRVC_SEND:
+       case MPI_FUNCTION_FW_UPLOAD:
+       case MPI_FUNCTION_SCSI_ENCLOSURE_PROCESSOR:
+       case MPI_FUNCTION_FW_DOWNLOAD:
+               break;
+
+       case MPI_FUNCTION_SCSI_IO_REQUEST:
+               if (ioc->sh) {
+                       SCSIIORequest_t *pScsiReq = (SCSIIORequest_t *) mf;
+                       VirtDevice      *pTarget = NULL;
+                       MPT_SCSI_HOST   *hd = NULL;
+                       int qtag = MPI_SCSIIO_CONTROL_UNTAGGED;
+                       int scsidir = 0;
+                       int target = (int) pScsiReq->TargetID;
+                       int dataSize;
+
+                       pScsiReq->MsgFlags = mpt_msg_flags();
+
+                       /* verify that app has not requested
+                        *      more sense data than driver
+                        *      can provide, if so, reset this parameter
+                        * set the sense buffer pointer low address
+                        * update the control field to specify Q type
+                        */
+                       if (karg.maxSenseBytes > MPT_SENSE_BUFFER_SIZE)
+                               pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
+
+                       pScsiReq->SenseBufferLowAddr =
+                               cpu_to_le32(ioc->sense_buf_low_dma
+                                  + (req_idx * MPT_SENSE_BUFFER_ALLOC));
+
+                       if ( (hd = (MPT_SCSI_HOST *) ioc->sh->hostdata)) {
+                               if (hd->Targets)
+                                       pTarget = hd->Targets[target];
+                       }
+
+                       if (pTarget &&(pTarget->tflags & MPT_TARGET_FLAGS_Q_YES))
+                               qtag = MPI_SCSIIO_CONTROL_SIMPLEQ;
+                       else {
+                               rc = -EPERM;
+                               goto done_free_mem;
+                       }
+
+                       /* Have the IOCTL driver set the direction based
+                        * on the dataOutSize (ordering issue with Sparc).
+                        */
+                       if (karg.dataOutSize > 0 ) {
+                               scsidir = MPI_SCSIIO_CONTROL_WRITE;
+                               dataSize = karg.dataOutSize;
+                       }
+                       else {
+                               scsidir = MPI_SCSIIO_CONTROL_READ;
+                               dataSize = karg.dataInSize;
+                       }
+
+                       pScsiReq->Control = cpu_to_le32(scsidir | qtag);
+                       pScsiReq->DataLength = cpu_to_le32(dataSize);
+
+                       ioc->ioctl->reset = MPTCTL_RESET_OK;
+                       ioc->ioctl->target = target;
+
+               } else {
+                       printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
+                               "SCSI driver is not loaded. \n",
+                                       __FILE__, __LINE__);
+                       rc = -EFAULT;
+                       goto done_free_mem;
+               }
+               break;
+
+       case MPI_FUNCTION_RAID_ACTION:
+               /* Just add a SGE
+                */
+               break;
+
+       case MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH:
+               if (ioc->sh) {
+                       SCSIIORequest_t *pScsiReq = (SCSIIORequest_t *) mf;
+                       int qtag = MPI_SCSIIO_CONTROL_SIMPLEQ;
+                       int scsidir = MPI_SCSIIO_CONTROL_READ;
+                       int dataSize;
+
+                       pScsiReq->MsgFlags = mpt_msg_flags();
+
+                       /* verify that app has not requested
+                        *      more sense data than driver
+                        *      can provide, if so, reset this parameter
+                        * set the sense buffer pointer low address
+                        * update the control field to specify Q type
+                        */
+                       if (karg.maxSenseBytes > MPT_SENSE_BUFFER_SIZE)
+                               pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
+
+                       pScsiReq->SenseBufferLowAddr =
+                               cpu_to_le32(ioc->sense_buf_low_dma
+                                  + (req_idx * MPT_SENSE_BUFFER_ALLOC));
+
+                       /* All commands to physical devices are tagged
+                        */
+
+                       /* Have the IOCTL driver set the direction based
+                        * on the dataOutSize (ordering issue with Sparc).
+                        */
+                       if (karg.dataOutSize > 0 ) {
+                               scsidir = MPI_SCSIIO_CONTROL_WRITE;
+                               dataSize = karg.dataOutSize;
+                       }
+                       else {
+                               scsidir = MPI_SCSIIO_CONTROL_READ;
+                               dataSize = karg.dataInSize;
+                       }
+
+                       pScsiReq->Control = cpu_to_le32(scsidir | qtag);
+                       pScsiReq->DataLength = cpu_to_le32(dataSize);
+
+                       ioc->ioctl->reset = MPTCTL_RESET_OK;
+                       ioc->ioctl->target = pScsiReq->TargetID;
+               } else {
+                       printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
+                               "SCSI driver is not loaded. \n",
+                                       __FILE__, __LINE__);
+                       rc = -EFAULT;
+                       goto done_free_mem;
+               }
+               break;
+
+       case MPI_FUNCTION_SCSI_TASK_MGMT:
+               { 
+                       MPT_SCSI_HOST *hd = NULL;
+                       if ((ioc->sh == NULL) || ((hd = (MPT_SCSI_HOST *)ioc->sh->hostdata) == NULL)) {
+                               printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
+                                       "SCSI driver not loaded or SCSI host not found. \n",
+                                       __FILE__, __LINE__);
+                               rc = -EFAULT;
+                               goto done_free_mem;
+                       }  else if (mptctl_set_tm_flags(hd) != 0) {
+                               rc = -EPERM;
+                               goto done_free_mem;
+                       }
+                       tm_flags_set = 1;
+               }
+               break;
+
+       default:
+               /*
+                * MPI_FUNCTION_IOC_INIT
+                * MPI_FUNCTION_PORT_ENABLE
+                * MPI_FUNCTION_TARGET_CMD_BUFFER_POST
+                * MPI_FUNCTION_TARGET_ASSIST
+                * MPI_FUNCTION_TARGET_STATUS_SEND
+                * MPI_FUNCTION_TARGET_MODE_ABORT
+                * MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET
+                * MPI_FUNCTION_IO_UNIT_RESET
+                * MPI_FUNCTION_HANDSHAKE
+                * MPI_FUNCTION_REPLY_FRAME_REMOVAL
+                * MPI_FUNCTION_EVENT_NOTIFICATION
+                *  (driver handles event notification)
+                * MPI_FUNCTION_EVENT_ACK
+                */
+
+               /*  What to do with these???  CHECK ME!!!
+                       MPI_FUNCTION_FC_LINK_SRVC_BUF_POST
+                       MPI_FUNCTION_FC_LINK_SRVC_RSP
+                       MPI_FUNCTION_FC_ABORT
+                       MPI_FUNCTION_FC_PRIMITIVE_SEND
+                       MPI_FUNCTION_LAN_SEND
+                       MPI_FUNCTION_LAN_RECEIVE
+                       MPI_FUNCTION_LAN_RESET
+               */
+
+               printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
+                       "Illegal request (function 0x%x) \n",
+                       __FILE__, __LINE__, hdr->Function);
+               rc = -EFAULT;
+               goto done_free_mem;
+       }
+
+       /* Add the SGL ( at most one data in SGE and one data out SGE )
+        * In the case of two SGE's - the data out (write) will always
+        * preceede the data in (read) SGE. psgList is used to free the
+        * allocated memory.
+        */
+       psge = (char *) ( ((int *) mf) + karg.dataSgeOffset);
+       flagsLength = 0;
+
+       /* bufIn and bufOut are used for user to kernel space transfers
+        */
+       bufIn.kptr = bufOut.kptr = NULL;
+       bufIn.len = bufOut.len = 0;
+
+       if (karg.dataOutSize > 0 )
+               sgSize ++;
+
+       if (karg.dataInSize > 0 )
+               sgSize ++;
+
+       if (sgSize > 0) {
+
+               /* Allocate memory for the SGL.
+                * Used to free kernel memory once
+                * the MF is freed.
+                */
+               sglbuf = pci_alloc_consistent (ioc->pcidev,
+                       sgSize*sizeof(MptSge_t), &sglbuf_dma);
+               if (sglbuf == NULL) {
+                       rc = -ENOMEM;
+                       goto done_free_mem;
+               }
+               this_sge = sglbuf;
+
+               /* Set up the dataOut memory allocation */
+               if (karg.dataOutSize > 0) {
+                       dir = PCI_DMA_TODEVICE;
+                       if (karg.dataInSize > 0 ) {
+                               flagsLength = ( MPI_SGE_FLAGS_SIMPLE_ELEMENT |
+                                               MPI_SGE_FLAGS_DIRECTION |
+                                               mpt_addr_size() )
+                                               << MPI_SGE_FLAGS_SHIFT;
+                       } else {
+                               flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
+                       }
+                       flagsLength |= karg.dataOutSize;
+
+                       this_alloc = karg.dataOutSize;
+                       bufOut.len = this_alloc;
+                       bufOut.kptr = pci_alloc_consistent(
+                                       ioc->pcidev, this_alloc, &dma_addr);
+
+                       if (bufOut.kptr == NULL) {
+                               rc = -ENOMEM;
+                               goto done_free_mem;
+                       } else {
+                               /* Copy user data to kernel space.
+                                */
+                               if (copy_from_user(bufOut.kptr,
+                                               karg.dataOutBufPtr,
+                                               bufOut.len)) {
+
+                                       printk(KERN_ERR
+                                               "%s@%d::mptctl_do_mpt_command - Unable "
+                                               "to read user data "
+                                               "struct @ %p\n",
+                                               __FILE__, __LINE__,(void*)karg.dataOutBufPtr);
+                                       rc =  -EFAULT;
+                                       goto done_free_mem;
+                               }
+
+                               /* Set up this SGE.
+                                * Copy to MF and to sglbuf
+                                */
+                               mpt_add_sge(psge, flagsLength, dma_addr);
+                               psge += (sizeof(u32) + sizeof(dma_addr_t));
+
+                               this_sge->FlagsLength = flagsLength;
+                               this_sge->Address = dma_addr;
+                               this_sge++;
+                       }
+               }
+
+               if (karg.dataInSize > 0) {
+                       dir = PCI_DMA_FROMDEVICE;
+                       flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
+                       flagsLength |= karg.dataInSize;
+
+                       this_alloc = karg.dataInSize;
+                       bufIn.len = this_alloc;
+                       bufIn.kptr = pci_alloc_consistent(ioc->pcidev,
+                                                       this_alloc, &dma_addr);
+                       if (bufIn.kptr == NULL) {
+                               rc = -ENOMEM;
+                               goto done_free_mem;
+                       } else {
+                               /* Set up this SGE
+                                * Copy to MF and to sglbuf
+                                */
+                               mpt_add_sge(psge, flagsLength, dma_addr);
+
+                               this_sge->FlagsLength = flagsLength;
+                               this_sge->Address = dma_addr;
+                               this_sge++;
+                       }
+               }
+       } else  {
+               /* Add a NULL SGE
+                */
+               mpt_add_sge(psge, flagsLength, (dma_addr_t) -1);
+       }
+
+       /* The request is complete. Set the timer parameters
+        * and issue the request.
+        */
+       if (karg.timeout > 0) {
+               ioc->ioctl->timer.expires = jiffies + HZ*karg.timeout;
+       } else {
+               ioc->ioctl->timer.expires = jiffies + HZ*MPT_IOCTL_DEFAULT_TIMEOUT;
+       }
+
+       ioc->ioctl->wait_done = 0;
+       ioc->ioctl->status |= MPT_IOCTL_STATUS_TIMER_ACTIVE;
+       add_timer(&ioc->ioctl->timer);
+
+       if (hdr->Function == MPI_FUNCTION_SCSI_TASK_MGMT) {
+               rc = mpt_send_handshake_request(mptctl_id, ioc->id,
+                               sizeof(SCSITaskMgmt_t), (u32*)mf, NO_SLEEP);
+               if (rc == 0) {
+                       wait_event(mptctl_wait, ioc->ioctl->wait_done);
+               } else {
+                       mptctl_free_tm_flags(ioc);
+                       tm_flags_set= 0;
+                       del_timer(&ioc->ioctl->timer);
+                       ioc->ioctl->status &= ~MPT_IOCTL_STATUS_TIMER_ACTIVE;
+                       ioc->ioctl->status = MPT_IOCTL_STATUS_TM_FAILED;
+               }
+       } else {
+               mpt_put_msg_frame(mptctl_id, ioc->id, mf);
+               wait_event(mptctl_wait, ioc->ioctl->wait_done);
+       }
+
+       /* The command is complete.  * Return data to the user.
+        *
+        * If command completed,  mf has been freed so cannot
+        * use this memory.
+        *
+        * If timeout, a recovery  mechanism has been called.
+        * Need to free the mf.
+        */
+       if (ioc->ioctl->status & MPT_IOCTL_STATUS_DID_IOCRESET) {
+
+               /* A timeout - there is no data to return to the
+                * the user other than an error.
+                * The timer callback deleted the
+                * timer and reset the adapter queues.
+                */
+               printk(KERN_WARNING "%s@%d::mptctl_do_mpt_command - "
+                       "Timeout Occurred on IOCTL! Reset IOC.\n", __FILE__, __LINE__);
+               tm_flags_set= 0;
+               rc = -ETIME;
+
+               /* Free memory and return to the calling function
+                */
+               goto done_free_mem;
+       } else if (ioc->ioctl->status & MPT_IOCTL_STATUS_TM_FAILED) {
+               /* User TM request failed!
+                */
+               rc = -ENODATA;
+       } else {
+               /* Callback freed request frame.
+                */
+               mf = NULL;
+
+               /* If a valid reply frame, copy to the user.
+                * Offset 2: reply length in U32's
+                */
+               if (ioc->ioctl->status & MPT_IOCTL_STATUS_RF_VALID) {
+                       if (karg.maxReplyBytes < ioc->reply_sz) {
+                                sz = MIN(karg.maxReplyBytes, 4*ioc->ioctl->ReplyFrame[2]);
+                       } else {
+                                sz = MIN(ioc->reply_sz, 4*ioc->ioctl->ReplyFrame[2]);
+                       }
+
+                       if (sz > 0) {
+                               if (copy_to_user((char *)karg.replyFrameBufPtr,
+                                        &ioc->ioctl->ReplyFrame, sz)){
+
+                                        printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
+                                        "Unable to write out reply frame %p\n",
+                                        __FILE__, __LINE__, (void*)karg.replyFrameBufPtr);
+                                        rc =  -ENODATA;
+                                        goto done_free_mem;
+                               }
+                       }
+               }
+
+               /* If valid sense data, copy to user.
+                */
+               if (ioc->ioctl->status & MPT_IOCTL_STATUS_SENSE_VALID) {
+                       sz = MIN(karg.maxSenseBytes, MPT_SENSE_BUFFER_SIZE);
+                       if (sz > 0) {
+                               if (copy_to_user((char *)karg.senseDataPtr, ioc->ioctl->sense, sz)) {
+                                       printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
+                                       "Unable to write sense data to user %p\n",
+                                       __FILE__, __LINE__,
+                                       (void*)karg.senseDataPtr);
+                                       rc =  -ENODATA;
+                                       goto done_free_mem;
+                               }
+                       }
+               }
+
+               /* If the overall status is _GOOD and data in, copy data
+                * to user.
+                */
+               if ((ioc->ioctl->status & MPT_IOCTL_STATUS_COMMAND_GOOD) &&
+                                       (karg.dataInSize > 0) && (bufIn.kptr)) {
+
+                       if (copy_to_user((char *)karg.dataInBufPtr,
+                                        bufIn.kptr, karg.dataInSize)) {
+                               printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
+                                       "Unable to write data to user %p\n",
+                                       __FILE__, __LINE__,
+                                       (void*)karg.dataInBufPtr);
+                               rc =  -ENODATA;
+                       }
+               }
+       }
+
+done_free_mem:
+       /* Clear status bits.
+        */
+       ioc->ioctl->status = 0;
+
+       if (tm_flags_set)
+               mptctl_free_tm_flags(ioc);
+
+       if (sglbuf) {
+               this_sge = sglbuf;
+
+               /* Free the allocated memory.
+                */
+                if (bufOut.kptr != NULL ) {
+                       dma_addr = this_sge->Address;
+                       this_sge++;     /* go to next structure */
+                       this_alloc = bufOut.len;
+                       pci_free_consistent(ioc->pcidev,
+                               this_alloc, (void *) &bufOut, dma_addr);
+               }
+
+               if (bufIn.kptr != NULL ) {
+                       dma_addr = this_sge->Address;
+                       this_alloc = bufIn.len;
+
+                       pci_free_consistent(ioc->pcidev,
+                                       this_alloc, (void *) &bufIn, dma_addr);
+               }
+
+               this_alloc = sgSize * sizeof(MptSge_t);
+               pci_free_consistent(ioc->pcidev,
+                               this_alloc, (void *) sglbuf, sglbuf_dma);
+
+       }
+
+       /* mf will be null if allocation failed OR
+        * if command completed OK (callback freed)
+        */
+       if (mf)
+               mpt_free_msg_frame(mptctl_id, ioc->id, mf);
+
+       return rc;
 }
 
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/* Routine for the Compaq IOCTL commands.
+ *
+ * Outputs:    None.
+ * Return:     0 if successful
+ *             -EBUSY  if previous command timout and IOC reset is not complete.
+ *             -EFAULT if data unavailable
+ *             -ENODEV if no such device/adapter
+ *             -ETIME  if timer expires
+ *             -ENOMEM if memory allocation error
+ */
+static int
+mptctl_compaq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+       int iocnum = 0;
+       unsigned iocnumX = 0;
+       int ret;
+       int nonblock = (file->f_flags & O_NONBLOCK);
+       MPT_ADAPTER *iocp = NULL;
+
+       if (cmd == CPQFCTS_SCSI_PASSTHRU) {
+               /* Update the iocnum */
+               if (copy_from_user(&iocnumX, (int *)arg, sizeof(int))) {
+                       printk(KERN_ERR "%s::mptctl_compaq_ioctl() @%d - "
+                               "Unable to read controller number @ %p\n",
+                               __FILE__, __LINE__, (void*)arg);
+                       return -EFAULT;
+               }
+               iocnumX &= 0xFF;
+       }
+
+       if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) ||
+           (iocp == NULL)) {
+               printk(KERN_ERR "%s::mptctl_compaq_ioctl() @%d - ioc%d not found!\n",
+                               __FILE__, __LINE__, iocnumX);
+               return -ENODEV;
+       }
+
+       /* All of these commands require an interrupt or
+        * are unknown/illegal.
+        */
+       if ((ret = mptctl_syscall_down(iocp, nonblock)) != 0)
+               return ret;
+
+       dctlprintk((MYIOC_s_INFO_FMT ": mptctl_compaq_ioctl()\n", iocp->name));
+
+       switch(cmd) {
+       case CPQFCTS_GETPCIINFO:
+               ret = mptctl_cpq_getpciinfo(arg);
+               break;
+       case CPQFCTS_GETDRIVER:
+               ret = mptctl_cpq_getdriver(arg);
+               break;
+       case CPQFCTS_CTLR_STATUS:
+               ret = mptctl_cpq_ctlr_status(arg);
+               break;
+       case CPQFCTS_SCSI_IOCTL_FC_TARGET_ADDRESS:
+               ret = mptctl_cpq_target_address(arg);
+               break;
+       case CPQFCTS_SCSI_PASSTHRU:
+               ret = mptctl_cpq_passthru(arg);
+               break;
+       default:
+               ret = -EINVAL;
+       }
+
+       up(&mptctl_syscall_sem_ioc[iocp->id]);
+
+       return ret;
+
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/* mptctl_cpq_getpciinfo - Get PCI Information in format desired by Compaq
+ *
+ * Outputs:    None.
+ * Return:     0 if successful
+ *             -EBUSY  if previous command timout and IOC reset is not complete.
+ *             -EFAULT if data unavailable
+ *             -ENODEV if no such device/adapter
+ *             -ETIME  if timer expires
+ */
+static int
+mptctl_cpq_getpciinfo(unsigned long arg)
+{
+       cpqfc_pci_info_struct *uarg = (cpqfc_pci_info_struct *) arg;
+       cpqfc_pci_info_struct karg;
+       MPT_ADAPTER             *ioc;
+       struct pci_dev          *pdev;
+       CONFIGPARMS             cfg;
+       ConfigPageHeader_t      hdr;
+       int                     iocnum = 0, iocnumX = 0;
+       dma_addr_t              buf_dma;
+       u8                      *pbuf = NULL;
+       int                     failed;
+
+       dctlprintk((": mptctl_cpq_pciinfo called.\n"));
+       if (copy_from_user(&karg, uarg, sizeof(cpqfc_pci_info_struct))) {
+               printk(KERN_ERR "%s@%d::mptctl_cpq_pciinfo - "
+                       "Unable to read in cpqfc_pci_info_struct @ %p\n",
+                               __FILE__, __LINE__, (void*)uarg);
+               return -EINVAL;
+       }
+
+       if (((iocnum = mpt_verify_adapter(iocnumX, &ioc)) < 0) ||
+           (ioc == NULL)) {
+               printk(KERN_ERR "%s::mptctl_pciinfo() @%d - ioc%d not found!\n",
+                               __FILE__, __LINE__, iocnum);
+               return -ENODEV;
+       }
+
+       pdev = (struct pci_dev *) ioc->pcidev;
+
+       /* Populate the structure. */
+       karg.bus = pdev->bus->number;
+       karg.bus_type = 1;      /* 1 = PCI; 4 = unknown */
+       karg.device_fn = PCI_FUNC(pdev->devfn);
+       karg.slot_number = PCI_SLOT(pdev->devfn);
+       karg.vendor_id = pdev->vendor;
+       karg.device_id = pdev->device;
+       karg.board_id = (karg.device_id | (karg.vendor_id << 16));
+       karg.class_code = pdev->class;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+       karg.sub_vendor_id = pdev->subsystem_vendor;
+       karg.sub_device_id = pdev->subsystem_device;
+#endif
+
+       /* Issue a config request to get the device serial number
+        */
+       hdr.PageVersion = 0;
+       hdr.PageLength = 0;
+       hdr.PageNumber = 0;
+       hdr.PageType = MPI_CONFIG_PAGETYPE_MANUFACTURING;
+       cfg.hdr = &hdr;
+       cfg.physAddr = -1;
+       cfg.pageAddr = 0;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+       cfg.dir = 0;    /* read */
+       cfg.timeout = 10;
+
+       failed = 1;
+
+       if (mpt_config(ioc, &cfg) == 0) {
+               if (cfg.hdr->PageLength > 0) {
+                       /* Issue the second config page request */
+                       cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+
+                       pbuf = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, &buf_dma);
+                       if (pbuf) {
+                               cfg.physAddr = buf_dma;
+                               if (mpt_config(ioc, &cfg) == 0) {
+                                       ManufacturingPage0_t *pdata = (ManufacturingPage0_t *) pbuf;
+                                       strncpy(karg.serial_number, pdata->BoardTracerNumber, 17);
+                                       failed = 0;
+                               }
+                               pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, pbuf, buf_dma);
+                               pbuf = NULL;
+                       }
+               }
+       }
+       if (failed)
+               strncpy(karg.serial_number, " ", 17);
+
+       /* Copy the data from kernel memory to user memory
+        */
+       if (copy_to_user((char *)arg, &karg,
+                               sizeof(cpqfc_pci_info_struct))) {
+               printk(KERN_ERR "%s@%d::mptctl_cpq_pciinfo - "
+                       "Unable to write out cpqfc_pci_info_struct @ %p\n",
+                               __FILE__, __LINE__, (void*)uarg);
+               return -EFAULT;
+       }
+
+       return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/* mptctl_cpq_getdriver - Get Driver Version in format desired by Compaq
+ *
+ * Outputs:    None.
+ * Return:     0 if successful
+ *             -EFAULT if data unavailable
+ *             -ENODEV if no such device/adapter
+ */
+static int
+mptctl_cpq_getdriver(unsigned long arg)
+{
+       int             *uarg = (int *)arg;
+       int             karg;
+       MPT_ADAPTER     *ioc = NULL;
+       int             iocnum = 0, iocnumX = 0;
+       int             ii, jj;
+       char            version[10];
+       char            val;
+       char            *vptr = NULL;
+       char            *pptr = NULL;
+
+       dctlprintk((": mptctl_cpq_getdriver called.\n"));
+       if (copy_from_user(&karg, uarg, sizeof(int))) {
+               printk(KERN_ERR "%s@%d::mptctl_cpq_getdriver - "
+                       "Unable to read in struct @ %p\n",
+                               __FILE__, __LINE__, (void*)uarg);
+               return -EFAULT;
+       }
+
+       if (((iocnum = mpt_verify_adapter(iocnumX, &ioc)) < 0) ||
+           (ioc == NULL)) {
+               printk(KERN_ERR "%s::mptctl_cpq_getdriver() @%d - ioc%d not found!\n",
+                               __FILE__, __LINE__, iocnum);
+               return -ENODEV;
+       }
+
+       strncpy(version, MPT_LINUX_VERSION_COMMON, 8);
+
+       karg = 0;
+       vptr = version;
+       ii = 3;
+       while (ii > 0) {
+               pptr = strchr(vptr, '.');
+               if (pptr) {
+                       *pptr = '\0';
+                       val = 0;
+                       for (jj=0; vptr[jj]>='0' && vptr[jj]<='9'; jj++)
+                               val = 10 * val + (vptr[jj] - '0');
+                       karg |= (val << (8*ii));
+                       pptr++;
+                       vptr = pptr;
+               } else
+                       break;
+               ii--;
+       }
+
+       /* Copy the data from kernel memory to user memory
+        */
+       if (copy_to_user((char *)arg, &karg,
+                               sizeof(int))) {
+               printk(KERN_ERR "%s@%d::mptctl_cpq_getdriver - "
+                       "Unable to write out stuct @ %p\n",
+                               __FILE__, __LINE__, (void*)uarg);
+               return -EFAULT;
+       }
+
+       return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/* mptctl_cpq_ctlr_status - Get controller status in format desired by Compaq
+ *
+ * Outputs:    None.
+ * Return:     0 if successful
+ *             -EFAULT if data unavailable
+ *             -ENODEV if no such device/adapter
+ */
+static int
+mptctl_cpq_ctlr_status(unsigned long arg)
+{
+       cpqfc_ctlr_status *uarg = (cpqfc_ctlr_status *) arg;
+       cpqfc_ctlr_status karg;
+       MPT_ADAPTER             *ioc;
+       int                     iocnum = 0, iocnumX = 0;
+
+       dctlprintk((": mptctl_cpq_pciinfo called.\n"));
+       if (copy_from_user(&karg, uarg, sizeof(cpqfc_ctlr_status))) {
+               printk(KERN_ERR "%s@%d::mptctl_cpq_ctlr_status - "
+                       "Unable to read in cpqfc_ctlr_status @ %p\n",
+                               __FILE__, __LINE__, (void*)uarg);
+               return -EFAULT;
+       }
+
+       if (((iocnum = mpt_verify_adapter(iocnumX, &ioc)) < 0) ||
+           (ioc == NULL)) {
+               printk(KERN_ERR "%s::mptctl_cpq_ctlr_status() @%d - ioc%d not found!\n",
+                               __FILE__, __LINE__, iocnum);
+               return -ENODEV;
+       }
+
+       karg.status = ioc->last_state;
+       karg.offline_reason = 0;
+
+       /* Copy the data from kernel memory to user memory
+        */
+       if (copy_to_user((char *)arg, &karg,
+                               sizeof(cpqfc_ctlr_status))) {
+               printk(KERN_ERR "%s@%d::mptctl_cpq_ctlr_status - "
+                       "Unable to write out cpqfc_ctlr_status @ %p\n",
+                               __FILE__, __LINE__, (void*)uarg);
+               return -EFAULT;
+       }
+
+       return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/* mptctl_cpq_target_address - Get WWN Information in format desired by Compaq
+ *
+ * Outputs:    None.
+ * Return:     0 if successful
+ *             -EBUSY  if previous command timout and IOC reset is not complete.
+ *             -EFAULT if data unavailable
+ *             -ENODEV if no such device/adapter
+ *             -ETIME  if timer expires
+ */
+static int
+mptctl_cpq_target_address(unsigned long arg)
+{
+       Scsi_FCTargAddress *uarg = (Scsi_FCTargAddress *) arg;
+       Scsi_FCTargAddress karg;
+       MPT_ADAPTER             *ioc;
+       int                     iocnum = 0, iocnumX = 0;
+       CONFIGPARMS             cfg;
+       ConfigPageHeader_t      hdr;
+       dma_addr_t              buf_dma;
+       u8                      *pbuf = NULL;
+       FCPortPage0_t           *ppp0;
+       int                     ii, failed;
+       u32                     low, high;
+
+       dctlprintk((": mptctl_cpq_target_address called.\n"));
+       if (copy_from_user(&karg, uarg, sizeof(Scsi_FCTargAddress))) {
+               printk(KERN_ERR "%s@%d::mptctl_cpq_target_address - "
+                       "Unable to read in Scsi_FCTargAddress @ %p\n",
+                               __FILE__, __LINE__, (void*)uarg);
+               return -EFAULT;
+       }
+
+       if (((iocnum = mpt_verify_adapter(iocnumX, &ioc)) < 0) ||
+           (ioc == NULL)) {
+               printk(KERN_ERR "%s::mptctl_cpq_target_address() @%d - ioc%d not found!\n",
+                               __FILE__, __LINE__, iocnum);
+               return -ENODEV;
+       }
+
+       karg.host_port_id = 0;
+
+       /* Issue a config request to get the device wwn
+        */
+       hdr.PageVersion = 0;
+       hdr.PageLength = 0;
+       hdr.PageNumber = 0;
+       hdr.PageType = MPI_CONFIG_PAGETYPE_FC_PORT;
+       cfg.hdr = &hdr;
+       cfg.physAddr = -1;
+       cfg.pageAddr = 0;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+       cfg.dir = 0;    /* read */
+       cfg.timeout = 10;
+
+       failed = 1;
+
+       if (mpt_config(ioc, &cfg) == 0) {
+               if (cfg.hdr->PageLength > 0) {
+                       /* Issue the second config page request */
+                       cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+
+                       pbuf = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, &buf_dma);
+                       if (pbuf) {
+                               cfg.physAddr = buf_dma;
+                               if (mpt_config(ioc, &cfg) == 0) {
+                                       ppp0 = (FCPortPage0_t *) pbuf;
+
+                                       low = le32_to_cpu(ppp0->WWNN.Low);
+                                       high = le32_to_cpu(ppp0->WWNN.High);
+
+                                       for (ii = 0; ii < 4; ii++) {
+                                               karg.host_wwn[7-ii] = low & 0xFF;
+                                               karg.host_wwn[3-ii] = high & 0xFF;
+                                               low = (low >> 8);
+                                               high = (high >> 8);
+                                       }
+                                       failed = 0;
+                               }
+                               pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, pbuf, buf_dma);
+                               pbuf = NULL;
+                       }
+               }
+       }
+
+       if (failed) {
+               for (ii = 7; ii >= 0; ii--)
+                       karg.host_wwn[ii] = 0;
+       }
+
+       /* Copy the data from kernel memory to user memory
+        */
+       if (copy_to_user((char *)arg, &karg,
+                               sizeof(Scsi_FCTargAddress))) {
+               printk(KERN_ERR "%s@%d::mptctl_cpq_target_address - "
+                       "Unable to write out Scsi_FCTargAddress @ %p\n",
+                               __FILE__, __LINE__, (void*)uarg);
+               return -EFAULT;
+       }
+
+       return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/* mptctl_cpq_passthru - Construct and issue a SCSI IO Passthru
+ *
+ * Requires the SCSI host driver to be loaded.
+ * I386 version.
+ *
+ * Outputs:    None.
+ * Return:     0 if successful
+ *             -EBUSY  if previous command timout and IOC reset is not complete.
+ *             -EFAULT if data unavailable
+ *             -ENODEV if no such device/adapter
+ *             -ETIME  if timer expires
+ */
+static int
+mptctl_cpq_passthru(unsigned long arg)
+{
+       VENDOR_IOCTL_REQ        *uarg = (VENDOR_IOCTL_REQ *) arg;
+       VENDOR_IOCTL_REQ        karg;
+       cpqfc_passthru_t        kpass;
+       MPT_ADAPTER             *ioc;
+       int                     iocnum = 0, iocnumX = 0;
+       int                     rc;
+
+       dctlprintk((": mptctl_cpq_passthru called.\n"));
+       if (copy_from_user(&karg, uarg, sizeof(VENDOR_IOCTL_REQ))) {
+               printk(KERN_ERR "%s@%d::mptctl_cpq_passthru - "
+                       "Unable to read in VENDOR_IOCTL_REQ @ %p\n",
+                               __FILE__, __LINE__, (void*)uarg);
+               return -EFAULT;
+       }
+
+       /* Set the IOC number */
+       iocnumX = karg.lc & 0xFF;
+       if (((iocnum = mpt_verify_adapter(iocnumX, &ioc)) < 0) ||
+           (ioc == NULL)) {
+               printk(KERN_ERR "%s::mptctl_cpq_passthru() @%d - ioc%d not found!\n",
+                               __FILE__, __LINE__, iocnum);
+               return -ENODEV;
+       }
+
+       if (ioc->sh == NULL) {
+               printk(KERN_ERR "%s::mptctl_cpq_passthru() @%d - SCSI Host driver not loaded!\n",
+                               __FILE__, __LINE__);
+               return -EFAULT;
+       }
+
+       /* Read in the second buffer */
+       if (copy_from_user(&kpass, uarg->argp, sizeof(cpqfc_passthru_t))) {
+               printk(KERN_ERR "%s@%d::mptctl_cpq_passthru - "
+                       "Unable to read in cpqfc_passthru_t @ %p\n",
+                               __FILE__, __LINE__, (void*)uarg);
+               return -EFAULT;
+       }
+
+
+       /* Generate the SCSI IO command and issue */
+       rc = mptctl_compaq_scsiio(&karg, &kpass);
+       return rc;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/* mptctl_compaq_scsiio - Reformat Compaq structures into driver structures
+ * Call the generic _do_mpt_command function.
+ *
+ * Requires the SCSI host driver to be loaded.
+ * I386 version.
+ *
+ * Outputs:    None.
+ * Return:     0 if successful
+ *             -EBUSY  if previous command timout and IOC reset is not complete.
+ *             -EFAULT if data unavailable
+ *             -ENODEV if no such device/adapter
+ *             -ETIME  if timer expires
+ */
+static int
+mptctl_compaq_scsiio(VENDOR_IOCTL_REQ *pVenReq, cpqfc_passthru_t *pPass)
+{
+       struct mpt_ioctl_command karg;
+       SCSIIORequest_t          request ;
+       SCSIIORequest_t          *pMf;
+       int                      ii, rc;
+       u8                       opcode;
+
+       /* Fill in parameters to karg */
+       karg.hdr.iocnum = pVenReq->lc;
+       karg.hdr.port = 0;
+       karg.hdr.maxDataSize = 0;       /* not used */
+       karg.timeout = 0;               /* use default */
+
+       karg.replyFrameBufPtr = NULL;   /* no reply data */
+       karg.maxReplyBytes = 0;
+
+       karg.senseDataPtr = pPass->sense_data;
+       karg.maxSenseBytes = pPass->sense_len;  /* max is 40 */
+
+       if (pPass->rw_flag == MPT_COMPAQ_WRITE) {
+               karg.dataOutBufPtr = pPass->bufp;
+               karg.dataOutSize = pPass->len;
+               karg.dataInBufPtr = NULL;
+               karg.dataInSize = 0;
+       } else {
+               karg.dataInBufPtr = pPass->bufp;
+               karg.dataInSize = pPass->len;
+               karg.dataOutBufPtr = NULL;
+               karg.dataOutSize = 0;
+       }
+
+       karg.dataSgeOffset = (sizeof(SCSIIORequest_t) - sizeof(SGE_IO_UNION))/4;
+
+       /* Construct the Message frame */
+       pMf = &request;
+
+       pMf->TargetID = (u8) pVenReq->ld;                       /* ???? FIXME */
+       pMf->Bus = (u8) pPass->bus;
+       pMf->ChainOffset = 0;
+       pMf->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
+
+       /* May need some tweaking here */
+       opcode = (u8) pPass->cdb[0];
+       if (opcode < 0x20)
+               pMf->CDBLength = 6;
+       else if (opcode < 0x60)
+               pMf->CDBLength = 10;
+       else if ((opcode < 0xC0) && (opcode >= 0xA0))
+               pMf->CDBLength = 12;
+       else
+               pMf->CDBLength = 16;
+
+       pMf->SenseBufferLength = karg.maxSenseBytes;    /* max is 40 */
+       pMf->Reserved = 0;
+       pMf->MsgFlags = 0;                              /* set later */
+       pMf->MsgContext = 0;                            /* set later */
+
+       for (ii = 0; ii < 8; ii++)
+               pMf->LUN[ii] = 0;
+       pMf->LUN[1] = 0;                                /* ???? FIXME */
+
+       /* Tag values set by _do_mpt_command */
+       if (pPass->rw_flag == MPT_COMPAQ_WRITE)
+               pMf->Control = MPI_SCSIIO_CONTROL_WRITE;
+       else
+               pMf->Control = MPI_SCSIIO_CONTROL_READ;
+
+       for (ii = 0; ii < 16; ii++)
+               pMf->CDB[ii] = pPass->cdb[ii];
+
+       pMf->DataLength = pPass->len;
+
+       /* All remaining fields are set by the next function
+        */
+       rc = mptctl_do_mpt_command (karg, (char *)pMf, 1);
+       return rc;
+}
+
+
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,51)
@@ -1110,7 +2923,7 @@ static struct file_operations mptctl_fops = {
        llseek:         no_llseek,
        read:           mptctl_read,
        write:          mptctl_write,
-       ioctl:          mpt_ioctl,
+       ioctl:          mptctl_ioctl,
        open:           mptctl_open,
        release:        mptctl_release,
 };
@@ -1133,18 +2946,15 @@ extern int register_ioctl32_conversion(unsigned int cmd,
                                                      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);
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/* sparc32_XXX functions are used to provide a conversion between
+ * pointers and u32's. If the arg does not contain any pointers, then
+ * a specialized function (sparc32_XXX) is not needed. If the arg
+ * does contain pointer(s), then the specialized function is used
+ * to ensure the structure contents is properly processed by mptctl.
+ */
 static int
 sparc32_mptfwxfer_ioctl(unsigned int fd, unsigned int cmd,
                        unsigned long arg, struct file *filp)
@@ -1156,7 +2966,7 @@ sparc32_mptfwxfer_ioctl(unsigned int fd, unsigned int cmd,
        int nonblock = (filp->f_flags & O_NONBLOCK);
        int ret;
 
-       dprintk((KERN_INFO MYNAM "::sparc32_mptfwxfer_ioctl() called\n"));
+       dctlprintk((KERN_INFO MYNAM "::sparc32_mptfwxfer_ioctl() called\n"));
 
        if (copy_from_user(&kfw32, (char *)arg, sizeof(kfw32)))
                return -EFAULT;
@@ -1177,13 +2987,131 @@ sparc32_mptfwxfer_ioctl(unsigned int fd, unsigned int cmd,
        kfw.fwlen = kfw32.fwlen;
        kfw.bufp = (void *)(unsigned long)kfw32.bufp;
 
-       ret = mpt_ioctl_do_fw_download(kfw.iocnum, kfw.bufp, kfw.fwlen);
+       ret = mptctl_do_fw_download(kfw.iocnum, kfw.bufp, kfw.fwlen);
+
+       up(&mptctl_syscall_sem_ioc[iocp->id]);
+
+       return ret;
+}
+
+static int
+sparc32_mpt_command(unsigned int fd, unsigned int cmd,
+                       unsigned long arg, struct file *filp)
+{
+       struct mpt_ioctl_command32 karg32;
+       struct mpt_ioctl_command32 *uarg = (struct mpt_ioctl_command32 *) arg;
+       struct mpt_ioctl_command karg;
+       MPT_ADAPTER *iocp = NULL;
+       int iocnum, iocnumX;
+       int nonblock = (filp->f_flags & O_NONBLOCK);
+       int ret;
+
+       dctlprintk((KERN_INFO MYNAM "::sparc32_mpt_command() called\n"));
+
+       if (copy_from_user(&karg32, (char *)arg, sizeof(karg32)))
+               return -EFAULT;
+
+       /* Verify intended MPT adapter */
+       iocnumX = karg32.hdr.iocnum & 0xFF;
+       if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) ||
+           (iocp == NULL)) {
+               printk(KERN_ERR MYNAM "::sparc32_mpt_command @%d - ioc%d not found!\n",
+                               __LINE__, iocnumX);
+               return -ENODEV;
+       }
+
+       if ((ret = mptctl_syscall_down(iocp, nonblock)) != 0)
+               return ret;
+
+       /* Copy data to karg */
+       karg.hdr.iocnum = karg32.hdr.iocnum;
+       karg.hdr.port = karg32.hdr.port;
+       karg.timeout = karg32.timeout;
+       karg.maxReplyBytes = karg32.maxReplyBytes;
+
+       karg.dataInSize = karg32.dataInSize;
+       karg.dataOutSize = karg32.dataOutSize;
+       karg.maxSenseBytes = karg32.maxSenseBytes;
+       karg.dataSgeOffset = karg32.dataSgeOffset;
+
+       karg.replyFrameBufPtr = (char *)(unsigned long)karg32.replyFrameBufPtr;
+       karg.dataInBufPtr = (char *)(unsigned long)karg32.dataInBufPtr;
+       karg.dataOutBufPtr = (char *)(unsigned long)karg32.dataOutBufPtr;
+       karg.senseDataPtr = (char *)(unsigned long)karg32.senseDataPtr;
+
+       /* Pass new structure to do_mpt_command
+        */
+       ret = mptctl_do_mpt_command (karg, (char *) &uarg->MF, 0);
 
        up(&mptctl_syscall_sem_ioc[iocp->id]);
 
        return ret;
 }
 
+static int
+sparc32_mptctl_cpq_passthru(unsigned int fd, unsigned int cmd,
+                       unsigned long arg, struct file *filp)
+{
+       VENDOR_IOCTL_REQ32      *uarg = (VENDOR_IOCTL_REQ32 *) arg;
+       VENDOR_IOCTL_REQ32      karg32;
+       VENDOR_IOCTL_REQ        karg;
+       cpqfc_passthru32_t      kpass32;
+       cpqfc_passthru_t        kpass;
+       MPT_ADAPTER             *ioc;
+       int                     nonblock = (filp->f_flags & O_NONBLOCK);
+       int                     iocnum = 0, iocnumX = 0;
+       int                     rc;
+       int                     ii;
+
+       dctlprintk((KERN_INFO MYNAM "::sparc32_mptctl_cpq_passthru() called\n"));
+
+       if (copy_from_user(&karg32, (char *)arg, sizeof(karg32)))
+               return -EFAULT;
+
+       /* Verify intended MPT adapter */
+       iocnumX = karg32.lc & 0xFF;
+       if (((iocnum = mpt_verify_adapter(iocnumX, &ioc)) < 0) ||
+           (ioc == NULL)) {
+               printk(KERN_ERR MYNAM "::sparc32_mpt_command @%d - ioc%d not found!\n",
+                               __LINE__, iocnumX);
+               return -ENODEV;
+       }
+
+       if ((rc = mptctl_syscall_down(ioc, nonblock)) != 0)
+               return rc;
+
+       /* Copy data to karg */
+       karg.ld = karg32.ld;
+       karg.node = karg32.node;
+       karg.lc = karg32.lc;
+       karg.nexus = karg32.nexus;
+       karg.argp = (void *)(unsigned long)karg32.argp;
+
+       /* Read in the second buffer */
+       if (copy_from_user(&kpass32, karg.argp, sizeof(cpqfc_passthru32_t))) {
+               printk(KERN_ERR "%s@%d::sparc32_mptctl_cpq_passthru - "
+                       "Unable to read in cpqfc_passthru_t @ %p\n",
+                               __FILE__, __LINE__, (void*)uarg);
+               return -EFAULT;
+       }
+
+       /* Copy the 32bit buffer to kpass */
+       for (ii = 0; ii < 16; ii++)
+               kpass.cdb[ii] = kpass32.cdb[ii];
+       kpass.bus = kpass32.bus;
+       kpass.pdrive = kpass32.pdrive;
+       kpass.len = kpass32.len;
+       kpass.sense_len = kpass32.sense_len;
+       kpass.bufp = (void *)(unsigned long)kpass32.bufp;
+       kpass.rw_flag = kpass32.rw_flag;
+
+       /* Generate the SCSI IO command and issue */
+       rc = mptctl_compaq_scsiio(&karg, &kpass);
+
+       up(&mptctl_syscall_sem_ioc[ioc->id]);
+       return rc;
+}
+
 #endif         /*} linux >= 2.3.x */
 #endif         /*} sparc */
 
@@ -1193,26 +3121,79 @@ int __init mptctl_init(void)
        int err;
        int i;
        int where = 1;
+       int sz;
+       u8 *mem;
+       MPT_ADAPTER *ioc = NULL;
+       int iocnum;
 
        show_mptmod_ver(my_NAME, my_VERSION);
 
        for (i=0; i<MPT_MAX_ADAPTERS; i++) {
                sema_init(&mptctl_syscall_sem_ioc[i], 1);
+
+               ioc = NULL;
+               if (((iocnum = mpt_verify_adapter(i, &ioc)) < 0) ||
+                   (ioc == NULL)) {
+                       continue;
+               }
+               else {
+                       /* This adapter instance is found.
+                        * Allocate and inite a MPT_IOCTL structure
+                        */
+                       sz = sizeof (MPT_IOCTL);
+                       mem = kmalloc(sz, GFP_KERNEL);
+                       if (mem == NULL) {
+                               err = -ENOMEM;
+                               goto out_fail;
+                       }
+
+                       memset(mem, 0, sz);
+                       ioc->ioctl = (MPT_IOCTL *) mem;
+                       ioc->ioctl->ioc = ioc;
+                       init_timer (&ioc->ioctl->timer);
+                       ioc->ioctl->timer.data = (unsigned long) ioc->ioctl;
+                       ioc->ioctl->timer.function = mptctl_timer_expired;
+                       init_timer (&ioc->ioctl->TMtimer);
+                       ioc->ioctl->TMtimer.data = (unsigned long) ioc->ioctl;
+                       ioc->ioctl->TMtimer.function = mptctl_timer_expired;
+               }
        }
 
 #if defined(__sparc__) && defined(__sparc_v9__)                /*{*/
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)                /*{*/
-       err = register_ioctl32_conversion(MPTRWPERF, NULL);
+       err = register_ioctl32_conversion(MPTIOCINFO, NULL);
+       if (++where && err) goto out_fail;
+       err = register_ioctl32_conversion(MPTTARGETINFO, NULL);
+       if (++where && err) goto out_fail;
+       err = register_ioctl32_conversion(MPTTEST, NULL);
+       if (++where && err) goto out_fail;
+       err = register_ioctl32_conversion(MPTEVENTQUERY, NULL);
+       if (++where && err) goto out_fail;
+       err = register_ioctl32_conversion(MPTEVENTENABLE, NULL);
+       if (++where && err) goto out_fail;
+       err = register_ioctl32_conversion(MPTEVENTREPORT, NULL);
+       if (++where && err) goto out_fail;
+       err = register_ioctl32_conversion(MPTHARDRESET, NULL);
+       if (++where && err) goto out_fail;
+       err = register_ioctl32_conversion(MPTCOMMAND32, sparc32_mpt_command);
+       if (++where && err) goto out_fail;
+       err = register_ioctl32_conversion(MPTFWDOWNLOAD32,
+                                         sparc32_mptfwxfer_ioctl);
        if (++where && err) goto out_fail;
-       err = register_ioctl32_conversion(MPTRWPERF_CHK, NULL);
+       err = register_ioctl32_conversion(CPQFCTS_GETPCIINFO, NULL);
        if (++where && err) goto out_fail;
-       err = register_ioctl32_conversion(MPTRWPERF_RESET, NULL);
+       err = register_ioctl32_conversion(CPQFCTS_CTLR_STATUS, NULL);
        if (++where && err) goto out_fail;
-       err = register_ioctl32_conversion(MPTFWDOWNLOAD32, sparc32_mptfwxfer_ioctl);
+       err = register_ioctl32_conversion(CPQFCTS_GETDRIVER, NULL);
+       if (++where && err) goto out_fail;
+       err = register_ioctl32_conversion(CPQFCTS_SCSI_IOCTL_FC_TARGET_ADDRESS, NULL);
+       if (++where && err) goto out_fail;
+       err = register_ioctl32_conversion(CPQFCTS_SCSI_PASSTHRU32, sparc32_mptctl_cpq_passthru);
        if (++where && err) goto out_fail;
 #endif         /*} linux >= 2.3.x */
 #endif         /*} sparc */
 
+       /* Register this device */
        if (misc_register(&mptctl_miscdev) == -1) {
                printk(KERN_ERR MYNAM ": Can't register misc device [minor=%d].\n", MPT_MINOR);
                err = -EBUSY;
@@ -1226,13 +3207,19 @@ int __init mptctl_init(void)
         *  Install our handler
         */
        ++where;
-       if ((mptctl_id = mpt_register(mptctl_reply, MPTCTL_DRIVER)) <= 0) {
+       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;
        }
 
+       if (mpt_reset_register(mptctl_id, mptctl_ioc_reset) == 0) {
+               dprintk((KERN_INFO MYNAM ": Registered for IOC reset notifications\n"));
+       } else {
+               /* FIXME! */
+       }
+
        return 0;
 
 out_fail:
@@ -1241,35 +3228,72 @@ out_fail:
 #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(MPTIOCINFO);
+       unregister_ioctl32_conversion(MPTTARGETINFO);
+       unregister_ioctl32_conversion(MPTTEST);
+       unregister_ioctl32_conversion(MPTEVENTQUERY);
+       unregister_ioctl32_conversion(MPTEVENTENABLE);
+       unregister_ioctl32_conversion(MPTEVENTREPORT);
+       unregister_ioctl32_conversion(MPTHARDRESET);
+       unregister_ioctl32_conversion(MPTCOMMAND32);
        unregister_ioctl32_conversion(MPTFWDOWNLOAD32);
+       unregister_ioctl32_conversion(CPQFCTS_GETPCIINFO);
+       unregister_ioctl32_conversion(CPQFCTS_GETDRIVER);
+       unregister_ioctl32_conversion(CPQFCTS_CTLR_STATUS);
+       unregister_ioctl32_conversion(CPQFCTS_SCSI_IOCTL_FC_TARGET_ADDRESS);
+       unregister_ioctl32_conversion(CPQFCTS_SCSI_PASSTHRU32);
 #endif         /*} linux >= 2.3.x */
 #endif         /*} sparc */
 
+       for (i=0; i<MPT_MAX_ADAPTERS; i++) {
+               ioc = NULL;
+               if (((iocnum = mpt_verify_adapter(i, &ioc)) < 0) ||
+                   (ioc == NULL)) {
+                       continue;
+               }
+               else {
+                       if (ioc->ioctl) {
+                               kfree ( ioc->ioctl );
+                               ioc->ioctl = NULL;
+                       }
+               }
+       }
        return err;
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 void mptctl_exit(void)
 {
-
-#if defined(__sparc__) && defined(__sparc_v9__)                /*{*/
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)                /*{*/
-       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 */
+       int i;
+       MPT_ADAPTER *ioc;
+       int iocnum;
 
        misc_deregister(&mptctl_miscdev);
-       printk(KERN_INFO MYNAM ": /dev/%s @ (major,minor=%d,%d)\n",
+       printk(KERN_INFO MYNAM ": Deregistered /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");
 
+       /* De-register reset handler from base module */
+       mpt_reset_deregister(mptctl_id);
+       dprintk((KERN_INFO MYNAM ": Deregistered for IOC reset notifications\n"));
+
+       /* De-register callback handler from base module */
        mpt_deregister(mptctl_id);
+       printk(KERN_INFO MYNAM ": Deregistered from Fusion MPT base driver\n");
+
+       /* Free allocated memory */
+       for (i=0; i<MPT_MAX_ADAPTERS; i++) {
+               ioc = NULL;
+               if (((iocnum = mpt_verify_adapter(i, &ioc)) < 0) ||
+                   (ioc == NULL)) {
+                       continue;
+               }
+               else {
+                       if (ioc->ioctl) {
+                               kfree ( ioc->ioctl );
+                               ioc->ioctl = NULL;
+                       }
+               }
+       }
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
diff --git a/drivers/message/fusion/mptctl.h b/drivers/message/fusion/mptctl.h
new file mode 100644 (file)
index 0000000..2a2acc0
--- /dev/null
@@ -0,0 +1,409 @@
+/*
+ *  linux/drivers/message/fusion/mptioctl.h
+ *      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!
+ *
+ *      (see also mptbase.c)
+ *
+ *  Copyright (c) 1999-2002 LSI Logic Corporation
+ *  Originally By: Steven J. Ralston
+ *  (mailto:sjralston1@netscape.net)
+ *  (mailto:Pam.Delaney@lsil.com)
+ *
+ *  $Id: mptctl.h,v 1.10 2002/05/28 15:57:16 pdelaney 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 MPTCTL_H_INCLUDED
+#define MPTCTL_H_INCLUDED
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+#include "linux/version.h"
+
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *
+ */
+#define MPT_MISCDEV_BASENAME            "mptctl"
+#define MPT_MISCDEV_PATHNAME            "/dev/" MPT_MISCDEV_BASENAME
+
+#define MPT_PRODUCT_LENGTH              12
+
+/*
+ *  Generic MPT Control IOCTLs and structures
+ */
+#define MPT_MAGIC_NUMBER       'm'
+
+#define MPTRWPERF              _IOWR(MPT_MAGIC_NUMBER,0,struct mpt_raw_r_w)
+
+#define MPTFWDOWNLOAD          _IOWR(MPT_MAGIC_NUMBER,15,struct mpt_fw_xfer)
+#define MPTCOMMAND             _IOWR(MPT_MAGIC_NUMBER,20,struct mpt_ioctl_command)
+
+#if defined(__KERNEL__) && defined(__sparc__) && defined(__sparc_v9__)         /*{*/
+#define MPTFWDOWNLOAD32                _IOWR(MPT_MAGIC_NUMBER,15,struct mpt_fw_xfer32)
+#define MPTCOMMAND32           _IOWR(MPT_MAGIC_NUMBER,20,struct mpt_ioctl_command32)
+#endif /*}*/
+
+#define MPTIOCINFO             _IOWR(MPT_MAGIC_NUMBER,17,struct mpt_ioctl_iocinfo)
+#define MPTTARGETINFO          _IOWR(MPT_MAGIC_NUMBER,18,struct mpt_ioctl_targetinfo)
+#define MPTTEST                        _IOWR(MPT_MAGIC_NUMBER,19,struct mpt_ioctl_test)
+#define MPTEVENTQUERY          _IOWR(MPT_MAGIC_NUMBER,21,struct mpt_ioctl_eventquery)
+#define MPTEVENTENABLE         _IOWR(MPT_MAGIC_NUMBER,22,struct mpt_ioctl_eventenable)
+#define MPTEVENTREPORT         _IOWR(MPT_MAGIC_NUMBER,23,struct mpt_ioctl_eventreport)
+#define MPTHARDRESET           _IOWR(MPT_MAGIC_NUMBER,24,struct mpt_ioctl_diag_reset)
+#define MPTFWREPLACE           _IOWR(MPT_MAGIC_NUMBER,25,struct mpt_ioctl_replace_fw)
+
+/*
+ * SPARC PLATFORM REMARK:
+ * IOCTL data structures that contain pointers
+ * will have different sizes in the driver and applications
+ * (as the app. will not use 8-byte pointers).
+ * Apps should use MPTFWDOWNLOAD and MPTCOMMAND.
+ * The driver will convert data from
+ * mpt_fw_xfer32 (mpt_ioctl_command32) to mpt_fw_xfer (mpt_ioctl_command)
+ * internally.
+ */
+struct mpt_fw_xfer {
+       unsigned int     iocnum;        /* IOC unit number */
+       unsigned int     fwlen;
+       void            *bufp;          /* Pointer to firmware buffer */
+};
+
+#if defined(__KERNEL__) && defined(__sparc__) && defined(__sparc_v9__)         /*{*/
+struct mpt_fw_xfer32 {
+       unsigned int iocnum;
+       unsigned int fwlen;
+       u32 bufp;
+};
+#endif /*}*/
+
+/*
+ *  IOCTL header structure.
+ *  iocnum - must be defined.
+ *  port - must be defined for all IOCTL commands other than MPTIOCINFO
+ *  maxDataSize - ignored on MPTCOMMAND commands
+ *             - ignored on MPTFWREPLACE commands
+ *             - on query commands, reports the maximum number of bytes to be returned
+ *               to the host driver (count includes the header).
+ *               That is, set to sizeof(struct mpt_ioctl_iocinfo) for fixed sized commands.
+ *               Set to sizeof(struct mpt_ioctl_targetinfo) + datasize for variable
+ *                     sized commands. (MPTTARGETINFO, MPTEVENTREPORT)
+ */
+typedef struct _mpt_ioctl_header {
+       unsigned int     iocnum;        /* IOC unit number */
+       unsigned int     port;          /* IOC port number */
+       int              maxDataSize;   /* Maximum Num. bytes to transfer on read */
+} mpt_ioctl_header;
+
+/*
+ * Issue a diagnostic reset
+ */
+struct mpt_ioctl_diag_reset {
+       mpt_ioctl_header hdr;
+};
+
+
+/*
+ *  PCI bus/device/function information structure.
+ */
+struct mpt_ioctl_pci_info {
+       union {
+               struct {
+                       unsigned long  deviceNumber   :  5;
+                       unsigned long  functionNumber :  3;
+                       unsigned long  busNumber      : 24;
+               } bits;
+               unsigned long  asUlong;
+       } u;
+};
+
+/*
+ *  Adapter Information Page
+ *  Read only.
+ *  Data starts at offset 0xC
+ */
+#define MPT_IOCTL_INTERFACE_FC         (0x01)
+#define MPT_IOCTL_INTERFACE_SCSI       (0x00)
+#define MPT_IOCTL_VERSION_LENGTH       (32)
+
+struct mpt_ioctl_iocinfo {
+       mpt_ioctl_header hdr;
+       int              adapterType;   /* SCSI or FCP */
+       int              port;          /* port number */
+       int              pciId;         /* PCI Id. */
+       int              hwRev;         /* hardware revision */
+       int              subSystemDevice;       /* PCI subsystem Device ID */
+       int              subSystemVendor;       /* PCI subsystem Vendor ID */
+       int              numDevices;            /* number of devices */
+       int              FWVersion;             /* FW Version (integer) */
+       int              BIOSVersion;           /* BIOS Version (integer) */
+       char             driverVersion[MPT_IOCTL_VERSION_LENGTH];       /* Driver Version (string) */
+       char             busChangeEvent;
+       char             hostId;
+       char             rsvd[2];
+       struct mpt_ioctl_pci_info  pciInfo; /* Added Rev 1 */
+};
+
+/*
+ * Device Information Page
+ * Report the number of, and ids of, all targets
+ * on this IOC.  The ids array is a packed structure
+ * of the known targetInfo.
+ * bits 31-24: reserved
+ *      23-16: LUN
+ *      15- 8: Bus Number
+ *       7- 0: Target ID
+ */
+struct mpt_ioctl_targetinfo {
+       mpt_ioctl_header hdr;
+       int              numDevices;    /* Num targets on this ioc */
+       int              targetInfo[1];
+};
+
+
+/*
+ * Event reporting IOCTL's.  These IOCTL's will
+ * use the following defines:
+ */
+struct mpt_ioctl_eventquery {
+       mpt_ioctl_header hdr;
+       unsigned short   eventEntries;
+       unsigned short   reserved;
+       unsigned int     eventTypes;
+};
+
+struct mpt_ioctl_eventenable {
+       mpt_ioctl_header hdr;
+       unsigned int     eventTypes;
+};
+
+#ifndef __KERNEL__
+typedef struct {
+       uint    event;
+       uint    eventContext;
+       uint    data[2];
+} MPT_IOCTL_EVENTS;
+#endif
+
+struct mpt_ioctl_eventreport {
+       mpt_ioctl_header        hdr;
+       MPT_IOCTL_EVENTS        eventData[1];
+};
+
+#define MPT_MAX_NAME   32
+struct mpt_ioctl_test {
+       mpt_ioctl_header hdr;
+       u8               name[MPT_MAX_NAME];
+       int              chip_type;
+       u8               product [MPT_PRODUCT_LENGTH];
+};
+
+/* Replace the FW image cached in host driver memory
+ * newImageSize - image size in bytes
+ * newImage - first byte of the new image
+ */
+typedef struct mpt_ioctl_replace_fw {
+       mpt_ioctl_header hdr;
+       int              newImageSize;
+       u8               newImage[1];
+} mpt_ioctl_replace_fw_t;
+
+/* General MPT Pass through data strucutre
+ *
+ * iocnum
+ * timeout - in seconds, command timeout. If 0, set by driver to
+ *             default value.
+ * replyFrameBufPtr - reply location
+ * dataInBufPtr - destination for read
+ * dataOutBufPtr - data source for write
+ * senseDataPtr - sense data location
+ * maxReplyBytes - maximum number of reply bytes to be sent to app.
+ * dataInSize - num bytes for data transfer in (read)
+ * dataOutSize - num bytes for data transfer out (write)
+ * dataSgeOffset - offset in words from the start of the request message
+ *             to the first SGL
+ * MF[1];
+ *
+ * Remark:  Some config pages have bi-directional transfer,
+ * both a read and a write. The basic structure allows for
+ * a bidirectional set up. Normal messages will have one or
+ * both of these buffers NULL.
+ */
+struct mpt_ioctl_command {
+       mpt_ioctl_header hdr;
+       int             timeout;        /* optional (seconds) */
+       char            *replyFrameBufPtr;
+       char            *dataInBufPtr;
+       char            *dataOutBufPtr;
+       char            *senseDataPtr;
+       int             maxReplyBytes;
+       int             dataInSize;
+       int             dataOutSize;
+       int             maxSenseBytes;
+       int             dataSgeOffset;
+       char            MF[1];
+};
+
+/*
+ * SPARC PLATFORM: See earlier remark.
+ */
+#if defined(__KERNEL__) && defined(__sparc__) && defined(__sparc_v9__)         /*{*/
+struct mpt_ioctl_command32 {
+       mpt_ioctl_header hdr;
+       int     timeout;
+       u32     replyFrameBufPtr;
+       u32     dataInBufPtr;
+       u32     dataOutBufPtr;
+       u32     senseDataPtr;
+       int     maxReplyBytes;
+       int     dataInSize;
+       int     dataOutSize;
+       int     maxSenseBytes;
+       int     dataSgeOffset;
+       char    MF[1];
+};
+#endif /*}*/
+
+
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ /*
+  *    COMPAQ Specific IOCTL Defines and Structures
+  */
+
+#define CPQFCTS_IOC_MAGIC 'Z'
+
+#define CPQFCTS_GETPCIINFO             _IOR(CPQFCTS_IOC_MAGIC, 1, cpqfc_pci_info_struct)
+#define CPQFCTS_GETDRIVER              _IOR(CPQFCTS_IOC_MAGIC, 2, int)
+#define CPQFCTS_CTLR_STATUS            _IOR(CPQFCTS_IOC_MAGIC, 3, struct _cpqfc_ctlr_status)
+#define CPQFCTS_SCSI_IOCTL_FC_TARGET_ADDRESS   _IOR(CPQFCTS_IOC_MAGIC, 4, struct scsi_fctargaddress)
+#define CPQFCTS_SCSI_PASSTHRU          _IOWR(CPQFCTS_IOC_MAGIC, 5, VENDOR_IOCTL_REQ)
+#if defined(__sparc__) && defined(__sparc_v9__)
+#define CPQFCTS_SCSI_PASSTHRU32                _IOWR(CPQFCTS_IOC_MAGIC, 5, VENDOR_IOCTL_REQ32)
+#endif
+
+typedef struct {
+       unsigned short bus;
+       unsigned short bus_type;
+       unsigned short device_fn;
+       u32 board_id;
+       u32 slot_number;
+       unsigned short vendor_id;
+       unsigned short device_id;
+       unsigned short class_code;
+       unsigned short sub_vendor_id;
+       unsigned short sub_device_id;
+       u8 serial_number[81];
+} cpqfc_pci_info_struct;
+
+
+typedef struct scsi_fctargaddress {
+       unsigned int host_port_id;
+       u8 host_wwn[8]; /* WW Network Name */
+} Scsi_FCTargAddress;
+
+typedef struct _cpqfc_ctlr_status {
+       u32 status;
+       u32 offline_reason;
+} cpqfc_ctlr_status;
+
+
+/* Compaq SCSI I/O Passthru structures.
+ */
+#define MPT_COMPAQ_READ                0x26
+#define MPT_COMPAQ_WRITE       0x27
+
+typedef struct {
+       int lc;         /* controller number */
+       int node;       /* node number */
+       int ld;         /* target logical id */
+       u32 nexus;
+       void *argp;
+} VENDOR_IOCTL_REQ;
+
+#if defined(__KERNEL__) && defined(__sparc__) && defined(__sparc_v9__)         /*{*/
+typedef struct {
+       int lc;         /* controller number */
+       int node;       /* node number */
+       int ld;         /* target logical id */
+       u32 nexus;
+       u32 argp;
+} VENDOR_IOCTL_REQ32;
+#endif
+
+typedef struct {
+       char cdb[16];           /* cdb */
+       unsigned short bus;     /* bus number */
+       unsigned short pdrive;  /* physical drive */
+       int len;                /* data area size */
+       int sense_len;          /* sense size */
+       char sense_data[40];    /* sense buffer */
+       void *bufp;             /* data buffer pointer */
+       char rw_flag;
+} cpqfc_passthru_t;
+
+#if defined(__KERNEL__) && defined(__sparc__) && defined(__sparc_v9__)         /*{*/
+typedef struct {
+       char cdb[16];           /* cdb */
+       unsigned short bus;     /* bus number */
+       unsigned short pdrive;  /* physical drive */
+       int len;                /* data area size */
+       int sense_len;          /* sense size */
+       char sense_data[40];    /* sense buffer */
+       u32 bufp;               /* data buffer pointer */
+       char rw_flag;
+} cpqfc_passthru32_t;
+#endif
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+#endif
+
index c0831d6a3b1f54cbffaffac1a97183cd3169f60b..f4484ed7ef375bb6b927cf51d68a0f9aa9cd5f6a 100644 (file)
  *
  *      (see also mptbase.c)
  *
- *  Copyright (c) 2000-2001 LSI Logic Corporation
+ *  Copyright (c) 2000-2002 LSI Logic Corporation
  *  Originally By: Noah Romer
  *
- *  $Id: mptlan.c,v 1.32.2.2 2001/07/12 19:43:33 nromer Exp $
+ *  $Id: mptlan.c,v 1.52 2002/05/06 13:45:07 sshirron Exp $
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -79,6 +79,8 @@
 
 #define MYNAM          "mptlan"
 
+MODULE_LICENSE("GPL");
+
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
  * MPT LAN message sizes without variable part.
@@ -109,8 +111,8 @@ 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 */
+       atomic_t buckets_out;           /* number of unused buckets on IOC */
+       int bucketthresh;               /* Send more when this many left */
 
        int *mpt_txfidx; /* Free Tx Context list */
        int mpt_txfidx_tail;
@@ -123,8 +125,8 @@ struct mpt_lan_priv {
        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 */
+       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;
@@ -152,7 +154,8 @@ 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 void mpt_lan_wake_post_buckets_task(struct net_device *dev, 
+                                          int priority);
 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);
@@ -175,8 +178,10 @@ static u32 tx_max_out_p = 127 - 16;
 
 static struct net_device *mpt_landev[MPT_MAX_ADAPTERS+1];
 
+#ifdef QLOGIC_NAA_WORKAROUND
 static struct NAA_Hosed *mpt_bad_naa = NULL;
 rwlock_t bad_naa_lock;
+#endif
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -229,7 +234,7 @@ lan_reply (MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply)
                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,
@@ -333,7 +338,7 @@ mpt_lan_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
        struct net_device *dev = mpt_landev[ioc->id];
        struct mpt_lan_priv *priv = (struct mpt_lan_priv *) dev->priv;
 
-       dprintk((KERN_INFO MYNAM ": IOC %s_reset routed to LAN driver!\n",
+       dlprintk((KERN_INFO MYNAM ": IOC %s_reset routed to LAN driver!\n",
                        reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post"));
 
        if (priv->mpt_rxfidx == NULL)
@@ -342,9 +347,11 @@ mpt_lan_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
        if (reset_phase == MPT_IOC_PRE_RESET) {
                int i;
                unsigned long flags;
-               
+
                netif_stop_queue(dev);
 
+               dlprintk ((KERN_INFO "mptlan/ioc_reset: called netif_stop_queue for %s.\n", dev->name));
+
                atomic_set(&priv->buckets_out, 0);
 
                /* Reset Rx Free Tail index and re-populate the queue. */
@@ -365,7 +372,7 @@ mpt_lan_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
 static int
 mpt_lan_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
 {
-       dprintk((KERN_INFO MYNAM ": MPT event routed to LAN driver!\n"));
+       dlprintk((KERN_INFO MYNAM ": MPT event routed to LAN driver!\n"));
 
        switch (le32_to_cpu(pEvReply->Event)) {
        case MPI_EVENT_NONE:                            /* 00 */
@@ -403,9 +410,9 @@ mpt_lan_open(struct net_device *dev)
 
        if (mpt_lan_reset(dev) != 0) {
                MPT_ADAPTER *mpt_dev = priv->mpt_dev;
-               
+
                printk (KERN_WARNING MYNAM "/lan_open: lan_reset failed.");
-               
+
                if (mpt_dev->active)
                        printk ("The ioc is active. Perhaps it needs to be"
                                " reset?\n");
@@ -429,7 +436,7 @@ mpt_lan_open(struct net_device *dev)
                priv->mpt_txfidx[++priv->mpt_txfidx_tail] = i;
        }
 
-       dprintk((KERN_INFO MYNAM "@lo: Finished initializing SendCtl\n"));
+       dlprintk((KERN_INFO MYNAM "@lo: Finished initializing SendCtl\n"));
 
        priv->mpt_rxfidx = kmalloc(priv->max_buckets_out * sizeof(int),
                                   GFP_KERNEL);
@@ -447,12 +454,12 @@ mpt_lan_open(struct net_device *dev)
                priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = i;
        }
 
-/**/   dprintk((KERN_INFO MYNAM "/lo: txfidx contains - "));
+/**/   dlprintk((KERN_INFO MYNAM "/lo: txfidx contains - "));
 /**/   for (i = 0; i < priv->tx_max_out; i++)
-/**/           dprintk((" %xh", priv->mpt_txfidx[i]));
-/**/   dprintk(("\n"));
+/**/           dlprintk((" %xh", priv->mpt_txfidx[i]));
+/**/   dlprintk(("\n"));
 
-       dprintk((KERN_INFO MYNAM "/lo: Finished initializing RcvCtl\n"));
+       dlprintk((KERN_INFO MYNAM "/lo: Finished initializing RcvCtl\n"));
 
        mpt_lan_post_receive_buckets(dev);
        printk(KERN_INFO MYNAM ": %s/%s: interface up & active\n",
@@ -466,7 +473,7 @@ mpt_lan_open(struct net_device *dev)
        }
 
        netif_start_queue(dev);
-       dprintk((KERN_INFO MYNAM "/lo: Done.\n"));
+       dlprintk((KERN_INFO MYNAM "/lo: Done.\n"));
 
        return 0;
 out_mpt_rxfidx:
@@ -494,7 +501,7 @@ mpt_lan_reset(struct net_device *dev)
        mf = mpt_get_msg_frame(LanCtx, priv->mpt_dev->id);
 
        if (mf == NULL) {
-/*             dprintk((KERN_ERR MYNAM "/reset: Evil funkiness abounds! "
+/*             dlprintk((KERN_ERR MYNAM "/reset: Evil funkiness abounds! "
                "Unable to allocate a request frame.\n"));
 */
                return -1;
@@ -523,11 +530,11 @@ mpt_lan_close(struct net_device *dev)
        unsigned int timeout;
        int i;
 
-       dprintk((KERN_INFO MYNAM ": mpt_lan_close called\n"));
+       dlprintk((KERN_INFO MYNAM ": mpt_lan_close called\n"));
 
        mpt_event_deregister(LanCtx);
 
-       dprintk((KERN_INFO MYNAM ":lan_close: Posted %d buckets "
+       dlprintk((KERN_INFO MYNAM ":lan_close: Posted %d buckets "
                  "since driver was loaded, %d still out\n",
                  priv->total_posted,atomic_read(&priv->buckets_out)));
 
@@ -537,18 +544,18 @@ mpt_lan_close(struct net_device *dev)
 
        timeout = 2 * HZ;
        while (atomic_read(&priv->buckets_out) && --timeout) {
-               current->state = TASK_INTERRUPTIBLE;
+               set_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 "
+/**/                   dlprintk((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,
+                                        priv->RcvCtl[i].len,
                                         PCI_DMA_FROMDEVICE);
-                       dev_kfree_skb(priv->RcvCtl[i].skb);
+                       dev_kfree_skb(priv->RcvCtl[i].skb);
                }
        }
 
@@ -556,11 +563,11 @@ mpt_lan_close(struct net_device *dev)
        kfree (priv->mpt_rxfidx);
 
        for (i = 0; i < priv->tx_max_out; i++) {
-               if (priv->SendCtl[i].skb != NULL) {
+               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);
+                       dev_kfree_skb(priv->SendCtl[i].skb);
                }
        }
 
@@ -599,7 +606,13 @@ mpt_lan_change_mtu(struct net_device *dev, int new_mtu)
 static void
 mpt_lan_tx_timeout(struct net_device *dev)
 {
-       netif_wake_queue(dev);  
+       struct mpt_lan_priv *priv = (struct mpt_lan_priv *) dev->priv;
+       MPT_ADAPTER *mpt_dev = priv->mpt_dev;
+
+       if (mpt_dev->active) {
+               dlprintk (("mptlan/tx_timeout: calling netif_wake_queue for %s.\n", dev->name));
+               netif_wake_queue(dev);
+       }
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -656,7 +669,7 @@ mpt_lan_send_reply(struct net_device *dev, LANSendReply_t *pSendRep)
 
        /* Add check for Loginfo Flag in IOCStatus */
 
-       switch (le16_to_cpu(pSendRep->IOCStatus)) {
+       switch (le16_to_cpu(pSendRep->IOCStatus) & MPI_IOCSTATUS_MASK) {
        case MPI_IOCSTATUS_SUCCESS:
                priv->stats.tx_packets += count;
                break;
@@ -722,7 +735,6 @@ mpt_lan_sdu_send (struct sk_buff *skb, struct net_device *dev)
        dma_addr_t dma;
        unsigned long flags;
        int ctx;
-       struct NAA_Hosed *nh;
        u16 cur_naa = 0x1000;
 
        dioprintk((KERN_INFO MYNAM ": %s called, skb_addr = %p\n",
@@ -741,7 +753,6 @@ mpt_lan_sdu_send (struct sk_buff *skb, struct net_device *dev)
        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",
@@ -791,6 +802,10 @@ mpt_lan_sdu_send (struct sk_buff *skb, struct net_device *dev)
 //                     IOC_AND_NETDEV_NAMES_s_s(dev),
 //                     ctx, skb, skb->data));
 
+#ifdef QLOGIC_NAA_WORKAROUND
+{
+       struct NAA_Hosed *nh;
+
        /* Munge the NAA for Tx packets to QLogic boards, which don't follow
           RFC 2625. The longer I look at this, the more my opinion of Qlogic
           drops. */
@@ -803,12 +818,14 @@ mpt_lan_sdu_send (struct sk_buff *skb, struct net_device *dev)
                    (nh->ieee[4] == skb->mac.raw[4]) &&
                    (nh->ieee[5] == skb->mac.raw[5])) {
                        cur_naa = nh->NAA;
-                       dprintk ((KERN_INFO "mptlan/sdu_send: using NAA value "
+                       dlprintk ((KERN_INFO "mptlan/sdu_send: using NAA value "
                                  "= %04x.\n", cur_naa));
                        break;
                }
        }
        read_unlock_irq(&bad_naa_lock);
+}
+#endif
 
        pTrans->TransactionDetails[0] = cpu_to_le32((cur_naa         << 16) |
                                                    (skb->mac.raw[0] <<  8) |
@@ -821,10 +838,10 @@ mpt_lan_sdu_send (struct sk_buff *skb, struct net_device *dev)
        pSimple = (SGESimple64_t *) &pTrans->TransactionDetails[2];
 
        /* If we ever decide to send more than one Simple SGE per LANSend, then
-          we will need to make sure that LAST_ELEMENT only gets set on the 
+          we will need to make sure that LAST_ELEMENT only gets set on the
           last one. Otherwise, bad voodoo and evil funkiness will commence. */
        pSimple->FlagsLength = cpu_to_le32(
-                       ((MPI_SGE_FLAGS_LAST_ELEMENT | 
+                       ((MPI_SGE_FLAGS_LAST_ELEMENT |
                          MPI_SGE_FLAGS_END_OF_BUFFER |
                          MPI_SGE_FLAGS_SIMPLE_ELEMENT |
                          MPI_SGE_FLAGS_SYSTEM_ADDRESS |
@@ -842,23 +859,32 @@ mpt_lan_sdu_send (struct sk_buff *skb, struct net_device *dev)
        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)));
+                       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)
+mpt_lan_wake_post_buckets_task(struct net_device *dev, int priority)
+/* 
+ * @priority: 0 = put it on the timer queue, 1 = put it on the immediate queue
+ */
 {
        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) ));
+               if (priority) {
+                       queue_task(&priv->post_buckets_task, &tq_immediate);
+                       mark_bh(IMMEDIATE_BH);
+               } else {
+                       queue_task(&priv->post_buckets_task, &tq_timer);
+                       dioprintk((KERN_INFO MYNAM ": post_buckets queued on "
+                                  "timer.\n"));
+               }
+               dioprintk((KERN_INFO MYNAM ": %s/%s: Queued post_buckets task.\n",
+                          IOC_AND_NETDEV_NAMES_s_s(dev) ));
        }
 }
 
@@ -870,7 +896,7 @@ mpt_lan_receive_skb(struct net_device *dev, struct sk_buff *skb)
 
        skb->protocol = mpt_lan_type_trans(skb, dev);
 
-       dioprintk((KERN_INFO MYNAM ": %s/%s: Incoming packet (%d bytes) " 
+       dioprintk((KERN_INFO MYNAM ": %s/%s: Incoming packet (%d bytes) "
                 "delivered to upper level.\n",
                        IOC_AND_NETDEV_NAMES_s_s(dev), skb->len));
 
@@ -884,7 +910,7 @@ mpt_lan_receive_skb(struct net_device *dev, struct sk_buff *skb)
                 atomic_read(&priv->buckets_out)));
 
        if (atomic_read(&priv->buckets_out) < priv->bucketthresh)
-               mpt_lan_wake_post_buckets_task(dev);
+               mpt_lan_wake_post_buckets_task(dev, 1);
 
        dioprintk((KERN_INFO MYNAM "/receive_post_reply: %d buckets "
                  "remaining, %d received back since sod\n",
@@ -956,12 +982,12 @@ mpt_lan_receive_post_free(struct net_device *dev,
        unsigned long flags;
        struct sk_buff *skb;
        u32 ctx;
-       u8 count;
+       int count;
        int i;
 
        count = pRecvRep->NumberOfContexts;
 
-/**/   dprintk((KERN_INFO MYNAM "/receive_post_reply: "
+/**/   dlprintk((KERN_INFO MYNAM "/receive_post_reply: "
                  "IOC returned %d buckets, freeing them...\n", count));
 
        spin_lock_irqsave(&priv->rxfidx_lock, flags);
@@ -970,11 +996,11 @@ mpt_lan_receive_post_free(struct net_device *dev,
 
                skb = priv->RcvCtl[ctx].skb;
 
-//             dprintk((KERN_INFO MYNAM ": %s: dev_name = %s\n",
+//             dlprintk((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"));
+//             dlprintk((KERN_INFO MYNAM "@rpr[2], priv = %p, buckets_out addr = %p",
+//                             priv, &(priv->buckets_out)));
+//             dlprintk((KERN_INFO MYNAM "@rpr[2] TC + 3\n"));
 
                priv->RcvCtl[ctx].skb = NULL;
                pci_unmap_single(mpt_dev->pcidev, priv->RcvCtl[ctx].dma,
@@ -989,13 +1015,13 @@ mpt_lan_receive_post_free(struct net_device *dev,
 
 //     for (i = 0; i < priv->max_buckets_out; i++)
 //             if (priv->RcvCtl[i].skb != NULL)
-//                     dprintk((KERN_INFO MYNAM "@rpr: bucket %03x "
+//                     dlprintk((KERN_INFO MYNAM "@rpr: bucket %03x "
 //                               "is still out\n", i));
 
-/*     dprintk((KERN_INFO MYNAM "/receive_post_reply: freed %d buckets\n",
+/*     dlprintk((KERN_INFO MYNAM "/receive_post_reply: freed %d buckets\n",
                  count));
 */
-/**/   dprintk((KERN_INFO MYNAM "@receive_post_reply: %d buckets "
+/**/   dlprintk((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;
@@ -1010,16 +1036,17 @@ mpt_lan_receive_post_reply(struct net_device *dev,
        MPT_ADAPTER *mpt_dev = priv->mpt_dev;
        struct sk_buff *skb, *old_skb;
        unsigned long flags;
-       u32 len, ctx;
-       u32 offset;
-       u8 count;
+       u32 len, ctx, offset;
+       u32 remaining = le32_to_cpu(pRecvRep->BucketsRemaining);
+       int 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)
+       if ((le16_to_cpu(pRecvRep->IOCStatus) & MPI_IOCSTATUS_MASK) ==
+                                               MPI_IOCSTATUS_LAN_CANCELED)
                return mpt_lan_receive_post_free(dev, pRecvRep);
 
        len = le32_to_cpu(pRecvRep->PacketLength);
@@ -1059,7 +1086,7 @@ mpt_lan_receive_post_reply(struct net_device *dev,
                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__);
+                                       __FILE__, __LINE__);
                        return -ENOMEM;
                }
 
@@ -1096,7 +1123,7 @@ mpt_lan_receive_post_reply(struct net_device *dev,
                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__);
+                                       __FILE__, __LINE__);
                        return -ENOMEM;
                }
 
@@ -1140,25 +1167,32 @@ mpt_lan_receive_post_reply(struct net_device *dev,
                                "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));
+       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 if (remaining < 10)
+               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));
+       
+       if ((remaining < priv->bucketthresh) &&
+           ((atomic_read(&priv->buckets_out) - remaining) > 
+            MPT_LAN_BUCKETS_REMAIN_MISMATCH_THRESH)) {
+               
+               printk (KERN_WARNING MYNAM " Mismatch between driver's "
+                       "buckets_out count and fw's BucketsRemaining "
+                       "count has crossed the threshold, issuing a "
+                       "LanReset to clear the fw's hashtable. You may "
+                       "want to check your /var/log/messages for \"CRC "
+                       "error\" event notifications.\n");
+               
+               mpt_lan_reset(dev);
+               mpt_lan_wake_post_buckets_task(dev, 0);
        }
-#endif
-
+       
        return mpt_lan_receive_skb(dev, skb);
 }
 
@@ -1242,15 +1276,15 @@ mpt_lan_post_receive_buckets(void *dev_id)
                        if (skb == NULL) {
                                skb = dev_alloc_skb(len);
                                if (skb == NULL) {
-/**/                                   printk (KERN_WARNING
-/**/                                           MYNAM "/%s: Can't alloc skb\n",
-/**/                                           __FUNCTION__);
+                                       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,
+                               dma = pci_map_single(mpt_dev->pcidev, skb->data,
                                                     len, PCI_DMA_FROMDEVICE);
 
                                priv->RcvCtl[ctx].skb = skb;
@@ -1308,7 +1342,7 @@ 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)); 
+       __FUNCTION__, priv->total_posted, priv->total_received));
 
        clear_bit(0, &priv->post_buckets_active);
 }
@@ -1336,7 +1370,7 @@ mpt_register_lan_device (MPT_ADAPTER *mpt_dev, int pnum)
        priv->post_buckets_task.data = dev;
        priv->post_buckets_active = 0;
 
-       dprintk((KERN_INFO MYNAM "@%d: bucketlen = %d\n",
+       dlprintk((KERN_INFO MYNAM "@%d: bucketlen = %d\n",
                        __LINE__, dev->mtu + dev->hard_header_len + 4));
 
        atomic_set(&priv->buckets_out, 0);
@@ -1346,7 +1380,7 @@ mpt_register_lan_device (MPT_ADAPTER *mpt_dev, int pnum)
        if (mpt_dev->pfacts[0].MaxLanBuckets < max_buckets_out)
                priv->max_buckets_out = mpt_dev->pfacts[0].MaxLanBuckets;
 
-       dprintk((KERN_INFO MYNAM "@%d: MaxLanBuckets=%d, max_buckets_out/priv=%d/%d\n",
+       dlprintk((KERN_INFO MYNAM "@%d: MaxLanBuckets=%d, max_buckets_out/priv=%d/%d\n",
                        __LINE__,
                        mpt_dev->pfacts[0].MaxLanBuckets,
                        max_buckets_out,
@@ -1389,7 +1423,7 @@ mpt_register_lan_device (MPT_ADAPTER *mpt_dev, int pnum)
        dev->tx_timeout = mpt_lan_tx_timeout;
        dev->watchdog_timeo = MPT_LAN_TX_TIMEOUT;
 
-       dprintk((KERN_INFO MYNAM ": Finished registering dev "
+       dlprintk((KERN_INFO MYNAM ": Finished registering dev "
                "and setting initial values\n"));
 
        SET_MODULE_OWNER(dev);
@@ -1403,13 +1437,15 @@ mpt_lan_init (void)
 {
        struct net_device *dev;
        MPT_ADAPTER *curadapter;
-       int i = 0, j;
+       int i, j;
 
        show_mptmod_ver(LANAME, LANVER);
 
-       /* Init the global r/w lock for the bad_naa list. We want to do this 
+#ifdef QLOGIC_NAA_WORKAROUND
+       /* Init the global r/w lock for the bad_naa list. We want to do this
           before any boards are initialized and may be used. */
        rwlock_init(&bad_naa_lock);
+#endif
 
        if ((LanCtx = mpt_register(lan_reply, MPTLAN_DRIVER)) <= 0) {
                printk (KERN_ERR MYNAM ": Failed to register with MPT base driver\n");
@@ -1419,10 +1455,10 @@ mpt_lan_init (void)
        /* 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));
+       dlprintk((KERN_INFO MYNAM ": assigned context of %d\n", LanCtx));
 
        if (mpt_reset_register(LanCtx, mpt_lan_ioc_reset) == 0) {
-               dprintk((KERN_INFO MYNAM ": Registered for IOC reset notifications\n"));
+               dlprintk((KERN_INFO MYNAM ": Registered for IOC reset notifications\n"));
        } else {
                printk(KERN_ERR MYNAM ": Eieee! unable to register a reset "
                       "handler with mptbase! The world is at an end! "
@@ -1433,7 +1469,6 @@ mpt_lan_init (void)
        for (j = 0; j < MPT_MAX_ADAPTERS; j++) {
                mpt_landev[j] = NULL;
        }
-       j = 0;
 
        curadapter = mpt_adapter_find_first();
        while (curadapter != NULL) {
@@ -1457,11 +1492,11 @@ mpt_lan_init (void)
 //                                     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);
+                                       j = curadapter->id;
                                        mpt_landev[j] = dev;
-                                       dprintk((KERN_INFO MYNAM "/init: dev_addr=%p, mpt_landev[%d]=%p\n",
+                                       dlprintk((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,
@@ -1508,18 +1543,15 @@ void __init mpt_lan_exit(void)
 MODULE_PARM(tx_max_out_p, "i");
 MODULE_PARM(max_buckets_out, "i"); // Debug stuff. FIXME!
 
-MODULE_LICENSE("GPL");
-
 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) 
+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;
-       u16 source_naa = fch->stype, found = 0;
 
        skb->mac.raw = skb->data;
        skb_pull(skb, sizeof(struct mpt_lan_ohdr));
@@ -1535,7 +1567,7 @@ mpt_lan_type_trans(struct sk_buff *skb, struct net_device *dev)
                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[0], fch->saddr[1], fch->saddr[2],
                                fch->saddr[3], fch->saddr[4], fch->saddr[5]);
        }
 
@@ -1555,6 +1587,10 @@ mpt_lan_type_trans(struct sk_buff *skb, struct net_device *dev)
 
        fcllc = (struct fcllc *)skb->data;
 
+#ifdef QLOGIC_NAA_WORKAROUND
+{
+       u16 source_naa = fch->stype, found = 0;
+
        /* Workaround for QLogic not following RFC 2625 in regards to the NAA
           value. */
 
@@ -1562,15 +1598,15 @@ mpt_lan_type_trans(struct sk_buff *skb, struct net_device *dev)
                source_naa = swab16(source_naa);
 
        if (fcllc->ethertype == htons(ETH_P_ARP))
-           dprintk ((KERN_INFO "mptlan/type_trans: got arp req/rep w/ naa of "
+           dlprintk ((KERN_INFO "mptlan/type_trans: got arp req/rep w/ naa of "
                      "%04x.\n", source_naa));
 
-       if ((fcllc->ethertype == htons(ETH_P_ARP)) && 
+       if ((fcllc->ethertype == htons(ETH_P_ARP)) &&
           ((source_naa >> 12) !=  MPT_LAN_NAA_RFC2625)){
                struct NAA_Hosed *nh, *prevnh;
                int i;
 
-               dprintk ((KERN_INFO "mptlan/type_trans: ARP Req/Rep from "
+               dlprintk ((KERN_INFO "mptlan/type_trans: ARP Req/Rep from "
                          "system with non-RFC 2625 NAA value (%04x).\n",
                          source_naa));
 
@@ -1584,17 +1620,17 @@ mpt_lan_type_trans(struct sk_buff *skb, struct net_device *dev)
                            (nh->ieee[4] == fch->saddr[4]) &&
                            (nh->ieee[5] == fch->saddr[5])) {
                                found = 1;
-                               dprintk ((KERN_INFO "mptlan/type_trans: ARP Re"
+                               dlprintk ((KERN_INFO "mptlan/type_trans: ARP Re"
                                         "q/Rep w/ bad NAA from system already"
                                         " in DB.\n"));
                                break;
                        }
                }
-               
+
                if ((!found) && (nh == NULL)) {
 
                        nh = kmalloc(sizeof(struct NAA_Hosed), GFP_KERNEL);
-                       dprintk ((KERN_INFO "mptlan/type_trans: ARP Req/Rep w/"
+                       dlprintk ((KERN_INFO "mptlan/type_trans: ARP Req/Rep w/"
                                 " bad NAA from system not yet in DB.\n"));
 
                        if (nh != NULL) {
@@ -1603,11 +1639,11 @@ mpt_lan_type_trans(struct sk_buff *skb, struct net_device *dev)
                                        mpt_bad_naa = nh;
                                if (prevnh)
                                        prevnh->next = nh;
-                               
+
                                nh->NAA = source_naa; /* Set the S_NAA value. */
                                for (i = 0; i < FC_ALEN; i++)
                                        nh->ieee[i] = fch->saddr[i];
-                               dprintk ((KERN_INFO "Got ARP from %02x:%02x:%02x:%02x:"
+                               dlprintk ((KERN_INFO "Got ARP from %02x:%02x:%02x:%02x:"
                                          "%02x:%02x with non-compliant S_NAA value.\n",
                                          fch->saddr[0], fch->saddr[1], fch->saddr[2],
                                          fch->saddr[3], fch->saddr[4],fch->saddr[5]));
@@ -1622,9 +1658,10 @@ mpt_lan_type_trans(struct sk_buff *skb, struct net_device *dev)
                }
                write_unlock_irq(&bad_naa_lock);
        }
-               
+}
+#endif
 
-       /* Strip the SNAP header from ARP packets since we don't 
+       /* Strip the SNAP header from ARP packets since we don't
         * pass them through to the 802.2/SNAP layers.
         */
        if (fcllc->dsap == EXTENDED_SAP &&
index 10f2976dff64b5eb86461842bcd00c2b7bda84b8..0edc8d5be977586089c93602c4b390b02098ef13 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/miscdevice.h>
 #include <linux/spinlock.h>
 #include <linux/tqueue.h>
+#include <linux/delay.h>
 // #include <linux/trdevice.h>
 
 #include <asm/uaccess.h>
@@ -43,13 +44,15 @@ MODULE_DESCRIPTION(LANAME);
 
 #define MPT_LAN_MAX_BUCKETS_OUT 256
 #define MPT_LAN_BUCKET_THRESH  18 /* 9 buckets in one message */
+#define MPT_LAN_BUCKETS_REMAIN_MISMATCH_THRESH 10
 #define MPT_LAN_RX_COPYBREAK   200
-#define MPT_LAN_TX_TIMEOUT     (1*HZ)
+#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 */
+#define MPT_LAN_MTU             13312          /* Max perf range + lower mem
+                                                  usage than 16128 */
 
 #define MPT_LAN_NAA_RFC2625     0x1
 #define MPT_LAN_NAA_QLOGIC      0x2
@@ -66,6 +69,12 @@ MODULE_DESCRIPTION(LANAME);
 #define dioprintk(x)
 #endif
 
+#ifdef MPT_LAN_DEBUG
+#define dlprintk(x)  printk x
+#else
+#define dlprintk(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
index 1a97a4284512c493cfb8b2552fc6d6f2d11cd422..8d03a096d507251e2b1bf4feaecb3a937d9451d6 100644 (file)
@@ -9,17 +9,24 @@
  *      This driver would not exist if not for Alan Cox's development
  *      of the linux i2o driver.
  *
+ *      A special thanks to Pamela Delaney (LSI Logic) for tons of work
+ *      and countless enhancements while adding support for the 1030
+ *      chip family.  Pam has been instrumental in the development of
+ *      of the 2.xx.xx series fusion drivers, and her contributions are
+ *      far too numerous to hope to list in one place.
+ *
  *      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
+ *  Copyright (c) 1999-2002 LSI Logic Corporation
  *  Original author: Steven J. Ralston
- *  (mailto:Steve.Ralston@lsil.com)
+ *  (mailto:sjralston1@netscape.net)
+ *  (mailto:Pam.Delaney@lsil.com)
  *
- *  $Id: mptscsih.c,v 1.29.4.1 2001/09/18 03:22:30 sralston Exp $
+ *  $Id: mptscsih.c,v 1.95 2002/06/20 13:28:17 pdelaney Exp $
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
 #include <linux/errno.h>
 #include <linux/kdev_t.h>
 #include <linux/blkdev.h>
-#include <linux/blk.h>
+#include <linux/blk.h>         /* for io_request_lock (spinlock) decl */
+#include <linux/delay.h>       /* for mdelay */
+#include <linux/interrupt.h>   /* needed for in_interrupt() proto */
+#include <linux/reboot.h>      /* notifier code */
 #include "../../scsi/scsi.h"
 #include "../../scsi/hosts.h"
 #include "../../scsi/sd.h"
@@ -83,52 +93,135 @@ MODULE_AUTHOR(MODULEAUTHOR);
 MODULE_DESCRIPTION(my_NAME);
 MODULE_LICENSE("GPL");
 
+/* Set string for command line args from insmod */
+#ifdef MODULE
+char *mptscsih = 0;
+MODULE_PARM(mptscsih, "s");
+#endif
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 
 typedef struct _BIG_SENSE_BUF {
-       u8              data[256];
+       u8              data[MPT_SENSE_BUFFER_ALLOC];
 } 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;
-} 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;
+#define MPT_SCANDV_GOOD                        (0x00000000) /* must be 0 */
+#define MPT_SCANDV_DID_RESET           (0x00000001)
+#define MPT_SCANDV_SENSE               (0x00000002)
+#define MPT_SCANDV_SOME_ERROR          (0x00000004)
+#define MPT_SCANDV_SELECTION_TIMEOUT   (0x00000008)
+
+#define MPT_SCANDV_MAX_RETRIES         (10)
+
+#define MPT_ICFLAG_BUF_CAP     0x01    /* ReadBuffer Read Capacity format */
+#define MPT_ICFLAG_ECHO                0x02    /* ReadBuffer Echo buffer format */
+#define MPT_ICFLAG_PHYS_DISK   0x04    /* Any SCSI IO but do Phys Disk Format */
+#define MPT_ICFLAG_TAGGED_CMD  0x08    /* Do tagged IO */
+#define MPT_ICFLAG_DID_RESET   0x20    /* Bus Reset occured with this command */
+#define MPT_ICFLAG_RESERVED    0x40    /* Reserved has been issued */
+
+typedef struct _internal_cmd {
+       char            *data;          /* data pointer */
+       dma_addr_t      data_dma;       /* data dma address */
+       int             size;           /* transfer size */
+       u8              cmd;            /* SCSI Op Code */
+       u8              bus;            /* bus number */
+       u8              id;             /* SCSI ID (virtual) */
+       u8              lun;
+       u8              flags;          /* Bit Field - See above */
+       u8              physDiskNum;    /* Phys disk number, -1 else */
+       u8              rsvd2;
+       u8              rsvd;
+} INTERNAL_CMD;
+
+typedef struct _negoparms {
+       u8 width;
+       u8 offset;
+       u8 factor;
+       u8 flags;
+} NEGOPARMS;
+
+typedef struct _dv_parameters {
+       NEGOPARMS        max;
+       NEGOPARMS        now;
+       u8               cmd;
+       u8               id;
+       u16              pad1;
+} DVPARAMETERS;
+
 
 /*
  *  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 int     mptscsih_AddSGE(MPT_SCSI_HOST *hd, Scsi_Cmnd *SCpnt,
+                                SCSIIORequest_t *pReq, int req_idx);
+static int     mptscsih_getFreeChainBuffer(MPT_SCSI_HOST *hd, int *retIndex);
+static void    mptscsih_freeChainBuffers(MPT_SCSI_HOST *hd, int req_idx);
+static int     mptscsih_initChainBuffers (MPT_SCSI_HOST *hd, int init);
+
 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);
+#ifndef MPT_SCSI_USE_NEW_EH
+static void    search_taskQ_for_cmd(Scsi_Cmnd *sc, MPT_SCSI_HOST *hd);
+#else
+static int     mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd);
+#endif
+static u32     SCPNT_TO_LOOKUP_IDX(Scsi_Cmnd *sc);
+static MPT_FRAME_HDR *mptscsih_search_pendingQ(MPT_SCSI_HOST *hd, int scpnt_idx);
+static void    post_pendingQ_commands(MPT_SCSI_HOST *hd);
+
+static int     mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 target, u8 lun, int ctx2abort, int sleepFlag);
+static int     mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 target, u8 lun, int ctx2abort, int sleepFlag);
 
 static int     mptscsih_ioc_reset(MPT_ADAPTER *ioc, int post_reset);
 static int     mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply);
 
+static VirtDevice      *mptscsih_initTarget(MPT_SCSI_HOST *hd, int bus_id, int target_id, u8 lun, char *data, int dlen);
+void           mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtDevice *target, char byte56);
+static void    clear_sense_flag(MPT_SCSI_HOST *hd, SCSIIORequest_t *pReq);
+static void    mptscsih_set_dvflags(MPT_SCSI_HOST *hd, SCSIIORequest_t *pReq, char *data);
+static void    mptscsih_setDevicePage1Flags (u8 width, u8 factor, u8 offset, int *requestedPtr, int *configurationPtr, u8 flags);
+static void    mptscsih_no_negotiate(MPT_SCSI_HOST *hd, int target_id);
+static int     mptscsih_writeSDP1(MPT_SCSI_HOST *hd, int portnum, int target, int flags);
+static int     mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
+static void    mptscsih_timer_expired(unsigned long data);
+static void    mptscsih_taskmgmt_timeout(unsigned long data);
+static int     mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *iocmd);
+static int     mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, int portnum);
+
+#ifndef MPTSCSIH_DISABLE_DOMAIN_VALIDATION
+static int     mptscsih_do_raid(MPT_SCSI_HOST *hd, u8 action, INTERNAL_CMD *io);
+static void    mptscsih_domainValidation(void *hd);
+static int     mptscsih_is_phys_disk(MPT_ADAPTER *ioc, int id);
+static void    mptscsih_qas_check(MPT_SCSI_HOST *hd);
+static void    mptscsih_doDv(MPT_SCSI_HOST *hd, int portnum, int target);
+static void    mptscsih_dv_parms(MPT_SCSI_HOST *hd, DVPARAMETERS *dv,void *pPage);
+static void    mptscsih_fillbuf(char *buffer, int size, int index, int width);
+#endif
+static int     mptscsih_setup(char *str);
+static int     mptscsih_halt(struct notifier_block *nb, ulong event, void *buf);
+
+/*
+ *     Reboot Notification
+ */
+static struct notifier_block mptscsih_notifier = {
+       mptscsih_halt, NULL, 0
+};
+
+/*
+ *     Private data...
+ */
 
 static int     mpt_scsi_hosts = 0;
 static atomic_t        queue_depth;
 
 static int     ScsiDoneCtx = -1;
 static int     ScsiTaskCtx = -1;
+static int     ScsiScanDvCtx = -1; /* Used only for bus scan and dv */
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,28)
 static struct proc_dir_entry proc_mpt_scsihost =
@@ -141,23 +234,40 @@ static struct proc_dir_entry proc_mpt_scsihost =
 };
 #endif
 
-#define SNS_LEN(scp)  sizeof((scp)->sense_buffer)
+#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;
+static spinlock_t mytaskQ_lock = SPIN_LOCK_UNLOCKED;
+static int mytaskQ_bh_active = 0;
+static struct tq_struct        mptscsih_ptaskfoo;
+static atomic_t        mpt_taskQdepth;
+#endif
+
+#ifndef MPTSCSIH_DISABLE_DOMAIN_VALIDATION
+/*
+ * Domain Validation task structure
+ */
+static spinlock_t dvtaskQ_lock = SPIN_LOCK_UNLOCKED;
+static int dvtaskQ_active = 0;
+static int dvtaskQ_release = 0;
+static struct tq_struct        mptscsih_dvTask;
 #endif
 
+/*
+ * Wait Queue setup
+ */
+static DECLARE_WAIT_QUEUE_HEAD (scandv_waitq);
+static int scandv_wait_done = 1;
+
+/* Driver default setup
+ */
+static struct mptscsih_driver_setup
+       driver_setup = MPTSCSIH_DRIVER_SETUP;
+
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
  *     mptscsih_io_done - Main SCSI IO callback routine registered to
@@ -174,123 +284,111 @@ static MPT_FRAME_HDR *mpt_scsih_active_taskmgmt_mf = NULL;
  *     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)
+mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
 {
        Scsi_Cmnd       *sc;
        MPT_SCSI_HOST   *hd;
-       MPT_SCSI_DEV    *mpt_sdev = NULL;
+       SCSIIORequest_t *pScsiReq;
+       SCSIIOReply_t   *pScsiReply;
+#ifndef MPT_SCSI_USE_NEW_EH
+       unsigned long    flags;
+#endif
        u16              req_idx;
 
+       hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
+
        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;
+               printk(MYIOC_s_ERR_FMT "%s req frame ptr! (=%p)!\n",
+                               ioc->name, mf?"BAD":"NULL", (void *) mf);
+               /* return 1; CHECKME SteveR. Don't free. */
+               return 0;
        }
 
-       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;
+       if (sc == NULL) {
+               MPIHeader_t *hdr = (MPIHeader_t *)mf;
 
-       dmfprintk((KERN_INFO MYNAM ": ScsiDone (req:sc:reply=%p:%p:%p)\n", mf, sc, r));
+               atomic_dec(&queue_depth);
 
-       atomic_dec(&queue_depth);
+               /* writeSDP1 will use the ScsiDoneCtx
+                * There is no processing for the reply.
+                * Just return to the calling function.
+                */
+               if (hdr->Function == MPI_FUNCTION_SCSI_IO_REQUEST)
+                       printk(MYIOC_s_ERR_FMT "NULL ScsiCmd ptr!\n", ioc->name);
 
-       /*
-        *  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
-               }
+               mptscsih_freeChainBuffers(hd, req_idx);
+               return 1;
        }
 
-#if 0
-{
-       MPT_FRAME_HDR   *mf_chk;
+       dmfprintk((MYIOC_s_INFO_FMT "ScsiDone (mf=%p,mr=%p,sc=%p)\n",
+                       ioc->name, mf, mr, sc));
 
-       /* 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(sc->host->host_lock, flags);
-                       sc->scsi_done(sc);
-                       spin_unlock_irqrestore(sc->host->host_lock, flags);
-                       return 1;
-               }
-       }
-}
-#endif
+       atomic_dec(&queue_depth);
 
-       if (r != NULL && sc != NULL) {
-               SCSIIOReply_t   *pScsiReply;
-               SCSIIORequest_t *pScsiReq;
-               u16              status;
+       sc->result = DID_OK << 16;              /* Set default reply as OK */
+       pScsiReq = (SCSIIORequest_t *) mf;
+       pScsiReply = (SCSIIOReply_t *) mr;
+
+       if (pScsiReply == NULL) {
+               /* special context reply handling */
+
+               /* If regular Inquiry cmd - save inquiry data
+                */
+               if (pScsiReq->CDB[0] == INQUIRY && !(pScsiReq->CDB[1] & 0x3)) {
+                       int      dlen;
+
+                       dlen = le32_to_cpu(pScsiReq->DataLength);
+                       if (dlen >= SCSI_STD_INQUIRY_BYTES) {
+                               mptscsih_initTarget(hd,
+                                               hd->port,
+                                               sc->target,
+                                               pScsiReq->LUN[1],
+                                               sc->buffer,
+                                               dlen);
+                       }
+               }
+               clear_sense_flag(hd, pScsiReq);
 
-               pScsiReply = (SCSIIOReply_t *) r;
-               pScsiReq = (SCSIIORequest_t *) mf;
+               if (hd->is_spi)
+                       mptscsih_set_dvflags(hd, pScsiReq, sc->buffer);
+       } else {
+               u32      xfer_cnt;
+               u16      status;
+               u8       scsi_state;
 
                status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK;
+               scsi_state = pScsiReply->SCSIState;
 
-               dprintk((KERN_NOTICE MYNAM ": Uh-Oh!  (req:sc:reply=%p:%p:%p)\n", mf, sc, r));
+               dprintk((KERN_NOTICE "  Uh-Oh! (%d:%d:%d) mf=%p, mr=%p, sc=%p\n",
+                               ioc->id, pScsiReq->TargetID, pScsiReq->LUN[1],
+                               mf, mr, sc));
                dprintk((KERN_NOTICE "  IOCStatus=%04xh, SCSIState=%02xh"
-                                    ", SCSIStatus=%02xh, IOCLogInfo=%08xh\n",
-                                    status, pScsiReply->SCSIState, pScsiReply->SCSIStatus,
-                                    le32_to_cpu(pScsiReply->IOCLogInfo)));
+                               ", SCSIStatus=%02xh, IOCLogInfo=%08xh\n",
+                               status, scsi_state, pScsiReply->SCSIStatus,
+                               le32_to_cpu(pScsiReply->IOCLogInfo)));
+
+               if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID)
+                       copy_sense_data(sc, hd, mf, pScsiReply);
 
                /*
                 *  Look for + dump FCP ResponseInfo[]!
                 */
-               if (pScsiReply->SCSIState & MPI_SCSI_STATE_RESPONSE_INFO_VALID) {
+               if (scsi_state & 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;
+                       /* CHECKME!
+                        * Maybe: DRIVER_BUSY | SUGGEST_RETRY | DID_SOFT_ERROR (retry)
+                        * But not: DID_BUS_BUSY lest one risk
+                        * killing interrupt handler:-(
+                        */
+                       sc->result = STS_BUSY;
                        break;
 
                case MPI_IOCSTATUS_SCSI_INVALID_BUS:            /* 0x0041 */
@@ -299,10 +397,37 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r)
                        break;
 
                case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE:       /* 0x0043 */
-                       /*  Spoof to SCSI Selection Timeout!  */
+                       /* Spoof to SCSI Selection Timeout! */
                        sc->result = DID_NO_CONNECT << 16;
                        break;
 
+               case MPI_IOCSTATUS_SCSI_TASK_TERMINATED:        /* 0x0048 */
+#ifndef MPT_SCSI_USE_NEW_EH
+                       search_taskQ_for_cmd(sc, hd);
+#endif
+                       /* Linux handles an unsolicited DID_RESET better 
+                        * than an unsolicited DID_ABORT.
+                        */
+                       sc->result = DID_RESET << 16;
+
+                       /* GEM Workaround. */ 
+                       if (hd->is_spi)
+                               mptscsih_no_negotiate(hd, sc->target);
+                       break;
+
+               case MPI_IOCSTATUS_SCSI_IOC_TERMINATED:         /* 0x004B */
+               case MPI_IOCSTATUS_SCSI_EXT_TERMINATED:         /* 0x004C */
+#ifndef MPT_SCSI_USE_NEW_EH
+                       search_taskQ_for_cmd(sc, hd);
+#endif
+                       sc->result = DID_RESET << 16;
+
+                       /* GEM Workaround. */ 
+                       if (hd->is_spi)
+                               mptscsih_no_negotiate(hd, sc->target);
+                       break;
+
+               case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:      /* 0x0049 */
                case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN:          /* 0x0045 */
                        /*
                         *  YIKES!  I just discovered that SCSI IO which
@@ -312,78 +437,148 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r)
                         *  Do upfront check for valid SenseData and give it
                         *  precedence!
                         */
+                       sc->result = (DID_OK << 16) | pScsiReply->SCSIStatus;
+                       clear_sense_flag(hd, pScsiReq);
                        if (pScsiReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
-                               copy_sense_data(sc, hd, mf, pScsiReply);
-                               sc->result = pScsiReply->SCSIStatus;
-                               break;
+                               /* Have already saved the status and sense data
+                                */
+                               ;
+                       } 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_RESET << 16;
                        }
 
-                       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)));
+                       /* Give report and update residual count.
+                        */
+                       xfer_cnt = le32_to_cpu(pScsiReply->TransferCount);
+                       dprintk((KERN_NOTICE "  sc->underflow={report ERR if < %02xh bytes xfer'd}\n",
+                                       sc->underflow));
+                       dprintk((KERN_NOTICE "  ActBytesXferd=%02xh\n", xfer_cnt));
 
 #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));
+                       sc->resid = sc->request_bufflen - xfer_cnt;
+                       dprintk((KERN_NOTICE  SET sc->resid=%02xh\n", sc->resid));
 #endif
 
-                       if (pScsiReq->CDB[0] == INQUIRY) {
-                               sc->result = (DID_OK << 16);
-                               break;
-                       }
+                       /* Report Queue Full
+                        */
+                       if (sc->result == MPI_SCSI_STATUS_TASK_SET_FULL)
+                               mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
 
-                       /* 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;
+                       /* If regular Inquiry cmd and some data was transferred,
+                        * save inquiry data
+                        */
+                       if (    pScsiReq->CDB[0] == INQUIRY
+                            && !(pScsiReq->CDB[1] & 0x3)
+                            && xfer_cnt >= SCSI_STD_INQUIRY_BYTES
+                          ) {
+                               mptscsih_initTarget(hd,
+                                               hd->port,
+                                               sc->target,
+                                               pScsiReq->LUN[1],
+                                               sc->buffer,
+                                               xfer_cnt);
                        }
-#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;
+                       if (hd->is_spi)
+                               mptscsih_set_dvflags(hd, pScsiReq, sc->buffer);
                        break;
 
+               case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR:        /* 0x0040 */
                case MPI_IOCSTATUS_SUCCESS:                     /* 0x0000 */
-                       sc->result = pScsiReply->SCSIStatus;
+                       sc->result = (DID_OK << 16) | pScsiReply->SCSIStatus;
+                       clear_sense_flag(hd, pScsiReq);
 
                        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 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);
+
+#ifndef MPT_SCSI_USE_NEW_EH
+                               /* ADDED 20011120 -sralston
+                                * Scsi mid-layer (old_eh) doesn't seem to like it
+                                * when RAID returns SCSIStatus=02 (CHECK CONDITION),
+                                * SenseKey=01 (RECOVERED ERROR), ASC/ASCQ=95/01.
+                                * Seems to be * treating this as a IO error:-(
+                                *
+                                * So just lie about it altogether here.
+                                *
+                                * NOTE: It still gets reported to syslog via
+                                * mpt_ScsiHost_ErrorReport from copy_sense_data
+                                * call far above.
+                                */
+                               if (    pScsiReply->SCSIStatus == STS_CHECK_CONDITION
+                                    && SD_Sense_Key(sc->sense_buffer) == SK_RECOVERED_ERROR
+                                  ) {
+                                       sc->result = 0;
+                               }
+#endif
+
                        }
-                       else if (pScsiReply->SCSIState & (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)) {
+                       else if (pScsiReply->SCSIState &
+                                (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)
+                          ) {
                                /*
-                                *  What to do?
+                                * 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;
+                               sc->result = DID_RESET << 16;
+                       }
+                       else if (pScsiReply->SCSIState & MPI_SCSI_STATE_QUEUE_TAG_REJECTED) {
+                               /* Device Inq. data indicates that it supports
+                                * QTags, but rejects QTag messages.
+                                * This command completed OK.
+                                *
+                                * Not real sure here either so do nothing...  */
                        }
 
                        if (sc->result == MPI_SCSI_STATUS_TASK_SET_FULL)
                                mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
 
+                       /* Add handling of:
+                        * Reservation Conflict, Busy,
+                        * Command Terminated, CHECK
+                        */
+
+                       /* If regular Inquiry cmd - save inquiry data
+                        */
+                       xfer_cnt = le32_to_cpu(pScsiReply->TransferCount);
+                       if (    sc->result == (DID_OK << 16)
+                            && pScsiReq->CDB[0] == INQUIRY
+                            && !(pScsiReq->CDB[1] & 0x3)
+                            && xfer_cnt >= SCSI_STD_INQUIRY_BYTES
+                          ) {
+                               mptscsih_initTarget(hd,
+                                               hd->port,
+                                               sc->target,
+                                               pScsiReq->LUN[1],
+                                               sc->buffer,
+                                               xfer_cnt);
+                       }
+
+                       if (hd->is_spi)
+                               mptscsih_set_dvflags(hd, pScsiReq, sc->buffer);
+                       break;
+
+               case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR:         /* 0x0047 */
+                       if (pScsiReply->SCSIState & MPI_SCSI_STATE_TERMINATED) {
+                               /*  Not real sure here either...  */
+                               sc->result = DID_RESET << 16;
+                       } else
+                               sc->result = DID_SOFT_ERROR << 16;
                        break;
 
                case MPI_IOCSTATUS_INVALID_FUNCTION:            /* 0x0001 */
@@ -395,50 +590,50 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r)
                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?
+                        * What to do?
                         */
                        sc->result = DID_SOFT_ERROR << 16;
                        break;
 
                }       /* switch(status) */
 
-               dprintk((KERN_NOTICE MYNAM ": sc->result set to %08xh\n", sc->result));
+               dprintk((KERN_NOTICE "  sc->result set to %08xh\n", sc->result));
+       } /* end of address reply case */
+
+       /* 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) {
+               scPrivate       *my_priv;
+
+               my_priv = (scPrivate *) &sc->SCp;
+               pci_unmap_single(ioc->pcidev, (dma_addr_t)(ulong)my_priv->p1,
+                          sc->request_bufflen,
+                          scsi_to_pci_dma_dir(sc->sc_data_direction));
        }
 
-       if (sc != NULL) {
-               unsigned long flags;
+       hd->ScsiLookup[req_idx] = NULL;
 
-               /* 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));
-               }
+       sc->host_scribble = NULL;       /* CHECKME! - Do we need to clear this??? */
 
-               spin_lock_irqsave(sc->host->host_lock, flags);
-               sc->scsi_done(sc);
-               spin_unlock_irqrestore(sc->host->host_lock, flags);
-       }
+        MPT_HOST_LOCK(flags);
+       sc->scsi_done(sc);              /* Issue the command callback */
+        MPT_HOST_UNLOCK(flags);
 
+       /* Free Chain buffers */
+       mptscsih_freeChainBuffers(hd, req_idx);
        return 1;
 }
 
-#ifndef MPT_SCSI_USE_NEW_EH
+#ifndef MPT_SCSI_USE_NEW_EH    /* { */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
  *     search_taskQ - Search SCSI task mgmt request queue for specific
- *                     request type
+ *     request type.
  *     @remove: (Boolean) Should request be removed if found?
  *     @sc: Pointer to Scsi_Cmnd structure
  *     @task_type: Task type to search for
@@ -447,42 +642,55 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r)
  *     was not found.
  */
 static MPT_FRAME_HDR *
-search_taskQ(int remove, Scsi_Cmnd *sc, u8 task_type)
+search_taskQ(int remove, Scsi_Cmnd *sc, MPT_SCSI_HOST *hd, 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;
+       dprintk((KERN_INFO MYNAM ": search_taskQ(%d,sc=%p,%d) called\n",
+                       remove, sc, task_type));
+       spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
+       list_sz = hd->taskQcnt;
+       if (! Q_IS_EMPTY(&hd->taskQ)) {
+               mf = hd->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--;
+                                       hd->taskQcnt--;
+                                       atomic_dec(&mpt_taskQdepth);
+
+                                       /* Don't save mf into nextmf because
+                                        * exit after command has been deleted.
+                                        */
+
+                                       /* Place the MF back on the FreeQ */
+                                       Q_ADD_TAIL(&hd->ioc->FreeQ,
+                                               &mf->u.frame.linkage,
+                                               MPT_FRAME_HDR);
+#ifdef MFCNT
+                                       hd->ioc->mfcnt--;
+#endif
                                }
                                break;
                        }
-               } while ((mf = mf->u.frame.linkage.forw) != (MPT_FRAME_HDR*)&mpt_scsih_taskQ);
-               if (mf == (MPT_FRAME_HDR*)&mpt_scsih_taskQ) {
+               } while ((mf = mf->u.frame.linkage.forw) != (MPT_FRAME_HDR*)&hd->taskQ);
+               if (mf == (MPT_FRAME_HDR*)&hd->taskQ) {
                        mf = NULL;
                }
        }
-       spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags);
+       spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
 
        if (list_sz) {
-               dprintk((KERN_INFO MYNAM ": search_taskQ(%d,%p,%d) results=%p (%sFOUND%s)!\n",
-                                  remove, sc, task_type,
+               dprintk((KERN_INFO "  Results=%p (%sFOUND%s)!\n",
                                   mf,
                                   mf ? "" : "NOT_",
                                   (mf && remove) ? "+REMOVED" : "" ));
-               dprintk((KERN_INFO MYNAM ": (searched thru %d of %d items on taskQ)\n",
+               dprintk((KERN_INFO  (searched thru %d of %d items on taskQ)\n",
                                   count,
                                   list_sz ));
        }
@@ -490,1709 +698,3562 @@ search_taskQ(int remove, Scsi_Cmnd *sc, u8 task_type)
        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
+ *     clean_taskQ - Clean the  SCSI task mgmt request for
+ *                     this SCSI host instance.
+ *     @hd: MPT_SCSI_HOST pointer
  *
- *     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.
+ *     Returns: None.
  */
 static void
-mptscsih_report_queue_full(Scsi_Cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq)
+clean_taskQ(MPT_SCSI_HOST *hd)
 {
-       long time = jiffies;
+       MPT_FRAME_HDR *mf = NULL;
+       MPT_FRAME_HDR *nextmf = NULL;
+       MPT_ADAPTER *ioc = hd->ioc;
+       unsigned long flags;
 
-       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;
+       dprintk((KERN_INFO MYNAM ": clean_taskQ called\n"));
+
+       spin_lock_irqsave(&ioc->FreeQlock, flags);
+       if (! Q_IS_EMPTY(&hd->taskQ)) {
+               mf = hd->taskQ.head;
+               do {
+                       Q_DEL_ITEM(&mf->u.frame.linkage);
+                       hd->taskQcnt--;
+                       atomic_dec(&mpt_taskQdepth);
+
+                       nextmf = mf->u.frame.linkage.forw;
+
+                       /* Place the MF back on the FreeQ */
+                       Q_ADD_TAIL(&ioc->FreeQ, &mf->u.frame.linkage,
+                               MPT_FRAME_HDR);
+#ifdef MFCNT
+                       hd->ioc->mfcnt--;
+#endif
+               } while ((mf = nextmf) != (MPT_FRAME_HDR*)&hd->taskQ);
        }
-}
+       spin_unlock_irqrestore(&ioc->FreeQlock, flags);
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-static int BeenHereDoneThat = 0;
+       return;
+}
 
-/*  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)
+/*
+ *     search_taskQ_for_cmd - Search the  SCSI task mgmt request queue for
+ *                     the specified command. If found, delete
+ *     @hd: MPT_SCSI_HOST pointer
  *
- *     Returns number of SCSI host adapters that were successfully
- *     registered with the linux scsi mid-layer via the scsi_register()
- *     API call.
+ *     Returns: None.
  */
-int
-mptscsih_detect(Scsi_Host_Template *tpnt)
+static void
+search_taskQ_for_cmd(Scsi_Cmnd *sc, MPT_SCSI_HOST *hd)
 {
-       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);
+       MPT_FRAME_HDR *mf = NULL;
+       unsigned long flags;
+       int count = 0;
 
-               if ((ScsiDoneCtx = mpt_register(mptscsih_io_done, MPTSCSIH_DRIVER)) <= 0) {
-                       printk(KERN_ERR MYNAM ": Failed to register callback1 with MPT base driver\n");
-                       return mpt_scsi_hosts;
-               }
-               if ((ScsiTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSCSIH_DRIVER)) <= 0) {
-                       printk(KERN_ERR MYNAM ": Failed to register callback2 with MPT base driver\n");
-                       return mpt_scsi_hosts;
-               }
+       dprintk((KERN_INFO MYNAM ": search_taskQ_for_cmd(sc=%p) called\n", sc));
+       spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
+       if (! Q_IS_EMPTY(&hd->taskQ)) {
+               mf = hd->taskQ.head;
+               do {
+                       count++;
+                       if (mf->u.frame.linkage.argp1 == sc) {
+                               Q_DEL_ITEM(&mf->u.frame.linkage);
+                               hd->taskQcnt--;
+                               atomic_dec(&mpt_taskQdepth);
+                               dprintk((KERN_INFO MYNAM
+                                       ": Cmd %p found! Deleting.\n", sc));
+
+                               /* Don't save mf into nextmf because
+                                * exit after command has been deleted.
+                                */
 
-#ifndef MPT_SCSI_USE_NEW_EH
-               Q_INIT(&mpt_scsih_taskQ, MPT_FRAME_HDR);
-               spin_lock_init(&mpt_scsih_taskQ_lock);
+                               /* Place the MF back on the FreeQ */
+                               Q_ADD_TAIL(&hd->ioc->FreeQ,
+                                       &mf->u.frame.linkage,
+                                       MPT_FRAME_HDR);
+#ifdef MFCNT
+                               hd->ioc->mfcnt--;
 #endif
+                               break;
+                       }
+               } while ((mf = mf->u.frame.linkage.forw) != (MPT_FRAME_HDR*)&hd->taskQ);
+       }
+       spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
 
-               if (mpt_event_register(ScsiDoneCtx, mptscsih_event_process) == 0) {
-                       dprintk((KERN_INFO MYNAM ": Registered for IOC event notifications\n"));
-               } else {
-                       /* FIXME! */
-               }
+       return;
+}
 
-               if (mpt_reset_register(ScsiDoneCtx, mptscsih_ioc_reset) == 0) {
-                       dprintk((KERN_INFO MYNAM ": Registered for IOC reset notifications\n"));
-               } else {
-                       /* FIXME! */
-               }
-       }
+#endif         /* } MPT_SCSI_USE_NEW_EH */
 
-       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++)
-                */
+/*
+ * Flush all commands on the doneQ.
+ * Lock Q when deleting/adding members
+ * Lock io_request_lock for OS callback.
+ */
+static void
+flush_doneQ(MPT_SCSI_HOST *hd)
+{
+       MPT_DONE_Q      *buffer;
+       Scsi_Cmnd       *SCpnt;
+       unsigned long    flags;
 
-               /* 20010215 -sralston
-                *  Added sanity check on SCSI Initiator-mode enabled
-                *  for this MPT adapter.
-                */
-               if (!(this->pfacts[0].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;
+       /* Flush the doneQ.
+        */
+       dprintk((KERN_INFO MYNAM ": flush_doneQ called\n"));
+       while (1) {
+               spin_lock_irqsave(&hd->freedoneQlock, flags);
+               if (Q_IS_EMPTY(&hd->doneQ)) {
+                       spin_unlock_irqrestore(&hd->freedoneQlock, flags);
+                       break;
                }
 
-               /* 20010202 -sralston
-                *  Added sanity check on readiness of the MPT adapter.
+               buffer = hd->doneQ.head;
+               /* Delete from Q
                 */
-               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!
-                        *
-                        * BUG FIX!  20010618 -sralston & pdelaney
-                        * FC919 testing was encountering "duplicate" FC devices,
-                        * as it turns out because the 919 was returning 512
-                        * for PortFacts.MaxDevices, causing a wraparound effect
-                        * in SCSI IO requests.  So instead of using:
-                        *     sh->max_id = this->pfacts[0].MaxDevices - 1
-                        * we'll use a definitive max here.
-                        */
-                       sh->max_id = MPT_MAX_FC_DEVICES;
-
-                       sh->this_id = this->pfacts[0].PortSCSIID;
+               Q_DEL_ITEM(buffer);
 
-                       restore_flags(flags);
+               /* Set the Scsi_Cmnd pointer
+                */
+               SCpnt = (Scsi_Cmnd *) buffer->argp;
+               buffer->argp = NULL;
 
-                       hd = (MPT_SCSI_HOST *) sh->hostdata;
-                       hd->ioc = this;
-                       hd->port = 0;           /* FIXME! */
+               /* Add to the freeQ
+                */
+               Q_ADD_TAIL(&hd->freeQ.head, buffer, MPT_DONE_Q);
+               spin_unlock_irqrestore(&hd->freedoneQlock, flags);
 
-                       /* 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;
+               /* Do the OS callback.
+                */
+                MPT_HOST_LOCK(flags);
+               SCpnt->scsi_done(SCpnt);
+                MPT_HOST_UNLOCK(flags);
+       }
 
-                       memset(mem, 0, sz);
-                       hd->ScsiLookup = (struct scsi_cmnd **) mem;
+       return;
+}
 
-                       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;
+/*
+ * Search the doneQ for a specific command. If found, delete from Q.
+ * Calling function will finish processing.
+ */
+static void
+search_doneQ_for_cmd(MPT_SCSI_HOST *hd, Scsi_Cmnd *SCpnt)
+{
+       unsigned long    flags;
+       MPT_DONE_Q      *buffer;
 
-                       dprintk((KERN_INFO MYNAM ": SgHunks    @ %p(%08x), sz=%d\n",
-                                hd->SgHunks, hd->SgHunksDMA, sz));
+       spin_lock_irqsave(&hd->freedoneQlock, flags);
+       if (!Q_IS_EMPTY(&hd->doneQ)) {
+               buffer = hd->doneQ.head;
+               do {
+                       Scsi_Cmnd *sc = (Scsi_Cmnd *) buffer->argp;
+                       if (SCpnt == sc) {
+                               Q_DEL_ITEM(buffer);
+                               SCpnt->result = sc->result;
 
-                       hd->qtag_tick = jiffies;
+                               /* Set the Scsi_Cmnd pointer
+                                */
+                               buffer->argp = NULL;
 
-                       this->sh = sh;
-                       mpt_scsi_hosts++;
-               }
-               this = mpt_adapter_find_next(this);
+                               /* Add to the freeQ
+                                */
+                               Q_ADD_TAIL(&hd->freeQ.head, buffer, MPT_DONE_Q);
+                               break;
+                       }
+               } while ((buffer = buffer->forw) != (MPT_DONE_Q *) &hd->doneQ);
        }
-
-       return mpt_scsi_hosts;
+       spin_unlock_irqrestore(&hd->freedoneQlock, flags);
+       return;
 }
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-    static char *info_kbuf = NULL;
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/**
- *     mptscsih_release - Unregister SCSI host from linux scsi mid-layer
- *     @host: Pointer to Scsi_Host structure
+/*
+ *     mptscsih_flush_running_cmds - For each command found, search
+ *             Scsi_Host instance taskQ and reply to OS.
+ *             Called only if recovering from a FW reload.
+ *     @hd: Pointer to a SCSI HOST structure
  *
- *     (linux Scsi_Host_Template.release routine)
- *     This routine releases all resources associated with the SCSI host
- *     adapter.
+ *     Returns: None.
  *
- *     Returns 0 for success.
+ *     Must be called while new I/Os are being queued.
  */
-int
-mptscsih_release(struct Scsi_Host *host)
+static void
+mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd)
 {
-       MPT_SCSI_HOST   *hd;
+       Scsi_Cmnd       *SCpnt = NULL;
+       MPT_FRAME_HDR   *mf = NULL;
+       int              ii;
+       int              max = hd->ioc->req_depth;
+
 #ifndef MPT_SCSI_USE_NEW_EH
        unsigned long    flags;
+#endif
 
-       spin_lock_irqsave(&mpt_scsih_taskQ_lock, flags);
-       if (mpt_scsih_taskQ_bh_active) {
-               int count = 10 * HZ;
+       dprintk((KERN_INFO MYNAM ": flush_ScsiLookup called\n"));
+       for (ii= 0; ii < max; ii++) {
+               if ((SCpnt = hd->ScsiLookup[ii]) != NULL) {
 
-               dprintk((KERN_INFO MYNAM ": Info: Zapping TaskMgmt thread!\n"));
+                       /* Command found.
+                        */
+
+#ifndef MPT_SCSI_USE_NEW_EH
+                       /* Search taskQ, if found, delete.
+                        */
+                       search_taskQ_for_cmd(SCpnt, hd);
+#endif
 
-               /* Zap the taskQ! */
-               Q_INIT(&mpt_scsih_taskQ, MPT_FRAME_HDR);
-               spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags);
+                       /* Search pendingQ, if found, 
+                        * delete from Q. If found, do not decrement
+                        * queue_depth, command never posted.
+                        */
+                       if (mptscsih_search_pendingQ(hd, ii) == NULL)
+                               atomic_dec(&queue_depth);
 
-               while(mpt_scsih_taskQ_bh_active && --count) {
-                       current->state = TASK_INTERRUPTIBLE;
-                       schedule_timeout(1);
+                       /* Null ScsiLookup index
+                        */
+                       hd->ScsiLookup[ii] = NULL;
+
+                       mf = MPT_INDEX_2_MFPTR(hd->ioc, ii);
+                       dmfprintk(( "flush: ScsiDone (mf=%p,sc=%p)\n",
+                                       mf, SCpnt));
+
+                       /* Set status
+                        * Do OS callback
+                        * Free chain buffers
+                        * Free message frame
+                        */
+                       SCpnt->result = DID_RESET << 16;
+                       SCpnt->host_scribble = NULL;
+                        MPT_HOST_LOCK(flags);
+                       SCpnt->scsi_done(SCpnt);        /* Issue the command callback */
+                        MPT_HOST_UNLOCK(flags);
+
+                       /* Free Chain buffers */
+                       mptscsih_freeChainBuffers(hd, ii);
+
+                       /* Free Message frames */
+                       mpt_free_msg_frame(ScsiDoneCtx, hd->ioc->id, mf);
                }
-               if (!count)
-                       printk(KERN_ERR MYNAM ": ERROR! TaskMgmt thread still active!\n");
        }
-       spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags);
-#endif
+       return;
+}
 
-       hd = (MPT_SCSI_HOST *) host->hostdata;
-       if (hd != NULL) {
-               int sz1, sz2;
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     mptscsih_initChainBuffers - Allocate memory for and initialize
+ *     chain buffers, chain buffer control arrays and spinlock.
+ *     @hd: Pointer to MPT_SCSI_HOST structure
+ *     @init: If set, initialize the spin lock.
+ */
+static int
+mptscsih_initChainBuffers (MPT_SCSI_HOST *hd, int init)
+{
+       MPT_FRAME_HDR   *chain;
+       u8              *mem;
+       unsigned long   flags;
+       int             sz, ii, numChain;
 
-               sz1 = sz2 = 0;
-               if (hd->ScsiLookup != NULL) {
-                       sz1 = hd->ioc->req_depth * sizeof(void *);
-                       kfree(hd->ScsiLookup);
-                       hd->ScsiLookup = NULL;
-               }
 
-               if (hd->SgHunks != NULL) {
+        /* Chain buffer allocations
+        * Allocate and initialize tracker structures
+        */
+       if (hd->ioc->req_sz <= 64)
+               numChain = MPT_SG_REQ_64_SCALE * hd->ioc->req_depth;
+       else if (hd->ioc->req_sz <= 96)
+               numChain = MPT_SG_REQ_96_SCALE * hd->ioc->req_depth;
+       else
+               numChain = MPT_SG_REQ_128_SCALE * hd->ioc->req_depth;
 
-                       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));
+       sz = numChain * sizeof(int);
+
+       if (hd->ReqToChain == NULL) {
+               mem = kmalloc(sz, GFP_ATOMIC);
+               if (mem == NULL)
+                       return -1;
+
+               hd->ReqToChain = (int *) mem;
+       } else {
+               mem = (u8 *) hd->ReqToChain;
        }
+       memset(mem, 0xFF, sz);
 
-       if (mpt_scsi_hosts) {
-               if (--mpt_scsi_hosts == 0) {
-#if 0
-                       mptscsih_flush_pending();
-#endif
-                       mpt_reset_deregister(ScsiDoneCtx);
-                       dprintk((KERN_INFO MYNAM ": Deregistered for IOC reset notifications\n"));
+       if (hd->ChainToChain == NULL) {
+               mem = kmalloc(sz, GFP_ATOMIC);
+               if (mem == NULL)
+                       return -1;
 
-                       mpt_event_deregister(ScsiDoneCtx);
-                       dprintk((KERN_INFO MYNAM ": Deregistered for IOC event notifications\n"));
+               hd->ChainToChain = (int *) mem;
+       } else {
+               mem = (u8 *) hd->ChainToChain;
+       }
+       memset(mem, 0xFF, sz);
 
-                       mpt_deregister(ScsiDoneCtx);
-                       mpt_deregister(ScsiTaskCtx);
+       if (hd->ChainBuffer == NULL) {
+               /* Allocate free chain buffer pool
+                */
+               sz = numChain * hd->ioc->req_sz;
+               mem = pci_alloc_consistent(hd->ioc->pcidev, sz, &hd->ChainBufferDMA);
+               if (mem == NULL)
+                       return -1;
 
-                       if (info_kbuf != NULL)
-                               kfree(info_kbuf);
-               }
+               hd->ChainBuffer = (u8*)mem;
+       } else {
+               mem = (u8 *) hd->ChainBuffer;
+       }
+       memset(mem, 0, sz);
+
+       dprintk((KERN_INFO "  ChainBuffer    @ %p(%p), sz=%d\n",
+                hd->ChainBuffer, (void *)(ulong)hd->ChainBufferDMA, sz));
+
+       /* Initialize the free chain Q.
+        */
+       if (init) {
+               spin_lock_init(&hd->FreeChainQlock);
+       }
+
+       spin_lock_irqsave (&hd->FreeChainQlock, flags);
+       Q_INIT(&hd->FreeChainQ, MPT_FRAME_HDR);
+
+       /* Post the chain buffers to the FreeChainQ.
+        */
+       mem = (u8 *)hd->ChainBuffer;
+       for (ii=0; ii < numChain; ii++) {
+               chain = (MPT_FRAME_HDR *) mem;
+               Q_ADD_TAIL(&hd->FreeChainQ.head, &chain->u.frame.linkage, MPT_FRAME_HDR);
+               mem += hd->ioc->req_sz;
        }
+       spin_unlock_irqrestore(&hd->FreeChainQlock, flags);
 
        return 0;
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/**
- *     mptscsih_info - Return information about MPT adapter
- *     @SChost: Pointer to Scsi_Host structure
- *
- *     (linux Scsi_Host_Template.info routine)
+/*
+ *  Hack! It might be nice 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
  *
- *     Returns pointer to buffer where information was written.
+ *     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.
  */
-const char *
-mptscsih_info(struct Scsi_Host *SChost)
+static void
+mptscsih_report_queue_full(Scsi_Cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq)
 {
-       MPT_SCSI_HOST *h;
-       int size = 0;
-
-       if (info_kbuf == NULL)
-               if ((info_kbuf = kmalloc(0x1000 /* 4Kb */, GFP_KERNEL)) == NULL)
-                       return info_kbuf;
+       long time = jiffies;
 
-       h = (MPT_SCSI_HOST *)SChost->hostdata;
-       info_kbuf[0] = '\0';
-       mpt_print_ioc_summary(h->ioc, info_kbuf, &size, 0, 0);
-       info_kbuf[size-1] = '\0';
+       if (time - last_queue_full > 10 * HZ) {
+               char *ioc_str = "ioc?";
 
-       return info_kbuf;
+               if (sc->host != NULL && sc->host->hostdata != NULL)
+                       ioc_str = ((MPT_SCSI_HOST *)sc->host->hostdata)->ioc->name;
+               printk(MYIOC_s_WARN_FMT "Device (%d:%d:%d) reported QUEUE_FULL!\n",
+                               ioc_str, 0, sc->target, sc->lun);
+               last_queue_full = time;
+       }
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-       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++;
+static int BeenHereDoneThat = 0;
 
-       index_log[i & (128 - 1)] = req_ent;
-}
-#else
-#define ADD_INDEX_LOG(req_ent) do { } while(0)
-#endif
+/*  SCSI host fops start here...  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
- *     mptscsih_qcmd - Primary Fusion MPT SCSI initiator IO start routine.
- *     @SCpnt: Pointer to Scsi_Cmnd structure
- *     @done: Pointer SCSI mid-layer IO completion function
+ *     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.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.
+ *     (linux Scsi_Host_Template.detect routine)
  *
- *     Returns 0. (rtn value discarded by linux scsi mid-layer)
+ *     Returns number of SCSI host adapters that were successfully
+ *     registered with the linux scsi mid-layer via the scsi_register()
+ *     API call.
  */
 int
-mptscsih_qcmd(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
+mptscsih_detect(Scsi_Host_Template *tpnt)
 {
-       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;
+       struct Scsi_Host        *sh = NULL;
+       MPT_SCSI_HOST           *hd = NULL;
+       MPT_ADAPTER             *this;
+       MPT_DONE_Q              *freedoneQ;
+       unsigned long            flags;
+       int                      sz, ii;
+       int                      numSGE = 0;
+       int                      scale;
+       u8                      *mem;
 
-       dmfprintk((KERN_INFO MYNAM "_qcmd: SCpnt=%p, done()=%p\n",
-                   SCpnt, done));
+       if (! BeenHereDoneThat++) {
+               show_mptmod_ver(my_NAME, my_VERSION);
 
-       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;
+               ScsiDoneCtx = mpt_register(mptscsih_io_done, MPTSCSIH_DRIVER);
+               ScsiTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSCSIH_DRIVER);
+               ScsiScanDvCtx = mpt_register(mptscsih_scandv_complete, MPTSCSIH_DRIVER);
 
-                       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");
+#ifndef MPT_SCSI_USE_NEW_EH
+               spin_lock_init(&mytaskQ_lock);
+#endif
+
+               if (mpt_event_register(ScsiDoneCtx, mptscsih_event_process) == 0) {
+                       dprintk((KERN_INFO MYNAM ": Registered for IOC event notifications\n"));
+               } else {
+                       /* FIXME! */
+               }
+
+               if (mpt_reset_register(ScsiDoneCtx, mptscsih_ioc_reset) == 0) {
+                       dprintk((KERN_INFO MYNAM ": Registered for IOC reset notifications\n"));
+               } else {
+                       /* FIXME! */
                }
-               sti();
-               while(1)
-                       barrier();
        }
-#endif
+       dprintk((KERN_INFO MYNAM ": mpt_scsih_detect()\n"));
 
-       SCpnt->scsi_done = done;
+#ifdef MODULE
+       /* Evaluate the command line arguments, if any */
+       if (mptscsih)
+               mptscsih_setup(mptscsih);
+#endif
+#ifndef MPT_SCSI_USE_NEW_EH
+       atomic_set(&mpt_taskQdepth, 0);
+#endif
 
-       /* 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;
+       this = mpt_adapter_find_first();
+       while (this != NULL) {
+               int      portnum;
+               for (portnum=0; portnum < this->facts.NumberOfPorts; portnum++) {
 
-               mpt_sdev = (MPT_SCSI_DEV *) SCpnt->device->hostdata;
-               if (mpt_sdev && SCpnt->cmnd[0] == REQUEST_SENSE) {
-                       u8 *dest = NULL;
+                       /* 20010215 -sralston
+                        *  Added sanity check on SCSI Initiator-mode enabled
+                        *  for this MPT adapter.
+                        */
+                       if (!(this->pfacts[portnum].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR)) {
+                               printk(MYIOC_s_WARN_FMT "Skipping because SCSI Initiator mode is NOT enabled!\n",
+                                               this->name);
+                               continue;
+                       }
 
-                       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
+                       /* 20010202 -sralston
+                        *  Added sanity check on readiness of the MPT adapter.
+                        */
+                       if (this->last_state != MPI_IOC_STATE_OPERATIONAL) {
+                               printk(MYIOC_s_WARN_FMT "Skipping because it's not operational!\n",
+                                               this->name);
+                               continue;
                        }
-                       SCpnt->resid = SCpnt->request_bufflen - mpt_sdev->sense_sz;
-                       SCpnt->result = 0;
-/*                     spin_lock(SCpnt->host->host_lock);      */
-                       SCpnt->scsi_done(SCpnt);
-/*                     spin_unlock(SCpnt->host->host_lock);    */
-                       return 0;
-               }
-       }
+
+#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!
+                                * pfactsN->MaxDevices unreliable
+                                * (not supported in early
+                                *      versions of the FW).
+                                * max_id = 1 + actual max id,
+                                * max_lun = 1 + actual last lun,
+                                *      see hosts.h :o(
+                                */
+                               if ((int)this->chip_type > (int)FC929)
+                                       sh->max_id = MPT_MAX_SCSI_DEVICES;
+                               else {
+                                       /* For FC, increase the queue depth
+                                        * from MPT_SCSI_CAN_QUEUE (31)
+                                        * to MPT_FC_CAN_QUEUE (63).
+                                        */
+                                       sh->can_queue = MPT_FC_CAN_QUEUE;
+                                       sh->max_id = MPT_MAX_FC_DEVICES<256 ? MPT_MAX_FC_DEVICES : 255;
+                               }
+                               sh->max_lun = MPT_LAST_LUN + 1;
 
-       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;
+                               sh->this_id = this->pfacts[portnum].PortSCSIID;
 
-       my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
+                               /* OS entry to allow host drivers to force
+                                * a queue depth on a per device basis.
+                                */
+                               sh->select_queue_depths = mptscsih_select_queue_depths;
+
+                               /* Verify that we won't exceed the maximum
+                                * number of chain buffers
+                                * We can optimize:  ZZ = req_sz/sizeof(SGE)
+                                * For 32bit SGE's:
+                                *  numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ
+                                *               + (req_sz - 64)/sizeof(SGE)
+                                * A slightly different algorithm is required for
+                                * 64bit SGEs.
+                                */
+                               scale = this->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
+                               if (sizeof(dma_addr_t) == sizeof(u64)) {
+                                       numSGE = (scale - 1) * (this->facts.MaxChainDepth-1) + scale +
+                                               (this->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
+                               } else {
+                                       numSGE = 1 + (scale - 1) * (this->facts.MaxChainDepth-1) + scale +
+                                               (this->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
+                               } 
+
+                               if (numSGE < sh->sg_tablesize) {
+                                       /* Reset this value */
+                                       dprintk((MYIOC_s_INFO_FMT
+                                                "Resetting sg_tablesize to %d from %d\n",
+                                                this->name, numSGE, sh->sg_tablesize));
+                                       sh->sg_tablesize = numSGE;
+                               }
 
-       ADD_INDEX_LOG(my_idx);
+                               /* Set the pci device pointer in Scsi_Host structure.
+                                */
+                               scsi_set_pci_device(sh, this->pcidev);
 
-       /* 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;
+                               restore_flags(flags);
 
-               buf_dma_addr = pci_map_single(hd->ioc->pcidev,
-                                             SCpnt->request_buffer,
-                                             SCpnt->request_bufflen,
-                                             scsi_to_pci_dma_dir(SCpnt->sc_data_direction));
+                               hd = (MPT_SCSI_HOST *) sh->hostdata;
+                               hd->ioc = this;
 
-               /* We hide it here for later unmap. */
-               SCpnt->SCp.ptr = (char *)(unsigned long) buf_dma_addr;
-       }
+                               if ((int)this->chip_type > (int)FC929)
+                                       hd->is_spi = 1;
 
-       /*
-        *  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;
-       }
+                               if (DmpService &&
+                                   (this->chip_type == FC919 || this->chip_type == FC929))
+                                       hd->is_multipath = 1;
 
-       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;
+                               hd->port = 0;           /* FIXME! */
 
-#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
-       }
+                               /* SCSI needs Scsi_Cmnd lookup table!
+                                * (with size equal to req_depth*PtrSz!)
+                                */
+                               sz = hd->ioc->req_depth * sizeof(void *);
+                               mem = kmalloc(sz, GFP_ATOMIC);
+                               if (mem == NULL)
+                                       goto done;
 
-       scsictl = scsidir | qtag;
+                               memset(mem, 0, sz);
+                               hd->ScsiLookup = (struct scsi_cmnd **) mem;
 
-       frm_sz = hd->ioc->req_sz;
+                               dprintk((MYIOC_s_INFO_FMT "ScsiLookup @ %p, sz=%d\n",
+                                        this->name, hd->ScsiLookup, 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));
+                               if (mptscsih_initChainBuffers(hd, 1) < 0)
+                                       goto done;
 
-#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
+                               /* Allocate memory for free and doneQ's
+                                */
+                               sz = sh->can_queue * sizeof(MPT_DONE_Q);
+                               mem = kmalloc(sz, GFP_ATOMIC);
+                               if (mem == NULL)
+                                       goto done;
 
-       dsgprintk((KERN_INFO MYNAM ": SG: %x     sges_left = %d (initially)\n",
-                  my_idx, sges_left));
+                               memset(mem, 0xFF, sz);
+                               hd->memQ = mem;
 
-       chain_offset = 0;
-       if (sges_left > (sge_spill1+1)) {
-#if 0
-               chain_offset = 0x1E;
-#endif
-               chain_offset = (frm_sz - 8) / 4;
-       }
+                               /* Initialize the free, done and pending Qs.
+                                */
+                               Q_INIT(&hd->freeQ, MPT_DONE_Q);
+                               Q_INIT(&hd->doneQ, MPT_DONE_Q);
+                               Q_INIT(&hd->pendingQ, MPT_DONE_Q);
+                               spin_lock_init(&hd->freedoneQlock);
+
+                               mem = hd->memQ;
+                               for (ii=0; ii < sh->can_queue; ii++) {
+                                       freedoneQ = (MPT_DONE_Q *) mem;
+                                       Q_ADD_TAIL(&hd->freeQ.head, freedoneQ, MPT_DONE_Q);
+                                       mem += sizeof(MPT_DONE_Q);
+                               }
 
-       pScsiReq->TargetID = SCpnt->target;
-       pScsiReq->Bus = hd->port;
-       pScsiReq->ChainOffset = chain_offset;
-       pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
-       pScsiReq->CDBLength = SCpnt->cmd_len;
+                               /* Initialize this Scsi_Host
+                                * internal task Q.
+                                */
+                               Q_INIT(&hd->taskQ, MPT_FRAME_HDR);
+                               hd->taskQcnt = 0;
 
-/* We have 256 bytes alloc'd per IO; let's use it. */
-/*     pScsiReq->SenseBufferLength = SNS_LEN(SCpnt);   */
-       pScsiReq->SenseBufferLength = 255;
+                               /* Allocate memory for the device structures.
+                                * A non-Null pointer at an offset
+                                * indicates a device exists.
+                                * max_id = 1 + maximum id (hosts.h)
+                                */
+                               sz = sh->max_id * sizeof(void *);
+                               mem = kmalloc(sz, GFP_ATOMIC);
+                               if (mem == NULL)
+                                       goto done;
 
-       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);
+                               memset(mem, 0, sz);
+                               hd->Targets = (VirtDevice **) mem;
 
-       /*
-        *  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;
+                               dprintk((KERN_INFO "  Targets @ %p, sz=%d\n", hd->Targets, sz));
 
-       /* DataLength */
-       pScsiReq->DataLength = cpu_to_le32(len);
 
-       /* SenseBuffer low address */
-       pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_pool_dma + (my_idx * 256));
+                               /* Clear the TM flags
+                                */
+                               hd->tmPending = 0;
+#ifdef MPT_SCSI_USE_NEW_EH
+                               hd->tmState = TM_STATE_NONE;
+#endif
+                               hd->resetPending = 0;
+                               hd->abortSCpnt = NULL;
+                               hd->tmPtr = NULL;
+                               hd->numTMrequests = 0;
+
+                               /* Clear the pointer used to store
+                                * single-threaded commands, i.e., those
+                                * issued during a bus scan, dv and
+                                * configuration pages.
+                                */
+                               hd->cmdPtr = NULL;
 
-       mptr = (u32 *) &pScsiReq->SGL;
+                               /* Attach the SCSI Host to the IOC structure
+                                */
+                               this->sh = sh;
 
-       /*
-        *  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!
+                               /* Initialize this SCSI Hosts' timers
+                                * To use, set the timer expires field
+                                * and add_timer
                                 */
-                               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;
+                               init_timer(&hd->timer);
+                               hd->timer.data = (unsigned long) hd;
+                               hd->timer.function = mptscsih_timer_expired;
+
+                               init_timer(&hd->TMtimer);
+                               hd->TMtimer.data = (unsigned long) hd;
+                               hd->TMtimer.function = mptscsih_taskmgmt_timeout;
+                               hd->qtag_tick = jiffies;
+
+                               /* Moved Earlier Pam D */
+                               /* this->sh = sh;       */
+
+                               if (hd->is_spi) {
+                                       /* Update with the driver setup
+                                        * values.
+                                        */
+                                       if (hd->ioc->spi_data.maxBusWidth > driver_setup.max_width)
+                                               hd->ioc->spi_data.maxBusWidth = driver_setup.max_width;
+                                       if (hd->ioc->spi_data.minSyncFactor < driver_setup.min_sync_fac)
+                                               hd->ioc->spi_data.minSyncFactor = driver_setup.min_sync_fac;
+
+                                       if (hd->ioc->spi_data.minSyncFactor == MPT_ASYNC)
+                                               hd->ioc->spi_data.maxSyncOffset = 0;
+
+                                       hd->negoNvram = 0;
+#ifdef MPTSCSIH_DISABLE_DOMAIN_VALIDATION
+                                       hd->negoNvram = MPT_SCSICFG_USE_NVRAM;
 #endif
-                                               chain_offset = (frm_sz - 8) / 4;
-                                               chain_sz = frm_sz;
-                                       } else {
-                                               chain_sz = sges_left * 8;
-                                       }
+                                       if (driver_setup.dv == 0)
+                                               hd->negoNvram = MPT_SCSICFG_USE_NVRAM;
 
-                                       /* 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));
+                                       hd->ioc->spi_data.forceDv = 0;
+                                       for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++)
+                                               hd->ioc->spi_data.dvStatus[ii] = MPT_SCSICFG_NEGOTIATE;
 
-               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);
-               }
-       }
+                                       ddvprintk((MYIOC_s_INFO_FMT
+                                               "dv %x width %x factor %x \n",
+                                               hd->ioc->name, driver_setup.dv,
+                                               driver_setup.max_width,
+                                               driver_setup.min_sync_fac));
 
-#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;
+                               mpt_scsi_hosts++;
+                       }
 
-       /* Main banana... */
-       mpt_put_msg_frame(ScsiDoneCtx, hd->ioc->id, mf);
+               }       /* for each adapter port */
 
-       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));
+               this = mpt_adapter_find_next(this);
        }
 
-       dmfprintk((KERN_INFO MYNAM ": Issued SCSI cmd (%p)\n", SCpnt));
+done:
+       if (mpt_scsi_hosts > 0)
+               register_reboot_notifier(&mptscsih_notifier);
 
-       return 0;
+       return mpt_scsi_hosts;
 }
 
-#ifdef MPT_SCSI_USE_NEW_EH             /* { */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*
-    mptscsih_abort
-    Returns: 0=SUCCESS, else FAILED
-*/
+    static char *info_kbuf = NULL;
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
- *     mptscsih_abort - Abort linux Scsi_Cmnd routine, new_eh variant
- *     @SCpnt: Pointer to Scsi_Cmnd structure, IO to be aborted
+ *     mptscsih_release - Unregister SCSI host from linux scsi mid-layer
+ *     @host: Pointer to Scsi_Host structure
  *
- *     (linux Scsi_Host_Template.eh_abort_handler routine)
+ *     (linux Scsi_Host_Template.release routine)
+ *     This routine releases all resources associated with the SCSI host
+ *     adapter.
  *
- *     Returns SUCCESS or FAILED.  
+ *     Returns 0 for success.
  */
 int
-mptscsih_abort(Scsi_Cmnd * SCpnt)
+mptscsih_release(struct Scsi_Host *host)
 {
-       MPT_FRAME_HDR   *mf;
-       SCSITaskMgmt_t  *pScsiTm;
        MPT_SCSI_HOST   *hd;
-       u32             *msg;
-       u32              ctx2abort;
-       int              i;
+       int              count;
        unsigned long    flags;
 
-       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 *) host->hostdata;
 
-       hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata;
+#ifndef MPT_SCSI_USE_NEW_EH
+#ifndef MPTSCSIH_DISABLE_DOMAIN_VALIDATION
+       spin_lock_irqsave(&dvtaskQ_lock, flags);
+       dvtaskQ_release = 1;
+       spin_unlock_irqrestore(&dvtaskQ_lock, flags);
+#endif
 
-       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;
+       count = 10 * HZ;
+       spin_lock_irqsave(&mytaskQ_lock, flags);
+       if (mytaskQ_bh_active) {
+               spin_unlock_irqrestore(&mytaskQ_lock, flags);
+               dprintk((KERN_INFO MYNAM ": Info: Zapping TaskMgmt thread!\n"));
+               clean_taskQ(hd);
+
+               while(mytaskQ_bh_active && --count) {
+                       set_current_state(TASK_INTERRUPTIBLE);
+                       schedule_timeout(1);
+               }
+       } else {
+               spin_unlock_irqrestore(&mytaskQ_lock, flags);
        }
+       if (!count)
+               printk(KERN_ERR MYNAM ": ERROR - TaskMgmt thread still active!\n");
 
-       pScsiTm = (SCSITaskMgmt_t *) mf;
-       msg = (u32 *) mf;
+#endif
 
-       pScsiTm->TargetID = SCpnt->target;
-       pScsiTm->Bus = hd->port;
-       pScsiTm->ChainOffset = 0;
-       pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
+#ifndef MPTSCSIH_DISABLE_DOMAIN_VALIDATION
+       /* Check DV thread active */
+       count = 10 * HZ;
+       spin_lock_irqsave(&dvtaskQ_lock, flags);
+       if (dvtaskQ_active) {
+               spin_unlock_irqrestore(&dvtaskQ_lock, flags);
+               while(dvtaskQ_active && --count) {
+                       set_current_state(TASK_INTERRUPTIBLE);
+                       schedule_timeout(1);
+               }
+       } else {
+               spin_unlock_irqrestore(&dvtaskQ_lock, flags);
+       }
+       if (!count)
+               printk(KERN_ERR MYNAM ": ERROR - DV thread still active!\n");
+#if defined(MPT_DEBUG_DV) || defined(MPT_DEBUG_DV_TINY)
+       else
+               printk(KERN_ERR MYNAM ": DV thread orig %d, count %d\n", 10 * HZ, count);
+#endif
+#endif
 
-       pScsiTm->Reserved = 0;
-       pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK;
-       pScsiTm->Reserved1 = 0;
-       pScsiTm->MsgFlags = 0;
+       unregister_reboot_notifier(&mptscsih_notifier);
 
-       for (i = 0; i < 8; i++) {
-               u8 val = 0;
-               if (i == 1)
-                       val = SCpnt->lun;
-               pScsiTm->LUN[i] = val;
-       }
+       if (hd != NULL) {
+               int sz1, sz2, sz3, sztarget=0;
+               int szchain = 0;
+               int szQ = 0;
+               int scale;
 
-       for (i = 0; i < 7; i++)
-               pScsiTm->Reserved2[i] = 0;
+               /* Synchronize disk caches
+                */
+               (void) mptscsih_synchronize_cache(hd, 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);
-       if (ctx2abort == -1) {
-               printk(KERN_ERR MYNAM ": ERROR - ScsiLookup fail(#2) for SCpnt=%p\n", SCpnt);
-               SCpnt->result = DID_SOFT_ERROR << 16;
-               spin_lock_irqsave(SCpnt->host->host_lock, flags);
-               SCpnt->scsi_done(SCpnt);
-               spin_unlock_irqrestore(SCpnt->host->host_lock, flags);
-               mpt_free_msg_frame(ScsiTaskCtx, hd->ioc->id, mf);
-       } else {
-               dprintk((KERN_INFO MYNAM ":DbG: ctx2abort = %08x\n", ctx2abort));
-               pScsiTm->TaskMsgContext = ctx2abort;
+               sz1 = sz2 = sz3 = 0;
 
+               if (hd->ioc->req_sz <= 64)
+                       scale = MPT_SG_REQ_64_SCALE;
+               else if (hd->ioc->req_sz <= 96)
+                       scale = MPT_SG_REQ_96_SCALE;
+               else
+                       scale = MPT_SG_REQ_128_SCALE;
 
-               /* MPI v0.10 requires SCSITaskMgmt requests be sent via Doorbell/handshake
-                       mpt_put_msg_frame(hd->ioc->id, mf);
-               */
-               if ((i = mpt_send_handshake_request(ScsiTaskCtx, hd->ioc->id,
-                                       sizeof(SCSITaskMgmt_t), msg))
-                   != 0) {
-                       printk(KERN_WARNING MYNAM
-                                       ": WARNING[2] - IOC error (%d) processing TaskMgmt request (mf=%p:sc=%p)\n",
-                                       i, mf, SCpnt);
-                       SCpnt->result = DID_SOFT_ERROR << 16;
-                       spin_lock_irqsave(SCpnt->host->host_lock, flags);
-                       SCpnt->scsi_done(SCpnt);
-                       spin_unlock_irqrestore(SCpnt->host->host_lock, flags);
-                       mpt_free_msg_frame(ScsiTaskCtx, hd->ioc->id, mf);
+               if (hd->ScsiLookup != NULL) {
+                       sz1 = hd->ioc->req_depth * sizeof(void *);
+                       kfree(hd->ScsiLookup);
+                       hd->ScsiLookup = NULL;
                }
-       }
 
-       //return SUCCESS;
-       return FAILED;
-}
+               if (hd->ReqToChain != NULL) {
+                       szchain += scale * hd->ioc->req_depth * sizeof(int);
+                       kfree(hd->ReqToChain);
+                       hd->ReqToChain = NULL;
+               }
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/**
- *     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;
-       unsigned long    flags;
+               if (hd->ChainToChain != NULL) {
+                       szchain += scale * hd->ioc->req_depth * sizeof(int);
+                       kfree(hd->ChainToChain);
+                       hd->ChainToChain = NULL;
+               }
 
-       printk(KERN_WARNING MYNAM ": Attempting _TARGET_RESET (%p)\n", SCpnt);
-       printk(KERN_WARNING MYNAM ": IOs outstanding = %d\n", atomic_read(&queue_depth));
+               if (hd->ChainBuffer != NULL) {
+                       sz2 = scale * hd->ioc->req_depth * hd->ioc->req_sz;
+                       szchain += sz2;
 
-       hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata;
+                       pci_free_consistent(hd->ioc->pcidev, sz2,
+                                   hd->ChainBuffer, hd->ChainBufferDMA);
+                       hd->ChainBuffer = NULL;
+               }
 
-       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;
-       }
+               if (hd->memQ != NULL) {
+                       szQ = host->can_queue * sizeof(MPT_DONE_Q);
+                       kfree(hd->memQ);
+                       hd->memQ = NULL;
+               }
 
-       pScsiTm = (SCSITaskMgmt_t *) mf;
-       msg = (u32*)mf;
+               if (hd->Targets != NULL) {
+                       int max, ii;
 
-       pScsiTm->TargetID = SCpnt->target;
-       pScsiTm->Bus = hd->port;
-       pScsiTm->ChainOffset = 0;
-       pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
+                       /*
+                        * Free any target structures that were allocated.
+                        */
+                       if (hd->is_spi) {
+                               max = MPT_MAX_SCSI_DEVICES;
+                       } else {
+                               max = MPT_MAX_FC_DEVICES;
+                       }
+                       for (ii=0; ii < max; ii++) {
+                               if (hd->Targets[ii]) {
+                                       kfree(hd->Targets[ii]);
+                                       hd->Targets[ii] = NULL;
+                                       sztarget += sizeof(VirtDevice);
+                               }
+                       }
 
-       pScsiTm->Reserved = 0;
-       pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
-       pScsiTm->Reserved1 = 0;
-       pScsiTm->MsgFlags = 0;
+                       /*
+                        * Free pointer array.
+                        */
+                       sz3 = max * sizeof(void *);
+                       kfree(hd->Targets);
+                       hd->Targets = NULL;
+               }
 
-       /* _TARGET_RESET goes to LUN 0 always! */
-       for (i = 0; i < 8; i++)
-               pScsiTm->LUN[i] = 0;
+               dprintk((MYIOC_s_INFO_FMT "Free'd ScsiLookup (%d), chain (%d) and Target (%d+%d) memory\n",
+                               hd->ioc->name, sz1, szchain, sz3, sztarget));
+               dprintk(("Free'd done and free Q (%d) memory\n", szQ));
+       }
+       /* NULL the Scsi_Host pointer
+        */
+       hd->ioc->sh = NULL;
+       scsi_unregister(host);
 
-       /* Control: No data direction, set task mgmt bit? */
-       for (i = 0; i < 7; i++)
-               pScsiTm->Reserved2[i] = 0;
+       if (mpt_scsi_hosts) {
+               if (--mpt_scsi_hosts == 0) {
+                       mpt_reset_deregister(ScsiDoneCtx);
+                       dprintk((KERN_INFO MYNAM ": Deregistered for IOC reset notifications\n"));
 
-       pScsiTm->TaskMsgContext = cpu_to_le32(0);
+                       mpt_event_deregister(ScsiDoneCtx);
+                       dprintk((KERN_INFO MYNAM ": Deregistered for IOC event notifications\n"));
 
-/* MPI v0.10 requires SCSITaskMgmt requests be sent via Doorbell/handshake
-       mpt_put_msg_frame(hd->ioc->id, mf);
-*/
-/* FIXME!  Check return status! */
-       if ((i = mpt_send_handshake_request(ScsiTaskCtx, hd->ioc->id,
-                               sizeof(SCSITaskMgmt_t), msg))
-           != 0) {
-               printk(KERN_WARNING MYNAM
-                               ": WARNING[3] - IOC error (%d) processing TaskMgmt request (mf=%p:sc=%p)\n",
-                               i, mf, SCpnt);
-               SCpnt->result = DID_SOFT_ERROR << 16;
-               spin_lock_irqsave(SCpnt->host->host_lock, flags);
-               SCpnt->scsi_done(SCpnt);
-               spin_unlock_irqrestore(SCpnt->host->host_lock, flags);
-               mpt_free_msg_frame(ScsiTaskCtx, hd->ioc->id, mf);
+                       mpt_deregister(ScsiScanDvCtx);
+                       mpt_deregister(ScsiTaskCtx);
+                       mpt_deregister(ScsiDoneCtx);
+
+                       if (info_kbuf != NULL)
+                               kfree(info_kbuf);
+               }
        }
 
-       //return SUCCESS;
-       return FAILED;
+       return 0;
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
- *     mptscsih_bus_reset - Perform a SCSI BUS_RESET!  new_eh variant
- *     @SCpnt: Pointer to Scsi_Cmnd structure, IO which reset is due to
+ *     mptscsih_halt - Process the reboot notification
+ *     @nb: Pointer to a struct notifier_block (ignored)
+ *     @event: event (SYS_HALT, SYS_RESTART, SYS_POWER_OFF)
+ *     @buf: Pointer to a data buffer (ignored)
  *
- *     (linux Scsi_Host_Template.eh_bus_reset_handler routine)
+ *     This routine called if a system shutdown or reboot is to occur.
  *
- *     Returns SUCCESS or FAILED.
+ *     Return NOTIFY_DONE if this is something other than a reboot message.
+ *             NOTIFY_OK if this is a reboot message.
  */
-int
-mptscsih_bus_reset(Scsi_Cmnd * SCpnt)
+static int
+mptscsih_halt(struct notifier_block *nb, ulong event, void *buf)
 {
-       MPT_FRAME_HDR   *mf;
-       SCSITaskMgmt_t  *pScsiTm;
-       MPT_SCSI_HOST   *hd;
-       u32             *msg;
-       int              i;
-       unsigned long    flags;
-
-       printk(KERN_WARNING MYNAM ": Attempting _BUS_RESET (%p)\n", SCpnt);
-       printk(KERN_WARNING MYNAM ": IOs outstanding = %d\n", atomic_read(&queue_depth));
+       MPT_ADAPTER *ioc = NULL;
+       MPT_SCSI_HOST *hd = NULL;
 
-       hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata;
+       /* Ignore all messages other than reboot message
+        */
+       if ((event != SYS_RESTART) && (event != SYS_HALT)
+               && (event != SYS_POWER_OFF))
+               return (NOTIFY_DONE);
 
-       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;
+       for (ioc = mpt_adapter_find_first(); ioc != NULL; ioc = mpt_adapter_find_next(ioc)) {
+               /* Flush the cache of this adapter
+                */
+               if (ioc->sh) {
+                       hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
+                       if (hd) {
+                               mptscsih_synchronize_cache(hd, 0);
+                       }
+               }
        }
 
-       pScsiTm = (SCSITaskMgmt_t *) mf;
-       msg = (u32 *) mf;
+       unregister_reboot_notifier(&mptscsih_notifier);
+       return NOTIFY_OK;
+}
 
-       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;
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     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;
 
-       for (i = 0; i < 8; i++)
-               pScsiTm->LUN[i] = 0;
+       if (info_kbuf == NULL)
+               if ((info_kbuf = kmalloc(0x1000 /* 4Kb */, GFP_KERNEL)) == NULL)
+                       return info_kbuf;
 
-       /* Control: No data direction, set task mgmt bit? */
-       for (i = 0; i < 7; i++)
-               pScsiTm->Reserved2[i] = 0;
+       h = (MPT_SCSI_HOST *)SChost->hostdata;
+       info_kbuf[0] = '\0';
+       mpt_print_ioc_summary(h->ioc, info_kbuf, &size, 0, 0);
+       info_kbuf[size-1] = '\0';
 
-       pScsiTm->TaskMsgContext = cpu_to_le32(0);
+       return info_kbuf;
+}
 
-/* MPI v0.10 requires SCSITaskMgmt requests be sent via Doorbell/handshake
-       mpt_put_msg_frame(hd->ioc->id, mf);
-*/
-/* FIXME!  Check return status! */
-       if ((i = mpt_send_handshake_request(ScsiTaskCtx, hd->ioc->id,
-                               sizeof(SCSITaskMgmt_t), msg))
-           != 0) {
-               printk(KERN_WARNING MYNAM
-                               ": WARNING[4] - IOC error (%d) processing TaskMgmt request (mf=%p:sc=%p)\n",
-                               i, mf, SCpnt);
-               SCpnt->result = DID_SOFT_ERROR << 16;
-               spin_lock_irqsave(SCpnt->host->host_lock, flags);
-               SCpnt->scsi_done(SCpnt);
-               spin_unlock_irqrestore(SCpnt->host->host_lock, flags);
-               mpt_free_msg_frame(ScsiTaskCtx, hd->ioc->id, mf);
-       }
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+       static int max_qd = 1;
+#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++;
 
-       return SUCCESS;
+       index_log[i & (128 - 1)] = req_ent;
 }
+#else
+#define ADD_INDEX_LOG(req_ent) do { } while(0)
+#endif
+
+#ifdef DROP_TEST
+#define DROP_IOC       1       /* IOC to force failures */
+#define DROP_TARGET    3       /* Target ID to force failures */
+#define        DROP_THIS_CMD   10000   /* iteration to drop command */
+static int dropCounter = 0;
+static int dropTestOK = 0;     /* num did good */
+static int dropTestBad = 0;    /* num did bad */
+static int dropTestNum = 0;    /* total = good + bad + incomplete */
+static int numTotCmds = 0;
+static MPT_FRAME_HDR *dropMfPtr = NULL;
+static int numTMrequested = 0;
+#endif
 
-#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
+/*
+ *     mptscsih_put_msgframe - Wrapper routine to post message frame to F/W.
+ *     @context: Call back context (ScsiDoneCtx, ScsiScanDvCtx) 
+ *     @id: IOC id number 
+ *     @mf: Pointer to message frame 
  *
- *     (linux Scsi_Host_Template.eh_host_reset_handler routine)
+ *     Handles the call to mptbase for posting request and queue depth 
+ *     tracking.
  *
- *     Returns SUCCESS or FAILED.
+ *     Returns none.
  */
-int
-mptscsih_host_reset(Scsi_Cmnd * SCpnt)
+static void
+mptscsih_put_msgframe(int context, int id, MPT_FRAME_HDR *mf)
 {
-       return FAILED;
+       /* Main banana... */
+       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));
+       }
+
+       mpt_put_msg_frame(context, id, mf);
+
+       return;
 }
-#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
+ *     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.abort routine)
+ *     (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 SCSI_ABORT_{SUCCESS,BUSY,PENDING}.
+ *     Returns 0. (rtn value discarded by linux scsi mid-layer)
  */
 int
-mptscsih_old_abort(Scsi_Cmnd *SCpnt)
+mptscsih_qcmd(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
 {
        MPT_SCSI_HOST           *hd;
        MPT_FRAME_HDR           *mf;
-       struct tq_struct        *ptaskfoo;
+       SCSIIORequest_t         *pScsiReq;
+       VirtDevice              *pTarget;
+       MPT_DONE_Q              *buffer = NULL;
        unsigned long            flags;
+       int      target;
+       int      lun;
+       int      datadir;
+       u32      datalen;
+       u32      scsictl;
+       u32      scsidir;
+       u32      qtag;
+       u32      cmd_len;
+       int      my_idx;
+       int      ii;
+       int      rc;
+       int      did_errcode;
+       int      issueCmd;
 
-       printk(KERN_WARNING MYNAM ": Scheduling _ABORT SCSI IO (=%p)\n", SCpnt);
-       printk(KERN_WARNING MYNAM ": IOs outstanding = %d\n", atomic_read(&queue_depth));
+       did_errcode = 0;
+       hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata;
+       target = SCpnt->target;
+       lun = SCpnt->lun;
+       SCpnt->scsi_done = done;
 
-       if ((hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata) == NULL) {
-               SCpnt->result = DID_ABORT << 16;
-               SCpnt->scsi_done(SCpnt);
-               return SCSI_ABORT_SUCCESS;
-       }
+       pTarget = hd->Targets[target];
 
-       /*
-        *  Check to see if there's already an ABORT queued for this guy.
+       dmfprintk((MYIOC_s_INFO_FMT "qcmd: SCpnt=%p, done()=%p\n",
+                       (hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt, 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.
         */
-       mf = search_taskQ(0,SCpnt,MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK);
-       if (mf != NULL) {
-               return SCSI_ABORT_PENDING;
+       if (SCpnt->cmnd[0] == REQUEST_SENSE) {
+               u8 *dest = NULL;
+               int sz;
+
+               if (pTarget && (pTarget->tflags & MPT_TARGET_FLAGS_VALID_SENSE)) {
+                       pTarget->tflags &= ~MPT_TARGET_FLAGS_VALID_SENSE;       //sjr-moved-here
+                       if (!SCpnt->use_sg) {
+                               dest = SCpnt->request_buffer;
+                       } else {
+                               struct scatterlist *sg = (struct scatterlist *) SCpnt->request_buffer;
+                               if (sg)
+                                       dest = (u8 *)(ulong)sg_dma_address(sg);
+                       }
+
+                       if (dest) {
+                               sz = MIN (SCSI_STD_SENSE_BYTES, SCpnt->request_bufflen);
+                               memcpy(dest, pTarget->sense, sz);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
+                               SCpnt->resid = SCpnt->request_bufflen - sz;
+#endif
+                               SCpnt->result = 0;
+                               SCpnt->scsi_done(SCpnt);
+
+                               //sjr-moved-up//pTarget->tflags &= ~MPT_TARGET_FLAGS_VALID_SENSE;
+
+                               return 0;
+                       }
+               }
        }
 
-       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;
+       if (hd->resetPending) {
+               /* Prevent new commands from being issued
+                * while reloading the FW.
+                */
+               did_errcode = 1;
+               goto did_error;
        }
 
        /*
-        *  Add ourselves to (end of) mpt_scsih_taskQ.
-        *  Check to see if our _bh is running.  If NOT, schedule it.
+        *  Put together a MPT SCSI request...
         */
-       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);
+       if ((mf = mpt_get_msg_frame(ScsiDoneCtx, hd->ioc->id)) == NULL) {
+               dprintk((MYIOC_s_WARN_FMT "QueueCmd, no msg frames!!\n",
+                               hd->ioc->name));
+               did_errcode = 2;
+               goto did_error;
        }
-       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;
+       pScsiReq = (SCSIIORequest_t *) mf;
 
-       printk(KERN_WARNING MYNAM ": Scheduling _BUS_RESET (=%p)\n", SCpnt);
-       printk(KERN_WARNING MYNAM ": IOs outstanding = %d\n", atomic_read(&queue_depth));
+       my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
 
-       if ((hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata) == NULL) {
-               SCpnt->result = DID_RESET << 16;
-               SCpnt->scsi_done(SCpnt);
-               return SCSI_RESET_SUCCESS;
-       }
+       ADD_INDEX_LOG(my_idx);
 
        /*
-        *  Check to see if there's already a BUS_RESET queued for this guy.
+        *  The scsi layer should be handling this stuff
+        *  (In 2.3.x it does -DaveM)
         */
-       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;
+       /*  BUG FIX!  19991030 -sralston
+        *    TUR's being issued with scsictl=0x02000000 (DATA_IN)!
+        *    Seems we may receive a buffer (datalen>0) even when there
+        *    will be no data transfer!  GRRRRR...
+        */
+       datadir = mptscsih_io_direction(SCpnt);
+       if (datadir == SCSI_DATA_READ) {
+               datalen = SCpnt->request_bufflen;
+               scsidir = MPI_SCSIIO_CONTROL_READ;      /* DATA IN  (host<--ioc<--dev) */
+       } else if (datadir == SCSI_DATA_WRITE) {
+               datalen = SCpnt->request_bufflen;
+               scsidir = MPI_SCSIIO_CONTROL_WRITE;     /* DATA OUT (host-->ioc-->dev) */
+       } else {
+               datalen = 0;
+               scsidir = MPI_SCSIIO_CONTROL_NODATATRANSFER;
        }
 
-       /*
-        *  Add ourselves to (end of) mpt_scsih_taskQ.
-        *  Check to see if our _bh is running.  If NOT, schedule it.
+       /* Default to untagged. Once a target structure has been allocated,
+        * use the Inquiry data to determine if device supports tagged.
         */
-       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;
+       qtag = MPI_SCSIIO_CONTROL_UNTAGGED;
+       if (pTarget && (pTarget->tflags & MPT_TARGET_FLAGS_Q_YES)
+                       && (SCpnt->device->tagged_supported)) {
                /*
-                *  Oh how cute, no alloc/free/mgmt needed if we use
-                *  (bottom/unused portion of) MPT request frame.
+                *  Some drives are too stupid to handle fairness issues
+                *  with tagged queueing. We throw in the odd ordered
+                *  tag to stop them starving themselves.
                 */
-               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);
+               if ((jiffies - hd->qtag_tick) > (5*HZ)) {
+                       qtag = MPI_SCSIIO_CONTROL_ORDEREDQ;
+                       hd->qtag_tick = jiffies;
+               }
+               else
+                       qtag = MPI_SCSIIO_CONTROL_SIMPLEQ;
        }
-       spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags);
+       scsictl = scsidir | qtag;
 
-       return SCSI_RESET_PENDING;
-}
+       /* Use the above information to set up the message frame
+        */
+       pScsiReq->TargetID = target;
+       pScsiReq->Bus = hd->port;
+       pScsiReq->ChainOffset = 0;
+       pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
+       pScsiReq->CDBLength = SCpnt->cmd_len;
+       pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
+       pScsiReq->Reserved = 0;
+       pScsiReq->MsgFlags = mpt_msg_flags();
+       pScsiReq->LUN[0] = 0;
+       pScsiReq->LUN[1] = 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);
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*
- *     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;
+       /*
+        *  Write SCSI CDB into the message
+        */
+       cmd_len = SCpnt->cmd_len;
+       for (ii=0; ii < cmd_len; ii++)
+               pScsiReq->CDB[ii] = SCpnt->cmnd[ii];
+       for (ii=cmd_len; ii < 16; ii++)
+               pScsiReq->CDB[ii] = 0;
 
-       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);
+       /* DataLength */
+       pScsiReq->DataLength = cpu_to_le32(datalen);
 
-       while (1) {
-               current->state = TASK_INTERRUPTIBLE;
-               schedule_timeout(HZ/4);
+       /* SenseBuffer low address */
+       pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma
+                                          + (my_idx * MPT_SENSE_BUFFER_ALLOC));
 
-               /*
-                *  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);
+       /* Now add the SG list
+        * Always have a SGE even if null length.
+        */
+       rc = SUCCESS;
+       if (datalen == 0) {
+               /* Add a NULL SGE */
+               mpt_add_sge((char *)&pScsiReq->SGL, MPT_SGE_FLAGS_SSIMPLE_READ | 0,
+                       (dma_addr_t) -1);
+       } else {
+               /* Add a 32 or 64 bit SGE */
+               rc = mptscsih_AddSGE(hd, SCpnt, pScsiReq, my_idx);
+       }
 
-               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;
-               }
-               hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata;
-               pScsiTm = (SCSITaskMgmt_t *) mf;
 
-               for (i = 0; i < 8; i++) {
-                       pScsiTm->LUN[i] = 0;
-               }
+       if (rc == SUCCESS) {
+               hd->ScsiLookup[my_idx] = SCpnt;
+               SCpnt->host_scribble = NULL;
+
+#ifdef DROP_TEST
+               numTotCmds++;
+               /* If the IOC number and target match, increment
+                * counter. If counter matches DROP_THIS, do not
+                * issue command to FW to force a reset.
+                * Save the MF pointer so we can free resources
+                * when task mgmt completes.
+                */
+               if ((hd->ioc->id == DROP_IOC) && (target == DROP_TARGET)) {
+                       dropCounter++;
 
-               task_type = mf->u.frame.linkage.arg1;
-               if (task_type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {
-                       printk(KERN_WARNING MYNAM ": Attempting _ABORT SCSI IO! (mf=%p:sc=%p)\n",
-                                       mf, SCpnt);
+                       if (dropCounter == DROP_THIS_CMD) {
+                               dropCounter = 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);
-                       if (ctx2abort == -1) {
-                               printk(KERN_ERR MYNAM ": ERROR - ScsiLookup fail(#1) for SCpnt=%p\n", SCpnt);
-                               SCpnt->result = DID_SOFT_ERROR << 16;
-                               spin_lock_irqsave(SCpnt->host->host_lock, flags);
-                               SCpnt->scsi_done(SCpnt);
-                               spin_unlock_irqrestore(SCpnt->host->host_lock, flags);
-                               mpt_free_msg_frame(ScsiTaskCtx, hd->ioc->id, mf);
-                               continue;
+                               /* If global is set, then we are already
+                                * doing something - so keep issuing commands.
+                                */
+                               if (dropMfPtr == NULL) {
+                                       dropTestNum++;
+                                       dropMfPtr = mf;
+                                       atomic_inc(&queue_depth);
+                                       printk(MYIOC_s_INFO_FMT
+                                               "Dropped SCSI cmd (%p)\n",
+                                               hd->ioc->name, SCpnt);
+                                       printk("mf (%p) req (%4x) tot cmds (%d)\n",
+                                               mf, my_idx, numTotCmds);
+
+                                       return 0;
+                               }
                        }
-                       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=%p:sc=%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));
-
-               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;
+               /* SCSI specific processing */
+               issueCmd = 1;
+               if (hd->is_spi) {
+                       int dvStatus = hd->ioc->spi_data.dvStatus[target];
+
+                       if (dvStatus || hd->ioc->spi_data.forceDv) {
+
+                               /* Write SDP1 on this I/O to this target */
+                               if (dvStatus & MPT_SCSICFG_NEGOTIATE) {
+                                       mptscsih_writeSDP1(hd, 0, target, hd->negoNvram);
+                                       dvStatus &= ~MPT_SCSICFG_NEGOTIATE;
+                                       hd->ioc->spi_data.dvStatus[target] =  dvStatus;
+                               } else if (dvStatus & MPT_SCSICFG_BLK_NEGO) {
+                                       mptscsih_writeSDP1(hd, 0, target, MPT_SCSICFG_BLK_NEGO);
+                                       dvStatus &= ~MPT_SCSICFG_BLK_NEGO;
+                                       hd->ioc->spi_data.dvStatus[target] =  dvStatus;
+                               }
 
-               dprintk((KERN_INFO MYNAM ":DbG: ctx2abort = %08x\n", ctx2abort));
-               pScsiTm->TaskMsgContext = ctx2abort;
+#ifndef MPTSCSIH_DISABLE_DOMAIN_VALIDATION
+                               if ((dvStatus & MPT_SCSICFG_NEED_DV) || hd->ioc->spi_data.forceDv) {
+                                       unsigned long lflags;
+                                       /* Schedule DV if necessary */
+                                       spin_lock_irqsave(&dvtaskQ_lock, lflags);
+                                       if (!dvtaskQ_active) {
+                                               dvtaskQ_active = 1;
+                                               spin_unlock_irqrestore(&dvtaskQ_lock, lflags);
+                                               mptscsih_dvTask.sync = 0;
+                                               mptscsih_dvTask.routine = mptscsih_domainValidation;
+                                               mptscsih_dvTask.data = (void *) hd;
+
+                                               SCHEDULE_TASK(&mptscsih_dvTask);
+                                       } else {
+                                               spin_unlock_irqrestore(&dvtaskQ_lock, lflags);
+                                       }
+                                       hd->ioc->spi_data.forceDv = 0;
+                               }
 
-               /* Control: No data direction, set task mgmt bit? */
+                               /* Trying to do DV to this target, extend timeout.
+                                * Wait to issue intil flag is clear 
+                                */
+                               if (dvStatus & MPT_SCSICFG_DV_PENDING) {
+                                       mod_timer(&SCpnt->eh_timeout, jiffies + 40 * HZ);
+                                       issueCmd = 0;
+                               }
+#endif
+                       }
+               }
 
-               /*
-                *  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.   :-(
-                */
-               if ((i = mpt_send_handshake_request(ScsiTaskCtx, hd->ioc->id,
-                                       sizeof(SCSITaskMgmt_t), (u32*) mf))
-                   != 0) {
-                       printk(KERN_WARNING MYNAM ": WARNING[1] - IOC error (%d) processing TaskMgmt request (mf=%p:sc=%p)\n", i, mf, SCpnt);
-                       SCpnt->result = DID_SOFT_ERROR << 16;
-                       spin_lock_irqsave(SCpnt->host->host_lock, flags);
-                       SCpnt->scsi_done(SCpnt);
-                       spin_unlock_irqrestore(SCpnt->host->host_lock, flags);
-                       mpt_free_msg_frame(ScsiTaskCtx, hd->ioc->id, mf);
+               if (issueCmd) {
+                       mptscsih_put_msgframe(ScsiDoneCtx, hd->ioc->id, mf);
+                       dmfprintk((MYIOC_s_INFO_FMT "Issued SCSI cmd (%p)\n",
+                                       hd->ioc->name, SCpnt));
                } else {
-                       /* Spin-Wait for TaskMgmt complete!!! */
-                       while (mpt_scsih_active_taskmgmt_mf != NULL) {
-                               current->state = TASK_INTERRUPTIBLE;
-                               schedule_timeout(HZ/4);
+                       ddvtprintk((MYIOC_s_INFO_FMT "Pending SCSI cmd (%p)\n",
+                                       hd->ioc->name, SCpnt));
+                       /* Place this command on the pendingQ if possible */
+                       spin_lock_irqsave(&hd->freedoneQlock, flags);
+                       if (!Q_IS_EMPTY(&hd->freeQ)) {
+                               buffer = hd->freeQ.head;
+                               Q_DEL_ITEM(buffer);
+
+                               /* Save the mf pointer
+                                */
+                               buffer->argp = (void *)mf;
+
+                               /* Add to the pendingQ
+                                */
+                               Q_ADD_TAIL(&hd->pendingQ.head, buffer, MPT_DONE_Q);
+                               spin_unlock_irqrestore(&hd->freedoneQlock, flags);
+                       } else {
+                               spin_unlock_irqrestore(&hd->freedoneQlock, flags);
+                               SCpnt->result = (DID_BUS_BUSY << 16);
+                               SCpnt->scsi_done(SCpnt);
                        }
                }
+       } else {
+               mptscsih_freeChainBuffers(hd, my_idx);
+               mpt_free_msg_frame(ScsiDoneCtx, hd->ioc->id, mf);
+               did_errcode = 3;
+               goto did_error;
        }
 
-       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 0;
 
-       return;
-}
+did_error:
+       dprintk((MYIOC_s_WARN_FMT "_qcmd did_errcode=%d (sc=%p)\n",
+                       hd->ioc->name, did_errcode, SCpnt));
+       /* Just wish OS to issue a retry */
+       SCpnt->result = (DID_BUS_BUSY << 16);
+       spin_lock_irqsave(&hd->freedoneQlock, flags);
+       if (!Q_IS_EMPTY(&hd->freeQ)) {
+               buffer = hd->freeQ.head;
+               Q_DEL_ITEM(buffer);
+
+               /* Set the Scsi_Cmnd pointer
+                */
+               buffer->argp = (void *)SCpnt;
 
-#endif         /* } */
+               /* Add to the doneQ
+                */
+               Q_ADD_TAIL(&hd->doneQ.head, buffer, MPT_DONE_Q);
+               spin_unlock_irqrestore(&hd->freedoneQlock, flags);
+       } else {
+               spin_unlock_irqrestore(&hd->freedoneQlock, flags);
+               SCpnt->scsi_done(SCpnt);
+       }
+
+       return 0;
+}
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/**
- *     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.
+/*
+ *     mptscsih_AddSGE - Add a SGE (plus chain buffers) to the
+ *     SCSIIORequest_t Message Frame.
+ *     @hd: Pointer to MPT_SCSI_HOST structure
+ *     @SCpnt: Pointer to Scsi_Cmnd structure
+ *     @pReq: Pointer to SCSIIORequest_t structure
  *
- *     Returns 1 indicating alloc'd request frame ptr should be freed.
+ *     Returns ...
  */
 static int
-mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r)
+mptscsih_AddSGE(MPT_SCSI_HOST *hd, Scsi_Cmnd *SCpnt,
+                                SCSIIORequest_t *pReq, int req_idx)
 {
-       SCSITaskMgmtReply_t     *pScsiTmReply;
-       SCSITaskMgmt_t          *pScsiTmReq;
-       u8                       tmType;
-#ifndef MPT_SCSI_USE_NEW_EH
-       unsigned long            flags;
-#endif
+       char    *psge;
+       char    *chainSge;
+       struct scatterlist *sg;
+       int      frm_sz;
+       int      sges_left, sg_done;
+       int      chain_idx = MPT_HOST_NO_CHAIN;
+       int      sgeOffset;
+       int      numSgeSlots, numSgeThisFrame;
+       u32      sgflags, sgdir, thisxfer = 0;
+       int      chain_dma_off = 0;
+       int      newIndex;
+       int      ii;
+       dma_addr_t v2;
+
+       sgdir = le32_to_cpu(pReq->Control) & MPI_SCSIIO_CONTROL_DATADIRECTION_MASK;
+       if (sgdir == MPI_SCSIIO_CONTROL_WRITE)  {
+               sgdir = MPT_TRANSFER_HOST_TO_IOC;
+       } else {
+               sgdir = MPT_TRANSFER_IOC_TO_HOST;
+       }
 
-       dprintk((KERN_INFO MYNAM ": SCSI TaskMgmt completed mf=%p, r=%p\n",
-                mf, r));
+       psge = (char *) &pReq->SGL;
+       frm_sz = hd->ioc->req_sz;
 
-#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;
+       /* Map the data portion, if any.
+        * sges_left  = 0 if no data transfer.
+        */
+       sges_left = SCpnt->use_sg;
+       if (SCpnt->use_sg) {
+               sges_left = pci_map_sg(hd->ioc->pcidev,
+                              (struct scatterlist *) SCpnt->request_buffer,
+                              SCpnt->use_sg,
+                              scsi_to_pci_dma_dir(SCpnt->sc_data_direction));
+       } else if (SCpnt->request_bufflen) {
+               dma_addr_t       buf_dma_addr;
+               scPrivate       *my_priv;
+
+               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. */
+               my_priv = (scPrivate *) &SCpnt->SCp;
+               my_priv->p1 = (void *)(ulong) buf_dma_addr;
+
+               dsgprintk((MYIOC_s_INFO_FMT "SG: non-SG for %p, len=%d\n",
+                               hd->ioc->name, SCpnt, SCpnt->request_bufflen));
+
+               mpt_add_sge((char *) &pReq->SGL,
+                       0xD1000000|MPT_SGE_FLAGS_ADDRESSING|sgdir|SCpnt->request_bufflen,
+                       buf_dma_addr);
+
+               return SUCCESS;
        }
 
-#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;
+       /* Handle the SG case.
+        */
+       sg = (struct scatterlist *) SCpnt->request_buffer;
+       sg_done  = 0;
+       sgeOffset = sizeof(SCSIIORequest_t) - sizeof(SGE_IO_UNION);
+       chainSge = NULL;
+
+       /* Prior to entering this loop - the following must be set
+        * current MF:  sgeOffset (bytes)
+        *              chainSge (Null if original MF is not a chain buffer)
+        *              sg_done (num SGE done for this MF)
+        */
+
+nextSGEset:
+       numSgeSlots = ((frm_sz - sgeOffset) / (sizeof(u32) + sizeof(dma_addr_t)) );
+       numSgeThisFrame = (sges_left < numSgeSlots) ? sges_left : numSgeSlots;
+
+       sgflags = MPT_SGE_FLAGS_SIMPLE_ELEMENT | MPT_SGE_FLAGS_ADDRESSING | sgdir;
+
+       /* Get first (num - 1) SG elements
+        * Skip any SG entries with a length of 0
+        * NOTE: at finish, sg and psge pointed to NEXT data/location positions
+        */
+       for (ii=0; ii < (numSgeThisFrame-1); ii++) {
+               thisxfer = sg_dma_len(sg);
+               if (thisxfer == 0) {
+                       sg ++; /* Get next SG element from the OS */
+                       sg_done++;
+                       continue;
+               }
+
+               v2 = sg_dma_address(sg);
+               mpt_add_sge(psge, sgflags | thisxfer, v2);
+
+               sg++;           /* Get next SG element from the OS */
+               psge += (sizeof(u32) + sizeof(dma_addr_t));
+               sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
+               sg_done++;
        }
-#endif
-       spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags);
-#endif
 
-       if (r != NULL) {
-               pScsiTmReply = (SCSITaskMgmtReply_t*)r;
-               pScsiTmReq = (SCSITaskMgmt_t*)mf;
+       if (numSgeThisFrame == sges_left) {
+               /* Add last element, end of buffer and end of list flags.
+                */
+               sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT |
+                               MPT_SGE_FLAGS_END_OF_BUFFER |
+                               MPT_SGE_FLAGS_END_OF_LIST;
 
-               /* Figure out if this was ABORT_TASK, TARGET_RESET, or BUS_RESET! */
-               tmType = pScsiTmReq->TaskType;
+               /* Add last SGE and set termination flags.
+                * Note: Last SGE may have a length of 0 - which should be ok.
+                */
+               thisxfer = sg_dma_len(sg);
 
-               dprintk((KERN_INFO MYNAM ": TaskType = %d\n", tmType));
-               dprintk((KERN_INFO MYNAM ": TerminationCount = %d\n",
-                        le32_to_cpu(pScsiTmReply->TerminationCount)));
+               v2 = sg_dma_address(sg);
+               mpt_add_sge(psge, sgflags | thisxfer, v2);
+               /*
+               sg++;
+               psge += (sizeof(u32) + sizeof(dma_addr_t));
+               */
+               sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
+               sg_done++;
+
+               if (chainSge) {
+                       /* The current buffer is a chain buffer,
+                        * but there is not another one.
+                        * Update the chain element
+                        * Offset and Length fields.
+                        */
+                       mpt_add_chain((char *)chainSge, 0, sgeOffset, hd->ChainBufferDMA + chain_dma_off);
+               } else {
+                       /* The current buffer is the original MF
+                        * and there is no Chain buffer.
+                        */
+                       pReq->ChainOffset = 0;
+               }
+       } else {
+               /* At least one chain buffer is needed.
+                * Complete the first MF
+                *  - last SGE element, set the LastElement bit
+                *  - set ChainOffset (words) for orig MF
+                *             (OR finish previous MF chain buffer)
+                *  - update MFStructPtr ChainIndex
+                *  - Populate chain element
+                * Also
+                * Loop until done.
+                */
 
-               /* 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)));
+               dsgprintk((MYIOC_s_INFO_FMT "SG: Chain Required! sg done %d\n",
+                               hd->ioc->name, sg_done));
+
+               /* Set LAST_ELEMENT flag for last non-chain element
+                * in the buffer. Since psge points at the NEXT
+                * SGE element, go back one SGE element, update the flags
+                * and reset the pointer. (Note: sgflags & thisxfer are already
+                * set properly).
+                */
+               if (sg_done) {
+                       u32 *ptmp = (u32 *) (psge - (sizeof(u32) + sizeof(dma_addr_t)));
+                       sgflags = le32_to_cpu(*ptmp);
+                       sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT;
+                       *ptmp = cpu_to_le32(sgflags);
+               }
+
+               if (chainSge) {
+                       /* The current buffer is a chain buffer.
+                        * chainSge points to the previous Chain Element.
+                        * Update its chain element Offset and Length (must
+                        * include chain element size) fields.
+                        * Old chain element is now complete.
+                        */
+                       u8 nextChain = (u8) (sgeOffset >> 2);
+                       sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
+                       mpt_add_chain((char *)chainSge, nextChain, sgeOffset, hd->ChainBufferDMA + chain_dma_off);
                } else {
-                       dprintk((KERN_INFO MYNAM ": SCSI TaskMgmt (%d) SUCCESS!\n", tmType));
+                       /* The original MF buffer requires a chain buffer -
+                        * set the offset.
+                        * Last element in this MF is a chain element.
+                        */
+                       pReq->ChainOffset = (u8) (sgeOffset >> 2);
                }
-       }
 
-#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
+               sges_left -= sg_done;
 
-       return 1;
-}
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*
- *     This is anyones guess quite frankly.
- */
+               /* NOTE: psge points to the beginning of the chain element
+                * in current buffer. Get a chain buffer.
+                */
+               if ((mptscsih_getFreeChainBuffer(hd, &newIndex)) == FAILED)
+                       return FAILED;
 
-int
-mptscsih_bios_param(Disk * disk, kdev_t dev, int *ip)
-{
-       int size;
+               /* Update the tracking arrays.
+                * If chainSge == NULL, update ReqToChain, else ChainToChain
+                */
+               if (chainSge) {
+                       hd->ChainToChain[chain_idx] = newIndex;
+               } else {
+                       hd->ReqToChain[req_idx] = newIndex;
+               }
+               chain_idx = newIndex;
+               chain_dma_off = hd->ioc->req_sz * chain_idx;
 
-       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                    */
+               /* Populate the chainSGE for the current buffer.
+                * - Set chain buffer pointer to psge and fill
+                *   out the Address and Flags fields.
+                */
+               chainSge = (char *) psge;
+               dsgprintk((KERN_INFO "  Current buff @ %p (index 0x%x)",
+                               psge, req_idx));
+
+               /* Start the SGE for the next buffer
+                */
+               psge = (char *) (hd->ChainBuffer + chain_dma_off);
+               sgeOffset = 0;
+               sg_done = 0;
+
+               dsgprintk((KERN_INFO "  Chain buff @ %p (index 0x%x)\n",
+                               psge, chain_idx));
+
+               /* Start the SGE for the next buffer
+                */
+
+               goto nextSGEset;
        }
-       return 0;
+
+       return SUCCESS;
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
- *  Private routines...
- */
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/* 19991030 -sralston
- *  Return absolute SCSI data direction:
- *     1 = _DATA_OUT
- *     0 = _DIR_NONE
- *    -1 = _DATA_IN
+ *     mptscsih_getFreeChainBuffes - Function to get a free chain
+ *     from the MPT_SCSI_HOST FreeChainQ.
+ *     @hd: Pointer to the MPT_SCSI_HOST instance
+ *     @req_idx: Index of the SCSI IO request frame. (output)
+ *
+ *     return SUCCESS or FAILED
  */
 static int
-mptscsih_io_direction(Scsi_Cmnd *cmd)
+mptscsih_getFreeChainBuffer(MPT_SCSI_HOST *hd, int *retIndex)
 {
-       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;
+       MPT_FRAME_HDR *chainBuf = NULL;
+       unsigned long flags;
+       int rc = FAILED;
+       int chain_idx = MPT_HOST_NO_CHAIN;
 
-       /*  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;
+       //spin_lock_irqsave(&hd->FreeChainQlock, flags);
+       spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
+       if (!Q_IS_EMPTY(&hd->FreeChainQ)) {
 
-       /*  Conditional data transfer commands  */
-       case FORMAT_UNIT:
-               if (cmd->cmnd[1] & 0x10)        /* FmtData (data out phase)? */
-                       return 1;
-               else
-                       return 0;
+               int offset;
 
-       case VERIFY:
-               if (cmd->cmnd[1] & 0x02)        /* VERIFY:BYTCHK (data out phase)? */
-                       return 1;
-               else
-                       return 0;
+               chainBuf = hd->FreeChainQ.head;
+               Q_DEL_ITEM(&chainBuf->u.frame.linkage);
+               offset = (u8 *)chainBuf - (u8 *)hd->ChainBuffer;
+               chain_idx = offset / hd->ioc->req_sz;
+               rc = SUCCESS;
+       }
+       //spin_unlock_irqrestore(&hd->FreeChainQlock, flags);
+       spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
 
-       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
+       *retIndex = chain_idx;
 
-       /*  Must be data _IN!  */
-       default:
-               return -1;
-       }
+       dsgprintk((MYIOC_s_INFO_FMT "getFreeChainBuffer (index %d), got buf=%p\n",
+                       hd->ioc->name, *retIndex, chainBuf));
+
+       return rc;
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     mptscsih_freeChainBuffers - Function to free chain buffers associated
+ *     with a SCSI IO request
+ *     @hd: Pointer to the MPT_SCSI_HOST instance
+ *     @req_idx: Index of the SCSI IO request frame.
+ *
+ *     Called if SG chain buffer allocation fails and mptscsih callbacks.
+ *     No return.
+ */
 static void
-copy_sense_data(Scsi_Cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply)
+mptscsih_freeChainBuffers(MPT_SCSI_HOST *hd, int req_idx)
 {
-       MPT_SCSI_DEV    *mpt_sdev = NULL;
-       u32              sense_count = le32_to_cpu(pScsiReply->SenseCount);
-       char             devFoo[32];
-       IO_Info_t        thisIo;
+       MPT_FRAME_HDR *chain = NULL;
+       unsigned long flags;
+       int chain_idx;
+       int next;
 
-       if (sc && sc->device)
-               mpt_sdev = (MPT_SCSI_DEV*) sc->device->hostdata;
+       /* Get the first chain index and reset
+        * tracker state.
+        */
+       chain_idx = hd->ReqToChain[req_idx];
+       hd->ReqToChain[req_idx] = MPT_HOST_NO_CHAIN;
 
-       if (sense_count) {
-               u8 *sense_data;
-               int req_index;
+       while (chain_idx != MPT_HOST_NO_CHAIN) {
 
-               /* 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"));
-       }
+               /* Save the next chain buffer index */
+               next = hd->ChainToChain[chain_idx];
 
+               /* Free this chain buffer and reset
+                * tracker
+                */
+               hd->ChainToChain[chain_idx] = MPT_HOST_NO_CHAIN;
 
-       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);
+               chain = (MPT_FRAME_HDR *) (hd->ChainBuffer
+                                       + (chain_idx * hd->ioc->req_sz));
+               spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
+               Q_ADD_TAIL(&hd->FreeChainQ.head,
+                                       &chain->u.frame.linkage, MPT_FRAME_HDR);
+               spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
 
+               dmfprintk((MYIOC_s_INFO_FMT "FreeChainBuffers (index %d)\n",
+                               hd->ioc->name, chain_idx));
+
+               /* handle next */
+               chain_idx = next;
+       }
        return;
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-static u32
-SCPNT_TO_MSGCTX(Scsi_Cmnd *sc)
+/*
+ *     Reset Handling
+ */
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     mptscsih_TMHandler - Generic handler for SCSI Task Management.
+ *     Fall through to mpt_HardResetHandler if: not operational, too many
+ *     failed TM requests or handshake failure.
+ *
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @type: Task Management type
+ *     @target: Logical Target ID for reset (if appropriate)
+ *     @lun: Logical Unit for reset (if appropriate)
+ *     @ctx2abort: Context for the task to be aborted (if appropriate)
+ *     @sleepFlag: If set, use udelay instead of schedule in handshake code.
+ *
+ *     Remark: Currently invoked from a non-interrupt thread (_bh).
+ *
+ *     Remark: With old EH code, at most 1 SCSI TaskMgmt function per IOC
+ *     will be active.
+ *
+ *     Returns 0 for SUCCESS or -1 if FAILED.
+ */
+static int
+mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 target, u8 lun, int ctx2abort, int sleepFlag)
 {
-       MPT_SCSI_HOST *hd;
-       MPT_FRAME_HDR *mf;
-       int i;
+       MPT_ADAPTER     *ioc = NULL;
+       int              rc = -1;
+       int              doTask = 1;
+       u32              ioc_raw_state;
+       unsigned long    flags;
 
-       hd = (MPT_SCSI_HOST *) sc->host->hostdata;
+       /* If FW is being reloaded currently, return success to
+        * the calling function.
+        */
+       if (hd == NULL)
+               return 0;
 
-       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;
-               }
+       ioc = hd->ioc;
+       dtmprintk((MYIOC_s_INFO_FMT "TMHandler Entered!\n", ioc->name));
+
+       if (ioc == NULL) {
+               printk(KERN_ERR MYNAM " TMHandler" " NULL ioc!\n");
+               return 0;
        }
 
-       return -1;
-}
+       // SJR - CHECKME - Can we avoid this here?
+       // (mpt_HardResetHandler has this check...)
+       spin_lock_irqsave(&ioc->diagLock, flags);
+       if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)) {
+               spin_unlock_irqrestore(&ioc->diagLock, flags);
+               return 0;
+       }
+       spin_unlock_irqrestore(&ioc->diagLock, flags);
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+       /* Do not do a Task Management if there are
+        * too many failed TMs on this adapter.
+        */
+       if (hd->numTMrequests > MPT_HOST_TOO_MANY_TM)
+               doTask = 0;
 
-/* see mptscsih.h */
+       /* Is operational?
+        */
+       ioc_raw_state = mpt_GetIocState(hd->ioc, 0);
 
-#ifdef MPT_SCSIHOST_NEED_ENTRY_EXIT_HOOKUPS
-       static Scsi_Host_Template driver_template = MPT_SCSIHOST;
-#      include "../../scsi/scsi_module.c"
+#ifdef MPT_DEBUG_RESET
+       if ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL) {
+               printk(MYIOC_s_WARN_FMT 
+                       "TM Handler: IOC Not operational! state 0x%x Calling HardResetHandler\n", 
+                       hd->ioc->name, ioc_raw_state);
+       }
 #endif
 
+       if (doTask && ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL)
+                               && !(ioc_raw_state & MPI_DOORBELL_ACTIVE)) {
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-static int
-mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
-{
-       dprintk((KERN_INFO MYNAM ": IOC %s_reset routed to SCSI host driver!\n",
-                       reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post"));
+               /* Isse the Task Mgmt request.
+                */
+               rc = mptscsih_IssueTaskMgmt(hd, type, target, lun, ctx2abort, sleepFlag);
+               if (rc) {
+#ifdef MPT_SCSI_USE_NEW_EH
+                       hd->tmState = TM_STATE_ERROR;
+#endif
+                       printk(MYIOC_s_INFO_FMT "Issue of TaskMgmt failed!\n", hd->ioc->name);
+               } else {
+                       printk(MYIOC_s_INFO_FMT "Issue of TaskMgmt Successful!\n", hd->ioc->name);
+               }
+       }
+#ifdef DROP_TEST
+       numTMrequested++;
+       if (numTMrequested > 5) {
+               rc = 0;         /* set to 1 to force a hard reset */
+               numTMrequested = 0;
+       }
+#endif
 
-       if (reset_phase == MPT_IOC_PRE_RESET) {
-               /* FIXME! Do pre-reset cleanup */
-       } else {
-               /* FIXME! Do post-reset cleanup */
+       if (rc) {
+               dtmprintk((MYIOC_s_INFO_FMT "Falling through to HardReset! \n",
+                        hd->ioc->name));
+               rc = mpt_HardResetHandler(hd->ioc, sleepFlag);
        }
 
-       return 1;               /* currently means nothing really */
+       dtmprintk((MYIOC_s_INFO_FMT "TMHandler rc = %d!\n", hd->ioc->name, rc));
+#ifndef MPT_SCSI_USE_NEW_EH
+       dtmprintk((MYIOC_s_INFO_FMT "TMHandler: _bh_handler state (%d) taskQ count (%d)\n",
+               ioc->name, mytaskQ_bh_active, hd->taskQcnt));
+#endif
+
+       return rc;
 }
 
+
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     mptscsih_IssueTaskMgmt - Generic send Task Management function.
+ *     @hd: Pointer to MPT_SCSI_HOST structure
+ *     @type: Task Management type
+ *     @target: Logical Target ID for reset (if appropriate)
+ *     @lun: Logical Unit for reset (if appropriate)
+ *     @ctx2abort: Context for the task to be aborted (if appropriate)
+ *     @sleepFlag: If set, use udelay instead of schedule in handshake code.
+ *
+ *     Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
+ *     or a non-interrupt thread.  In the former, must not call schedule().
+ *
+ *     Not all fields are meaningfull for all task types.
+ *
+ *     Returns 0 for SUCCESS, -999 for "no msg frames",
+ *     else other non-zero value returned.
+ */
 static int
-mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
+mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 target, u8 lun, int ctx2abort, int sleepFlag)
 {
-       u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
+       MPT_FRAME_HDR   *mf;
+       SCSITaskMgmt_t  *pScsiTm;
+       int              ii;
+       int              retval;
 
-       dprintk((KERN_INFO MYNAM ": MPT event (=%02Xh) routed to SCSI host driver!\n", event));
+       /* Return Fail to calling function if no message frames available.
+        */
+       if ((mf = mpt_get_msg_frame(ScsiTaskCtx, hd->ioc->id)) == NULL) {
+               dtmprintk((MYIOC_s_WARN_FMT "IssueTaskMgmt, no msg frames!!\n",
+                               hd->ioc->name));
+               //return FAILED;
+               return -999;
+       }
+       dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt request @ %p\n",
+                       hd->ioc->name, mf));
 
-       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;
+       /* Format the Request
+        */
+       pScsiTm = (SCSITaskMgmt_t *) mf;
+       pScsiTm->TargetID = target;
+       pScsiTm->Bus = hd->port;
+       pScsiTm->ChainOffset = 0;
+       pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
 
-               /*
-                *  CHECKME! Don't think we need to do
-                *  anything for these, but...
+       pScsiTm->Reserved = 0;
+       pScsiTm->TaskType = type;
+       pScsiTm->Reserved1 = 0;
+       pScsiTm->MsgFlags = (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS)
+                           ? MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION : 0;
+
+       for (ii= 0; ii < 8; ii++) {
+               pScsiTm->LUN[ii] = 0;
+       }
+       pScsiTm->LUN[1] = lun;
+
+       for (ii=0; ii < 7; ii++)
+               pScsiTm->Reserved2[ii] = 0;
+
+       pScsiTm->TaskMsgContext = ctx2abort;
+       dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt, ctx2abort (0x%08x), type (%d)\n",
+                       hd->ioc->name, ctx2abort, type));
+
+       /* MPI v0.10 requires SCSITaskMgmt requests be sent via Doorbell/handshake
+               mpt_put_msg_frame(hd->ioc->id, mf);
+       * Save the MF pointer in case the request times out.
+       */
+       hd->tmPtr = mf;
+       hd->numTMrequests++;
+       hd->TMtimer.expires = jiffies + HZ*20;  /* 20 seconds */
+       add_timer(&hd->TMtimer);
+
+       if ((retval = mpt_send_handshake_request(ScsiTaskCtx, hd->ioc->id,
+                               sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, sleepFlag))
+       != 0) {
+               dtmprintk((MYIOC_s_WARN_FMT "_send_handshake FAILED!"
+                       " (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd, hd->ioc, mf));
+               hd->numTMrequests--;
+               hd->tmPtr = NULL;
+               del_timer(&hd->TMtimer);
+               mpt_free_msg_frame(ScsiTaskCtx, hd->ioc->id, mf);
+       }
+
+       return retval;
+}
+
+#ifdef MPT_SCSI_USE_NEW_EH             /* { */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     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_SCSI_HOST   *hd;
+       MPT_FRAME_HDR   *mf;
+       unsigned long    flags;
+       u32              ctx2abort;
+       int              scpnt_idx;
+
+       /* If we can't locate our host adapter structure, return FAILED status.
+        */
+       if ((hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata) == NULL) {
+               SCpnt->result = DID_RESET << 16;
+               SCpnt->scsi_done(SCpnt);
+               nehprintk((KERN_WARNING MYNAM ": mptscsih_abort: "
+                          "Can't locate host! (sc=%p)\n",
+                          SCpnt));
+               return FAILED;
+       }
+
+       printk(KERN_WARNING MYNAM ": %s: >> Attempting task abort! (sc=%p)\n",
+              hd->ioc->name, SCpnt);
+       printk(KERN_WARNING MYNAM ": %s: IOs outstanding = %d\n",
+              hd->ioc->name, atomic_read(&queue_depth));
+
+       /* Find this command
+        */
+       if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(SCpnt)) < 0) {
+               /* Cmd not found in ScsiLookup. If found in
+                * doneQ, delete from Q. Do OS callback.
                 */
-       case MPI_EVENT_RESCAN:                          /* 06 */
-       case MPI_EVENT_LINK_STATUS_CHANGE:              /* 07 */
-       case MPI_EVENT_LOOP_STATE_CHANGE:               /* 08 */
-               /*
-                *  CHECKME!  Falling thru...
+               search_doneQ_for_cmd(hd, SCpnt);
+
+               SCpnt->result = DID_RESET << 16;
+               SCpnt->scsi_done(SCpnt);
+               nehprintk((KERN_WARNING MYNAM ": %s: mptscsih_abort: "
+                          "Command not in the active list! (sc=%p)\n",
+                          hd->ioc->name, SCpnt));
+               return SUCCESS;
+       }
+
+       /*  Wait a fixed amount of time for the TM pending flag to be cleared.
+        *  If we time out, then we return a FAILED status to the caller.  This
+        *  call to mptscsih_tm_pending_wait() will set the pending flag if we are
+        *  successful.
+        */
+       if (mptscsih_tm_pending_wait(hd) == FAILED){
+               nehprintk((KERN_WARNING MYNAM ": %s: mptscsih_abort: "
+                          "Timed out waiting for previous TM to complete! "
+                          "(sc = %p)\n",
+                          hd->ioc->name, SCpnt));
+               return FAILED;
+       }
+
+       /* If this command is pended, then timeout/hang occurred
+        * during DV. Post command and flush pending Q
+        * and then following up with the reset request.
+        */
+       if ((mf = mptscsih_search_pendingQ(hd, scpnt_idx)) != NULL) {
+               mptscsih_put_msgframe(ScsiDoneCtx, hd->ioc->id, mf);
+               post_pendingQ_commands(hd);
+               nehprintk((KERN_WARNING MYNAM ": %s: mptscsih_abort: "
+                          "Found command in pending queue! (sc=%p)\n",
+                          hd->ioc->name, 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
+        */
+       mf = MPT_INDEX_2_MFPTR(hd->ioc, scpnt_idx);
+       ctx2abort = mf->u.frame.hwhdr.msgctxu.MsgContext;
+
+       hd->abortSCpnt = SCpnt;
+
+       if (mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK,
+                              SCpnt->target, SCpnt->lun, ctx2abort, CAN_SLEEP) 
+               < 0
+           || hd->tmState == TM_STATE_ERROR) {
+
+               /* The TM request failed and the subsequent FW-reload failed!
+                * Fatal error case.
                 */
+               printk(MYIOC_s_WARN_FMT "Error issuing abort task! (sc=%p)\n",
+                      hd->ioc->name, SCpnt);
 
-       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;
+               /* If command not found, do not do callback,
+                *  just return failed.  CHECKME
+                */
+               if (hd->ScsiLookup[scpnt_idx] != NULL) {
+                       SCpnt->result = STS_BUSY;
+                       SCpnt->scsi_done(SCpnt);
+               }
+
+               /* We must clear our pending flag before clearing our state.
+                */
+               hd->tmPending = 0;
+               hd->tmState = TM_STATE_NONE;
+
+               return FAILED;
        }
 
-       return 1;               /* currently means nothing really */
+       /* Our task management request will either complete or time out.  So we
+        * spin until tmPending is != 1. If tmState is set to TM_STATE_ERROR, 
+        * we encountered an error executing the task management request.
+        */
+       while (hd->tmPending == 1){
+               set_current_state(TASK_INTERRUPTIBLE);
+               schedule_timeout(HZ/4);
+       }
+       spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
+       if (hd->tmState == TM_STATE_ERROR){
+               hd->tmState = TM_STATE_NONE;
+               spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+               nehprintk((KERN_WARNING MYNAM ": %s: mptscsih_abort: "
+                          "TM timeout error! (sc=%p)\n",
+                          hd->ioc->name,
+                          SCpnt));
+               return FAILED;
+       }
+       hd->tmState = TM_STATE_NONE;
+       spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+
+       nehprintk((KERN_WARNING MYNAM ": %s: mptscsih_abort: "
+                  "Abort was successful! (sc=%p)\n",
+                  hd->ioc->name,
+                  SCpnt));
+
+       return SUCCESS;
 }
 
-#if 0          /* { */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*
- *     scsiherr.c - Fusion MPT SCSI Host driver error handling/reporting.
+/**
+ *     mptscsih_dev_reset - Perform a SCSI TARGET_RESET!  new_eh variant
+ *     @SCpnt: Pointer to Scsi_Cmnd structure, IO which reset is due to
  *
- *     drivers/message/fusion/scsiherr.c
+ *     (linux Scsi_Host_Template.eh_dev_reset_handler routine)
+ *
+ *     Returns SUCCESS or FAILED.
  */
+int
+mptscsih_dev_reset(Scsi_Cmnd * SCpnt)
+{
+       MPT_SCSI_HOST   *hd;
+       unsigned long    flags;
 
-//extern const char    **mpt_ScsiOpcodesPtr;   /* needed by mptscsih.c */
-//extern ASCQ_Table_t   *mpt_ASCQ_TablePtr;
-//extern int             mpt_ASCQ_TableSz;
+       /* If we can't locate our host adapter structure, return FAILED status.
+        */
+       if ((hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata) == NULL){
+               nehprintk((KERN_WARNING MYNAM ": mptscsih_dev_reset: "
+                          "Can't locate host! (sc=%p)\n",
+                          SCpnt));
+               return FAILED;
+       }
 
-/*  Lie!  */
-#define MYNAM  "mptscsih"
+       printk(KERN_WARNING MYNAM ": %s: >> Attempting target reset! (sc=%p)\n",
+              hd->ioc->name, SCpnt);
+       printk(KERN_WARNING MYNAM ": %s: IOs outstanding = %d\n",
+              hd->ioc->name, atomic_read(&queue_depth));
 
-#endif         /* } */
+       /*  Wait a fixed amount of time for the TM pending flag to be cleared.
+        *  If we time out, then we return a FAILED status to the caller.  This
+        *  call to mptscsih_tm_pending_wait() will set the pending flag if we are
+        *  successful.
+        */
+       if (mptscsih_tm_pending_wait(hd) == FAILED) {
+               nehprintk((KERN_WARNING MYNAM ": %s: mptscsih_dev_reset: "
+                          "Timed out waiting for previous TM to complete! "
+                          "(sc = %p)\n",
+                          hd->ioc->name, SCpnt));
+               return FAILED;
+       }
+
+       if (mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
+                              SCpnt->target, 0, 0, CAN_SLEEP) 
+               < 0){
+               /* The TM request failed and the subsequent FW-reload failed!
+                * Fatal error case.
+                */
+               printk(MYIOC_s_WARN_FMT "Error processing TaskMgmt request (sc=%p)\n",
+                               hd->ioc->name, SCpnt);
+               hd->tmPending = 0;
+               hd->tmState = TM_STATE_NONE;
+               return FAILED;
+       }
+
+       /* Our task management request will either complete or time out.  So we
+        * spin until tmPending is != 1. If tmState is set to TM_STATE_ERROR, 
+        * we encountered an error executing the task management request.
+        */
+       while (hd->tmPending == 1){
+               set_current_state(TASK_INTERRUPTIBLE);
+               schedule_timeout(HZ/4);
+       }
+       spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
+       if (hd->tmState == TM_STATE_ERROR){
+               hd->tmState = TM_STATE_NONE;
+               spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+               nehprintk((KERN_WARNING MYNAM ": %s: mptscsih_dev_reset: "
+                          "TM timeout error! (sc=%p)\n",
+                          hd->ioc->name,
+                          SCpnt));
+               return FAILED;
+       }
+       hd->tmState = TM_STATE_NONE;
+       spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+
+       nehprintk((KERN_WARNING MYNAM ": %s: mptscsih_dev_reset: "
+                  "Device reset was successful! (sc=%p)\n",
+                  hd->ioc->name,
+                  SCpnt));
+
+       return SUCCESS;
+}
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*
- *  Private data...
+/**
+ *     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.
  */
-static ASCQ_Table_t *mptscsih_ASCQ_TablePtr;
+int
+mptscsih_bus_reset(Scsi_Cmnd * SCpnt)
+{
+       MPT_SCSI_HOST   *hd;
+       unsigned long    flags;
+
+       /* If we can't locate our host adapter structure, return FAILED status.
+        */
+       if ((hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata) == NULL){
+               nehprintk((KERN_WARNING MYNAM ": mptscsih_bus_reset: "
+                          "Can't locate host! (sc=%p)\n",
+                          SCpnt ) );
+               return FAILED;
+       }
+
+       printk(KERN_WARNING MYNAM ": %s: >> Attempting bus reset! (sc=%p)\n",
+              hd->ioc->name, SCpnt);
+       printk(KERN_WARNING MYNAM ": %s: IOs outstanding = %d\n",
+              hd->ioc->name, atomic_read(&queue_depth));
+
+       /*  Wait a fixed amount of time for the TM pending flag to be cleared.
+        *  If we time out, then we return a FAILED status to the caller.  This
+        *  call to mptscsih_tm_pending_wait() will set the pending flag if we are
+        *  successful.
+        */
+       if (mptscsih_tm_pending_wait(hd) == FAILED) {
+               nehprintk((KERN_WARNING MYNAM ": %s: mptscsih_bus_reset: "
+                          "Timed out waiting for previous TM to complete! "
+                          "(sc = %p)\n",
+                          hd->ioc->name, SCpnt ) );
+               return FAILED;
+       }
+
+       /* We are now ready to execute the task management request. */
+       if (mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
+                              0, 0, 0, CAN_SLEEP) 
+           < 0){
+
+               /* The TM request failed and the subsequent FW-reload failed!
+                * Fatal error case.
+                */
+               printk(MYIOC_s_WARN_FMT 
+                      "Error processing TaskMgmt request (sc=%p)\n",
+                      hd->ioc->name, SCpnt);
+               hd->tmPending = 0;
+               hd->tmState = TM_STATE_NONE;
+               return FAILED;
+       }
+
+       /* Our task management request will either complete or time out.  So we
+        * spin until tmPending is != 1. If tmState is set to TM_STATE_ERROR, 
+        * we encountered an error executing the task management request.
+        */
+       while (hd->tmPending == 1){
+               set_current_state(TASK_INTERRUPTIBLE);
+               schedule_timeout(HZ/4);
+       }
+       spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
+       if (hd->tmState == TM_STATE_ERROR){
+               hd->tmState = TM_STATE_NONE;
+               spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+               nehprintk((KERN_WARNING MYNAM ": %s: mptscsih_bus_reset: "
+                          "TM timeout error! (sc=%p)\n",
+                          hd->ioc->name,
+                          SCpnt));
+               return FAILED;
+       }
+       hd->tmState = TM_STATE_NONE;
+       spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+
+       nehprintk((KERN_WARNING MYNAM ": %s: mptscsih_bus_reset: "
+                  "Bus reset was successful! (sc=%p)\n",
+                  hd->ioc->name,
+                  SCpnt));
+
+       return SUCCESS;
+}
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/* old symsense.c stuff... */
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*
- * Private data...
- * To protect ourselves against those that would pass us bogus pointers
+/**
+ *     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.
  */
-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 };
+int
+mptscsih_host_reset(Scsi_Cmnd *SCpnt)
+{
+       MPT_SCSI_HOST *  hd;
+       int              status = SUCCESS;
+
+       /*  If we can't locate the host to reset, then we failed. */
+       if ((hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata) == NULL){
+               nehprintk( ( KERN_WARNING MYNAM ": mptscsih_host_reset: "
+                            "Can't locate host! (sc=%p)\n",
+                            SCpnt ) );
+               return FAILED;
+       }
 
-#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 */
+       printk(KERN_WARNING MYNAM ": %s: >> Attempting host reset! (sc=%p)\n",
+              hd->ioc->name, SCpnt);
+       printk(KERN_WARNING MYNAM ": %s: IOs outstanding = %d\n",
+              hd->ioc->name, atomic_read(&queue_depth));
+
+       /*  If our attempts to reset the host failed, then return a failed
+        *  status.  The host will be taken off line by the SCSI mid-layer.
+        */
+       if (mpt_HardResetHandler(hd->ioc, CAN_SLEEP) < 0){
+               status = FAILED;
+       } else {
+               /*  Make sure TM pending is cleared and TM state is set to 
+                *  NONE. 
+                */
+               hd->tmPending = 0;
+               hd->tmState = TM_STATE_NONE;
+       }
+
+
+       nehprintk( ( KERN_WARNING MYNAM ": mptscsih_host_reset: "
+                    "Status = %s\n",
+                    (status == SUCCESS) ? "SUCCESS" : "FAILED" ) );
+
+       return status;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mptscsih_tm_pending_wait - wait for pending task management request to 
+ *             complete.
+ *     @hd: Pointer to MPT host structure.
+ *
+ *     Returns {SUCCESS,FAILED}.
+ */
+static int
+mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd)
+{
+       unsigned long  flags;
+       int            loop_count = 60 * 4;  /* Wait 60 seconds */
+       int            status = FAILED;
+
+       do {
+               spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
+               if (hd->tmState == TM_STATE_NONE) {
+                       hd->tmState = TM_STATE_IN_PROGRESS;
+                       hd->tmPending = 1;
+                       spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+                       status = SUCCESS;
+                       break;
+               }
+               spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+               set_current_state(TASK_INTERRUPTIBLE);
+               schedule_timeout(HZ/4);
+
+       } while (--loop_count);
+
+       return status;
+}
+
+#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;
+       int                      scpnt_idx;
+
+       printk(KERN_WARNING MYNAM ": OldAbort scheduling ABORT SCSI IO (sc=%p)\n", (void *) SCpnt);
+       printk(KERN_WARNING "  IOs outstanding = %d\n", atomic_read(&queue_depth));
+
+       if ((hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata) == NULL) {
+               printk(KERN_WARNING "  WARNING - OldAbort, NULL hostdata ptr!!\n");
+               SCpnt->result = DID_ERROR << 16;
+               SCpnt->scsi_done(SCpnt);
+               return SCSI_ABORT_NOT_RUNNING;
+       }
+
+       if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(SCpnt)) < 0) {
+               /* Cmd not found in ScsiLookup.
+                * If found in doneQ, delete from Q.
+                * Do OS callback.
+                */
+               search_doneQ_for_cmd(hd, SCpnt);
+
+               SCpnt->result = DID_RESET << 16;
+               SCpnt->scsi_done(SCpnt);
+               return SCSI_ABORT_SUCCESS;
+       } else {
+               /* If this command is pended, then timeout/hang occurred
+                * during DV. Force bus reset by posting command to F/W
+                * and then following up with the reset request.
+                */
+               if ((mf = mptscsih_search_pendingQ(hd, scpnt_idx)) != NULL) {
+                       mptscsih_put_msgframe(ScsiDoneCtx, hd->ioc->id, mf);
+                       post_pendingQ_commands(hd);
+               }
+       }
+
+       /*
+        *  Check to see if there's already an ABORT queued for this guy.
+        */
+       mf = search_taskQ(0, SCpnt, hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK);
+       if (mf != NULL) {
+               dtmprintk((MYIOC_s_INFO_FMT "OldAbort:Abort Task PENDING cmd (%p) taskQ depth (%d)\n",
+                       hd->ioc->name, SCpnt, hd->taskQcnt));
+               return SCSI_ABORT_PENDING;
+       }
+
+       // SJR - CHECKME - Can we avoid this here?
+       // (mpt_HardResetHandler has this check...)
+       /* If IOC is reloading FW, return PENDING.
+        */
+       spin_lock_irqsave(&hd->ioc->diagLock, flags);
+       if (hd->ioc->diagPending) {
+               spin_unlock_irqrestore(&hd->ioc->diagLock, flags);
+               return SCSI_ABORT_PENDING;
+       }
+       spin_unlock_irqrestore(&hd->ioc->diagLock, flags);
+
+       /* If there are no message frames what should we do?
+        */
+       if ((mf = mpt_get_msg_frame(ScsiTaskCtx, hd->ioc->id)) == NULL) {
+               printk((KERN_WARNING "  WARNING - OldAbort, no msg frames!!\n"));
+               /* We are out of message frames!
+                * Call the reset handler to do a FW reload.
+                */
+               printk((KERN_WARNING " Reloading Firmware!!\n"));
+               if (mpt_HardResetHandler(hd->ioc, NO_SLEEP) < 0) {
+                       printk((KERN_WARNING " Firmware Reload FAILED!!\n"));
+               }
+               return SCSI_ABORT_PENDING;
+       }
+
+       /*
+        *  Add ourselves to (end of) taskQ .
+        *  Check to see if our _bh is running.  If NOT, schedule it.
+        */
+       spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
+       Q_ADD_TAIL(&hd->taskQ, &mf->u.frame.linkage, MPT_FRAME_HDR);
+       hd->taskQcnt++;
+       atomic_inc(&mpt_taskQdepth);
+       spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+
+       spin_lock_irqsave(&mytaskQ_lock, flags);
+
+       /* Save the original SCpnt mf pointer
+        */
+       SCpnt->host_scribble = (u8 *) MPT_INDEX_2_MFPTR (hd->ioc, scpnt_idx);
+
+       /* For the time being, force bus reset on any abort
+        * requests for the 1030 FW.
+        */
+       if (hd->is_spi)
+               mf->u.frame.linkage.arg1 = MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS;
+       else
+               mf->u.frame.linkage.arg1 = MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK;
+
+       mf->u.frame.linkage.argp1 = SCpnt;
+       mf->u.frame.linkage.argp2 = (void *) hd;
+
+       dtmprintk((MYIOC_s_INFO_FMT "OldAbort:_bh_handler state (%d) taskQ count (%d)\n",
+               hd->ioc->name, mytaskQ_bh_active, hd->taskQcnt));
+
+       if (! mytaskQ_bh_active) {
+               mytaskQ_bh_active = 1;
+               spin_unlock_irqrestore(&mytaskQ_lock, flags);
+
+               /*
+                *  Oh how cute, no alloc/free/mgmt needed if we use
+                *  (bottom/unused portion of) MPT request frame.
+                */
+               ptaskfoo = (struct tq_struct *) &mptscsih_ptaskfoo;
+               ptaskfoo->sync = 0;
+               ptaskfoo->routine = mptscsih_taskmgmt_bh;
+               ptaskfoo->data = SCpnt;
+
+               SCHEDULE_TASK(ptaskfoo);
+       } else  {
+               spin_unlock_irqrestore(&mytaskQ_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;
+       int                      scpnt_idx;
+
+       printk(KERN_WARNING MYNAM ": OldReset scheduling BUS_RESET (sc=%p)\n", (void *) SCpnt);
+       printk(KERN_WARNING "  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;
+       }
+
+       if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(SCpnt)) < 0) {
+               /* Cmd not found in ScsiLookup.
+                * If found in doneQ, delete from Q.
+                * Do OS callback.
+                */
+               search_doneQ_for_cmd(hd, SCpnt);
+
+               SCpnt->result = DID_RESET << 16;
+               SCpnt->scsi_done(SCpnt);
+               return SCSI_RESET_SUCCESS;
+       } else {
+               /* If this command is pended, then timeout/hang occurred
+                * during DV. Force bus reset by posting command to F/W
+                * and then following up with the reset request.
+                */
+               if ((mf = mptscsih_search_pendingQ(hd, scpnt_idx)) != NULL) {
+                       mptscsih_put_msgframe(ScsiDoneCtx, hd->ioc->id, mf);
+                       post_pendingQ_commands(hd);
+               }
+       }
+
+       /*
+        *  Check to see if there's an ABORT_TASK queued for this guy.
+        *  If so, delete.
+        */
+       search_taskQ(1, SCpnt, hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK);
+
+       /*
+        *  Check to see if there's already a BUS_RESET queued for this guy.
+        */
+       mf = search_taskQ(0, SCpnt, hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS);
+       if (mf != NULL) {
+               dtmprintk((MYIOC_s_INFO_FMT "OldReset:Reset Task PENDING cmd (%p) taskQ depth (%d)\n",
+                       hd->ioc->name, SCpnt, hd->taskQcnt));
+               return SCSI_RESET_PENDING;
+       }
+
+       // SJR - CHECKME - Can we avoid this here?
+       // (mpt_HardResetHandler has this check...)
+       /* If IOC is reloading FW, return PENDING.
+        */
+       spin_lock_irqsave(&hd->ioc->diagLock, flags);
+       if (hd->ioc->diagPending) {
+               spin_unlock_irqrestore(&hd->ioc->diagLock, flags);
+               return SCSI_RESET_PENDING;
+       }
+       spin_unlock_irqrestore(&hd->ioc->diagLock, flags);
+
+       if ((mf = mpt_get_msg_frame(ScsiTaskCtx, hd->ioc->id)) == NULL) {
+               /* We are out of message frames!
+                * Call the reset handler to do a FW reload.
+                */
+               printk((KERN_WARNING " Reloading Firmware!!\n"));
+               if (mpt_HardResetHandler(hd->ioc, NO_SLEEP) < 0) {
+                       printk((KERN_WARNING " Firmware Reload FAILED!!\n"));
+               }
+               return SCSI_RESET_PENDING;
+       }
+
+       /*
+        *  Add ourselves to (end of) taskQ.
+        *  Check to see if our _bh is running.  If NOT, schedule it.
+        */
+       spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
+       Q_ADD_TAIL(&hd->taskQ, &mf->u.frame.linkage, MPT_FRAME_HDR);
+       hd->taskQcnt++;
+       atomic_inc(&mpt_taskQdepth);
+       spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+
+
+       dtmprintk((MYIOC_s_INFO_FMT "OldReset: _bh_handler state (%d) taskQ count (%d)\n",
+               hd->ioc->name, mytaskQ_bh_active, hd->taskQcnt));
+
+       spin_lock_irqsave(&mytaskQ_lock, flags);
+       /* Save the original SCpnt mf pointer
+        */
+       SCpnt->host_scribble = (u8 *) MPT_INDEX_2_MFPTR (hd->ioc, scpnt_idx);
+
+       mf->u.frame.linkage.arg1 = MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS;
+       mf->u.frame.linkage.argp1 = SCpnt;
+       mf->u.frame.linkage.argp2 = (void *) hd;
+
+       if (! mytaskQ_bh_active) {
+               mytaskQ_bh_active = 1;
+               spin_unlock_irqrestore(&mytaskQ_lock, flags);
+               /*
+                *  Oh how cute, no alloc/free/mgmt needed if we use
+                *  (bottom/unused portion of) MPT request frame.
+                */
+               ptaskfoo = (struct tq_struct *) &mptscsih_ptaskfoo;
+               ptaskfoo->sync = 0;
+               ptaskfoo->routine = mptscsih_taskmgmt_bh;
+               ptaskfoo->data = SCpnt;
+
+               SCHEDULE_TASK(ptaskfoo);
+       } else  {
+               spin_unlock_irqrestore(&mytaskQ_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)
+{
+       MPT_ADAPTER     *ioc;
+       Scsi_Cmnd       *SCpnt;
+       MPT_FRAME_HDR   *mf = NULL;
+       MPT_SCSI_HOST   *hd;
+       u32              ctx2abort = 0;
+       unsigned long    flags;
+       int              scpnt_idx;
+       int              did;
+       u8               task_type;
+
+       spin_lock_irqsave(&mytaskQ_lock, flags);
+       mytaskQ_bh_active = 1;
+       spin_unlock_irqrestore(&mytaskQ_lock, flags);
+
+       do {
+               set_current_state(TASK_INTERRUPTIBLE);
+               schedule_timeout(HZ/4);
+               did = 0;
+
+               for (ioc = mpt_adapter_find_first(); ioc != NULL; ioc = mpt_adapter_find_next(ioc)) {
+                       if (ioc->sh) {
+                               hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
+                               if (hd == NULL) {
+                                       printk(KERN_ERR MYNAM
+                                                       ": ERROR - TaskMgmt NULL SCSI Host!"
+                                                       "(ioc=%p, sh=%p hd=%p)\n",
+                                                       (void *) ioc, (void *) ioc->sh, (void *) hd);
+                                       continue;
+                               }
+
+                               spin_lock_irqsave(&ioc->FreeQlock, flags);
+                               if (Q_IS_EMPTY(&hd->taskQ)) {
+                                       spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+                                       continue;
+                               }
+
+                               /* If we ever find a non-empty queue,
+                                * keep the handler alive
+                                */
+                               did++;
+
+                               /* tmPending is SMP lock-protected */
+                               if (hd->tmPending || hd->tmPtr) {
+                                       spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+                                       continue;
+                               }
+                               hd->tmPending = 1;
+
+                               /* Process this request
+                                */
+                                mf = hd->taskQ.head;
+                               Q_DEL_ITEM(&mf->u.frame.linkage);
+                               hd->taskQcnt--;
+                               atomic_dec(&mpt_taskQdepth);
+                               spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+
+                               SCpnt = (Scsi_Cmnd*)mf->u.frame.linkage.argp1;
+                               if (SCpnt == NULL) {
+                                       printk(KERN_ERR MYNAM ": ERROR - TaskMgmt has NULL SCpnt! (mf=%p:sc=%p)\n",
+                                                       (void *) mf, (void *) SCpnt);
+                                       mpt_free_msg_frame(ScsiTaskCtx, hd->ioc->id, mf);
+                                       spin_lock_irqsave(&ioc->FreeQlock, flags);
+                                       hd->tmPending = 0;
+                                       spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+                                       continue;
+                               }
+
+                               /* Get the ScsiLookup index pointer
+                                * from the SC pointer.
+                                */
+                               if (!SCpnt->host_scribble || ((MPT_SCSI_HOST *)SCpnt->host->hostdata != hd)) {
+                                       /* The command associated with the
+                                        * abort/reset request must have
+                                        * completed and this is a stale
+                                        * request. We are done.
+                                        * Free the current MF and continue.
+                                        */
+                                       mpt_free_msg_frame(ScsiTaskCtx, hd->ioc->id, mf);
+                                       spin_lock_irqsave(&ioc->FreeQlock, flags);
+                                       hd->tmPending = 0;
+                                       spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+                                       continue;
+                               }
+
+                               scpnt_idx = MFPTR_2_MPT_INDEX(hd->ioc, SCpnt->host_scribble);
+                               if (scpnt_idx != SCPNT_TO_LOOKUP_IDX(SCpnt)) {
+                                       /* Error! this should never happen!!
+                                        */
+                                       mpt_free_msg_frame(ScsiTaskCtx, hd->ioc->id, mf);
+                                       spin_lock_irqsave(&ioc->FreeQlock, flags);
+                                       hd->tmPending = 0;
+                                       spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+                                       continue;
+                               }
+
+                               task_type = mf->u.frame.linkage.arg1;
+                               ctx2abort = 0;
+                               if (task_type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {
+                                       MPT_FRAME_HDR   *SCpntMf;
+
+                                       /*
+                                        * 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
+                                        */
+                                       SCpntMf = (MPT_FRAME_HDR *) SCpnt->host_scribble;
+                                       ctx2abort = SCpntMf->u.frame.hwhdr.msgctxu.MsgContext;
+
+                                       hd->abortSCpnt = SCpnt;
+                                       printk(KERN_WARNING MYNAM ": Attempting ABORT SCSI IO! (mf=%p:sc=%p)\n",
+                                                       (void *) mf, (void *) SCpnt);
+                               }
+
+                               /* The TM handler will allocate a new mf,
+                                * so free the current mf.
+                                */
+                               mpt_free_msg_frame(ScsiTaskCtx, hd->ioc->id, mf);
+                               mf = NULL;
+
+                               if (mptscsih_TMHandler(hd, task_type, SCpnt->target, SCpnt->lun, ctx2abort, NO_SLEEP) < 0) {
+
+                                       /* The TM request failed and the subsequent FW-reload failed!
+                                        * Fatal error case.
+                                        */
+                                       printk(KERN_WARNING MYNAM
+                                               ": WARNING[1] - IOC error processing TaskMgmt request (sc=%p)\n", (void *) SCpnt);
+
+                                       if (hd->ScsiLookup[scpnt_idx] != NULL) {
+                                               atomic_dec(&queue_depth);
+                                               SCpnt->result = DID_SOFT_ERROR << 16;
+                                                MPT_HOST_LOCK(flags);
+                                               SCpnt->scsi_done(SCpnt);
+                                                MPT_HOST_UNLOCK(flags);
+                                               mpt_free_msg_frame(ScsiTaskCtx, hd->ioc->id, mf);
+                                       }
+                                       spin_lock_irqsave(&ioc->FreeQlock, flags);
+                                       hd->tmPending = 0;
+                                       spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+                                       hd->abortSCpnt = NULL;
+                               }
+                       }
+               }
+               if (atomic_read(&mpt_taskQdepth) > 0)
+                       did++;
+
+       } while ( did );
+
+       spin_lock_irqsave(&mytaskQ_lock, flags);
+       mytaskQ_bh_active = 0;
+       spin_unlock_irqrestore(&mytaskQ_lock, flags);
+
+       return;
+}
+#endif         /* } */
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mptscsih_taskmgmt_complete - Registered with Fusion MPT base driver
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @mf: Pointer to SCSI task mgmt request frame
+ *     @mr: 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 *mr)
+{
+       SCSITaskMgmtReply_t     *pScsiTmReply;
+       SCSITaskMgmt_t          *pScsiTmReq;
+       MPT_SCSI_HOST           *hd = NULL;
+       unsigned long            flags;
+       u8                       tmType = 0;
+
+       dtmprintk((MYIOC_s_INFO_FMT "SCSI TaskMgmt completed (mf=%p,r=%p)\n",
+                       ioc->name, mf, mr));
+       if (ioc->sh) {
+               /* Depending on the thread, a timer is activated for
+                * the TM request.  Delete this timer on completion of TM.
+                * Decrement count of outstanding TM requests.
+                */
+               hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
+               if (hd->tmPtr) {
+                       del_timer(&hd->TMtimer);
+               }
+               dtmprintk((MYIOC_s_INFO_FMT "taskQcnt (%d)\n",
+                       ioc->name, hd->taskQcnt));
+       } else {
+               dtmprintk((MYIOC_s_WARN_FMT "TaskMgmt Complete: NULL Scsi Host Ptr\n",
+                       ioc->name));
+               return 1;
+       }
+
+       if (mr == NULL) {
+               dtmprintk((MYIOC_s_WARN_FMT "ERROR! TaskMgmt Reply: NULL Request %p\n",
+                       ioc->name, mf));
+               return 1;
+       } else {
+               pScsiTmReply = (SCSITaskMgmtReply_t*)mr;
+               pScsiTmReq = (SCSITaskMgmt_t*)mf;
+
+               /* Figure out if this was ABORT_TASK, TARGET_RESET, or BUS_RESET! */
+               tmType = pScsiTmReq->TaskType;
+
+               dtmprintk((KERN_INFO "  TaskType = %d, TerminationCount=%d\n",
+                               tmType, le32_to_cpu(pScsiTmReply->TerminationCount)));
+
+               /* Error?  (anything non-zero?) */
+               if (*(u32 *)&pScsiTmReply->Reserved2[0]) {
+                       u16      iocstatus;
+
+                       iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK;
+                       dtmprintk((KERN_INFO "  SCSI TaskMgmt (%d) - Oops!\n", tmType));
+                       dtmprintk((KERN_INFO "  IOCStatus = %04xh\n", iocstatus));
+                       dtmprintk((KERN_INFO "  IOCLogInfo = %08xh\n",
+                                le32_to_cpu(pScsiTmReply->IOCLogInfo)));
+
+                       /* clear flags and continue.
+                        */
+                       if (tmType == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK)
+                               hd->abortSCpnt = NULL;
+#ifdef DROP_TEST
+                       if (dropMfPtr)
+                               dropTestBad++;
+#endif
+                       /* If an internal command is present
+                        * or the TM failed - reload the FW.
+                        * FC FW may respond FAILED to an ABORT
+                        */
+                       if (tmType == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) {
+                               if ((hd->cmdPtr) ||
+                                   (iocstatus == MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED)) {
+                                       if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0) {
+                                               printk((KERN_WARNING
+                                                       " Firmware Reload FAILED!!\n"));
+                                       }
+                               }
+                       }
+#ifdef MPT_SCSI_USE_NEW_EH
+                       hd->tmState = TM_STATE_ERROR;
+#endif
+               } else {
+                       dtmprintk((KERN_INFO "  SCSI TaskMgmt SUCCESS!\n"));
+
+#ifndef MPT_SCSI_USE_NEW_EH
+                       if (tmType == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) {
+                               /* clean taskQ - remove tasks associated with
+                                * completed commands.
+                                */
+                               clean_taskQ(hd);
+                       } else if (tmType == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {
+                               /* If taskQ contains another request
+                                * for this SCpnt, delete this request.
+                                */
+                               search_taskQ_for_cmd(hd->abortSCpnt, hd);
+                       }
+#endif
+                       hd->numTMrequests--;
+                       hd->abortSCpnt = NULL;
+                       flush_doneQ(hd);
+
+#ifdef DROP_TEST
+                       if (dropMfPtr)
+                               dropTestOK++;
+#endif
+               }
+       }
+
+#ifdef DROP_TEST
+       {
+               Scsi_Cmnd       *sc;
+               unsigned long    flags;
+               u16              req_idx;
+
+               /* Free resources for the drop test MF and chain buffers.
+                */
+               if (dropMfPtr) {
+                       req_idx = le16_to_cpu(dropMfPtr->u.frame.hwhdr.msgctxu.fld.req_idx);
+                       sc = hd->ScsiLookup[req_idx];
+                       if (sc == NULL) {
+                               printk(MYIOC_s_ERR_FMT
+                                       "Drop Test: NULL ScsiCmd ptr!\n",
+                                       ioc->name);
+                       } else {
+                               sc->host_scribble = NULL;
+                               if (tmType == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS)
+                                       sc->result = DID_RESET << 16;
+                               else
+                                       sc->result = DID_ABORT << 16;
+
+                               hd->ScsiLookup[req_idx] = NULL;
+                               atomic_dec(&queue_depth);
+                                MPT_HOST_LOCK(flags);
+                               sc->scsi_done(sc);      /* Issue callback */
+                                MPT_HOST_UNLOCK(flags);
+
+                               mptscsih_freeChainBuffers(hd, req_idx);
+                               mpt_free_msg_frame(ScsiDoneCtx, ioc->id, dropMfPtr);
+
+                               printk(MYIOC_s_INFO_FMT
+                                               "Free'd Dropped cmd (%p)\n",
+                                               hd->ioc->name, sc);
+                               printk(MYIOC_s_INFO_FMT
+                                               "mf (%p) reqidx (%4x)\n",
+                                               hd->ioc->name, dropMfPtr,
+                                               req_idx);
+                               printk(MYIOC_s_INFO_FMT
+                                       "Num Tot (%d) Good (%d) Bad (%d) \n",
+                                       hd->ioc->name, dropTestNum,
+                                       dropTestOK, dropTestBad);
+                       }
+                       dropMfPtr = NULL;
+               }
+       }
+#endif
+
+#ifndef MPT_SCSI_USE_NEW_EH
+       /*
+        *  Signal to _bh thread that we finished.
+        *  This IOC can now process another TM command.
+        */
+       dtmprintk((MYIOC_s_INFO_FMT "taskmgmt_complete: (=%p) done! Num Failed(%d) Task Count (%d)\n",
+                       ioc->name, mf, hd->numTMrequests, hd->taskQcnt));
+#endif
+       hd->tmPtr = NULL;
+       spin_lock_irqsave(&ioc->FreeQlock, flags);
+       hd->tmPending = 0;
+       spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+
+       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;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     OS entry point to adjust the queue_depths on a per-device basis.
+ *     Called once per device the bus scan. Use it to force the queue_depth
+ *     member to 1 if a device does not support Q tags.
+ */
+void
+mptscsih_select_queue_depths(struct Scsi_Host *sh, Scsi_Device *sdList)
+{
+       struct scsi_device      *device;
+       VirtDevice              *pTarget;
+       MPT_SCSI_HOST           *hd;
+       int                      ii, max;
+
+       for (device = sdList; device != NULL; device = device->next) {
+
+               if (device->host != sh)
+                       continue;
+
+               hd = (MPT_SCSI_HOST *) sh->hostdata;
+               if (hd == NULL)
+                       continue;
+
+               if (hd->Targets != NULL) {
+                       if (hd->is_spi)
+                               max = MPT_MAX_SCSI_DEVICES;
+                       else
+                               max = MPT_MAX_FC_DEVICES;
+
+                       for (ii=0; ii < max; ii++) {
+                               pTarget = hd->Targets[ii];
+                               if (pTarget && !(pTarget->tflags & MPT_TARGET_FLAGS_Q_YES)) {
+                                       device->queue_depth = 1;
+                               }
+                       }
+               }
+       }
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *  Private routines...
+ */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/* 19991030 -sralston
+ *  Return absolute SCSI data direction:
+ *     1 = _DATA_OUT
+ *     0 = _DIR_NONE
+ *    -1 = _DATA_IN
+ *
+ * Changed: 3-20-2002 pdelaney to use the default data
+ * direction and the defines set up in the
+ * 2.4 kernel series
+ *     1 = _DATA_OUT   changed to SCSI_DATA_WRITE (1)
+ *     0 = _DIR_NONE   changed to SCSI_DATA_NONE (3)
+ *    -1 = _DATA_IN    changed to SCSI_DATA_READ (2)
+ * If the direction is unknown, fall through to original code.
+ */
+static int
+mptscsih_io_direction(Scsi_Cmnd *cmd)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+       if (cmd->sc_data_direction != SCSI_DATA_UNKNOWN)
+               return cmd->sc_data_direction;
+#endif
+       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:
+       case 0xa3:
+               return SCSI_DATA_WRITE;
+
+       /*  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 SCSI_DATA_NONE;
+
+       /*  Conditional data transfer commands  */
+       case FORMAT_UNIT:
+               if (cmd->cmnd[1] & 0x10)        /* FmtData (data out phase)? */
+                       return SCSI_DATA_WRITE;
+               else
+                       return SCSI_DATA_NONE;
+
+       case VERIFY:
+               if (cmd->cmnd[1] & 0x02)        /* VERIFY:BYTCHK (data out phase)? */
+                       return SCSI_DATA_WRITE;
+               else
+                       return SCSI_DATA_NONE;
+
+       case RESERVE_10:
+               if (cmd->cmnd[1] & 0x03)        /* RESERVE:{LongID|Extent} (data out phase)? */
+                       return SCSI_DATA_WRITE;
+               else
+                       return SCSI_DATA_NONE;
+
+#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 SCSI_DATA_READ;
+       }
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/* Utility function to copy sense data from the scsi_cmnd buffer
+ * to the FC and SCSI target structures.
+ *
+ */
+static void
+copy_sense_data(Scsi_Cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply)
+{
+       VirtDevice      *target;
+       SCSIIORequest_t *pReq;
+       u32              sense_count = le32_to_cpu(pScsiReply->SenseCount);
+       int              index;
+       char             devFoo[96];
+       IO_Info_t        thisIo;
+
+       /* Get target structure
+        */
+       pReq = (SCSIIORequest_t *) mf;
+       index = (int) pReq->TargetID;
+       target = hd->Targets[index];
+       if (hd->is_multipath && sc->device->hostdata)
+               target = (VirtDevice *) 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 * MPT_SENSE_BUFFER_ALLOC));
+               memcpy(sc->sense_buffer, sense_data, SNS_LEN(sc));
+
+               /* save sense data to the target device
+                */
+               if (target) {
+                       int sz;
+
+                       sz = MIN(pReq->SenseBufferLength, sense_count);
+                       if (sz > SCSI_STD_SENSE_BYTES)
+                               sz =  SCSI_STD_SENSE_BYTES;
+                       memcpy(target->sense, sense_data, sz);
+                       target->tflags |= MPT_TARGET_FLAGS_VALID_SENSE;
+               }
+
+               /* Log SMART data (asc = 0x5D, non-IM case only) if required.
+                */
+               if ((hd->ioc->events) && (hd->ioc->eventTypes & (1 << MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE))) {
+                       if ((sense_data[12] == 0x5D) && (target->raidVolume == 0)) {
+                               int idx;
+                               MPT_ADAPTER *ioc = hd->ioc;
+
+                               idx = ioc->eventContext % ioc->eventLogSize;
+                               ioc->events[idx].event = MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE;
+                               ioc->events[idx].eventContext = ioc->eventContext;
+
+                               ioc->events[idx].data[0] = (pReq->LUN[1] << 24) ||
+                                       (MPI_EVENT_SCSI_DEV_STAT_RC_SMART_DATA << 16) ||
+                                       (pReq->Bus << 8) || pReq->TargetID;
+
+                               ioc->events[idx].data[1] = (sense_data[13] << 8) || sense_data[12];
+
+                               ioc->eventContext++;
+                       }
+               }
+
+               /* Print an error report for the user.
+                */
+               thisIo.cdbPtr = sc->cmnd;
+               thisIo.sensePtr = sc->sense_buffer;
+               thisIo.SCSIStatus = pScsiReply->SCSIStatus;
+               thisIo.DoDisplay = 1;
+               if (hd->is_multipath)
+                       sprintf(devFoo, "%d:%d:%d \"%s\"",
+                                       hd->ioc->id,
+                                       pReq->TargetID,
+                                       pReq->LUN[1],
+                                       target->dev_vol_name);
+               else
+                       sprintf(devFoo, "%d:%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);
+
+       } else {
+               dprintk((MYIOC_s_INFO_FMT "Hmmm... SenseData len=0! (?)\n",
+                               hd->ioc->name));
+       }
+
+       return;
+}
+
+static u32
+SCPNT_TO_LOOKUP_IDX(Scsi_Cmnd *sc)
+{
+       MPT_SCSI_HOST *hd;
+       int i;
+
+       hd = (MPT_SCSI_HOST *) sc->host->hostdata;
+
+       for (i = 0; i < hd->ioc->req_depth; i++) {
+               if (hd->ScsiLookup[i] == sc) {
+                       return i;
+               }
+       }
+
+       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
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/* Search the pendingQ for a command with specific index.
+ * If found, delete and return mf pointer  
+ * If not found, return NULL
+ */
+static MPT_FRAME_HDR *
+mptscsih_search_pendingQ(MPT_SCSI_HOST *hd, int scpnt_idx)
+{
+       unsigned long    flags;
+       MPT_DONE_Q      *buffer;
+       MPT_FRAME_HDR   *mf = NULL;
+       MPT_FRAME_HDR   *cmdMfPtr = NULL;
+
+       ddvtprintk((MYIOC_s_INFO_FMT ": search_pendingQ called...", hd->ioc->name));
+       cmdMfPtr = MPT_INDEX_2_MFPTR(hd->ioc, scpnt_idx);
+       spin_lock_irqsave(&hd->freedoneQlock, flags);
+       if (!Q_IS_EMPTY(&hd->pendingQ)) {
+               buffer = hd->pendingQ.head;
+               do {
+                       mf = (MPT_FRAME_HDR *) buffer->argp;
+                       if (mf == cmdMfPtr) {
+                               Q_DEL_ITEM(buffer);
+
+                               /* clear the arg pointer
+                                */
+                               buffer->argp = NULL;
+
+                               /* Add to the freeQ
+                                */
+                               Q_ADD_TAIL(&hd->freeQ.head, buffer, MPT_DONE_Q);
+                               break;
+                       }
+                       mf = NULL;
+               } while ((buffer = buffer->forw) != (MPT_DONE_Q *) &hd->pendingQ);
+       }
+       spin_unlock_irqrestore(&hd->freedoneQlock, flags);
+       ddvtprintk((" ...return %p\n", mf));
+       return mf;
+}
+
+/* Post all commands on the pendingQ to the FW.
+ * Lock Q when deleting/adding members
+ * Lock io_request_lock for OS callback.
+ */
+static void
+post_pendingQ_commands(MPT_SCSI_HOST *hd)
+{
+       MPT_FRAME_HDR   *mf;
+       MPT_DONE_Q      *buffer;
+       unsigned long    flags;
+
+       /* Flush the pendingQ.
+        */
+       ddvtprintk((MYIOC_s_INFO_FMT ": post_pendingQ_commands called\n", hd->ioc->name));
+       while (1) {
+               spin_lock_irqsave(&hd->freedoneQlock, flags);
+               if (Q_IS_EMPTY(&hd->pendingQ)) {
+                       spin_unlock_irqrestore(&hd->freedoneQlock, flags);
+                       break;
+               }
+
+               buffer = hd->pendingQ.head;
+               /* Delete from Q
+                */
+               Q_DEL_ITEM(buffer);
+
+               mf = (MPT_FRAME_HDR *) buffer->argp;
+               buffer->argp = NULL;
+
+               /* Add to the freeQ
+                */
+               Q_ADD_TAIL(&hd->freeQ.head, buffer, MPT_DONE_Q);
+               spin_unlock_irqrestore(&hd->freedoneQlock, flags);
+
+               if (!mf) {
+                       /* This should never happen */
+                       printk(MYIOC_s_WARN_FMT "post_pendingQ_commands: mf %p\n", hd->ioc->name, (void *) mf);
+                       continue;
+               }
+
+               mptscsih_put_msgframe(ScsiDoneCtx, hd->ioc->id, mf);
+               ddvtprintk((MYIOC_s_INFO_FMT "Issued SCSI cmd (mf=%p)\n",
+                               hd->ioc->name, mf));
+       }
+
+       return;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
+{
+       MPT_SCSI_HOST   *hd = NULL;
+       unsigned long    flags;
+
+       dtmprintk((KERN_WARNING MYNAM
+                       ": IOC %s_reset routed to SCSI host driver!\n",
+                       reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post"));
+
+       /* If a FW reload request arrives after base installed but
+        * before all scsi hosts have been attached, then an alt_ioc
+        * may have a NULL sh pointer.
+        */
+       if ((ioc->sh == NULL) || (ioc->sh->hostdata == NULL))
+               return 0;
+       else
+               hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
+
+       if (reset_phase == MPT_IOC_PRE_RESET) {
+               dtmprintk((MYIOC_s_WARN_FMT "Do Pre-Diag Reset handling\n",
+                       ioc->name));
+
+               /* Clean Up:
+                * 1. Set Hard Reset Pending Flag
+                * All new commands go to doneQ
+                */
+               hd->resetPending = 1;
+
+               /* 2. Flush running commands
+                *      Clean drop test code - if compiled
+                *      Clean ScsiLookup (and associated memory)
+                *      AND clean mytaskQ
+                */
+
+               /* 2a. Drop Test Command.
+                */
+#ifdef DROP_TEST
+               {
+                       Scsi_Cmnd       *sc;
+                       unsigned long    flags;
+                       u16              req_idx;
+
+                       /* Free resources for the drop test MF
+                        * and chain buffers.
+                        */
+                       if (dropMfPtr) {
+                               req_idx = le16_to_cpu(dropMfPtr->u.frame.hwhdr.msgctxu.fld.req_idx);
+                               sc = hd->ScsiLookup[req_idx];
+                               if (sc == NULL) {
+                                       printk(MYIOC_s_ERR_FMT
+                                       "Drop Test: NULL ScsiCmd ptr!\n",
+                                       ioc->name);
+                               } else {
+                                       sc->host_scribble = NULL;
+                                       sc->result = DID_RESET << 16;
+                                       hd->ScsiLookup[req_idx] = NULL;
+                                       atomic_dec(&queue_depth);
+                                        MPT_HOST_LOCK(flags);
+                                       sc->scsi_done(sc);      /* Issue callback */
+                                        MPT_HOST_UNLOCK(flags);
+                               }
+
+                               mptscsih_freeChainBuffers(hd, req_idx);
+                               mpt_free_msg_frame(ScsiDoneCtx, ioc->id, dropMfPtr);
+                               printk(MYIOC_s_INFO_FMT
+                                               "Free'd: mf (%p) reqidx (%4x)\n",
+                                               hd->ioc->name, dropMfPtr,
+                                               req_idx);
+                       }
+                       dropMfPtr = NULL;
+               }
+#endif
+
+               /* 2b. Reply to OS all known outstanding I/O commands.
+                */
+               mptscsih_flush_running_cmds(hd);
+
+               /* 2c. If there was an internal command that
+                * has not completed, configuration or io request,
+                * free these resources.
+                */
+               if (hd->cmdPtr) {
+                       del_timer(&hd->timer);
+                       mpt_free_msg_frame(ScsiScanDvCtx, ioc->id, hd->cmdPtr);
+                       atomic_dec(&queue_depth);
+               }
+
+               /* 2d. If a task management has not completed,
+                * free resources associated with this request.
+                */
+               if (hd->tmPtr) {
+                       del_timer(&hd->TMtimer);
+                       mpt_free_msg_frame(ScsiTaskCtx, ioc->id, hd->tmPtr);
+               }
+
+#ifndef MPT_SCSI_USE_NEW_EH
+               /* 2e. Delete all commands on taskQ
+                * Should be superfluous - as this taskQ should
+                * be empty.
+                */
+               clean_taskQ(hd);
+#endif
+               dtmprintk((MYIOC_s_WARN_FMT "Pre-Reset handling complete.\n",
+                       ioc->name));
+
+       } else {
+               dtmprintk((MYIOC_s_WARN_FMT "Do Post-Diag Reset handling\n",
+                       ioc->name));
+
+               /* Once a FW reload begins, all new OS commands are
+                * redirected to the doneQ w/ a reset status.
+                * Init all control structures.
+                */
+
+               /* ScsiLookup initialization
+                */
+               {
+                       int ii;
+                       for (ii=0; ii < hd->ioc->req_depth; ii++)
+                               hd->ScsiLookup[ii] = NULL;
+               }
+
+               /* 2. Chain Buffer initialization
+                */
+               mptscsih_initChainBuffers(hd, 0);
+
+               /* 3. tmPtr clear
+                */
+               if (hd->tmPtr) {
+                       hd->tmPtr = NULL;
+               }
+
+               /* 4. Renegotiate to all devices, if SCSI
+                */
+               if (hd->is_spi)
+                       mptscsih_writeSDP1(hd, 0, 0, MPT_SCSICFG_ALL_IDS | MPT_SCSICFG_USE_NVRAM);
+
+               /* 5. Enable new commands to be posted
+                */
+               spin_lock_irqsave(&ioc->FreeQlock, flags);
+               hd->tmPending = 0;
+               spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+               hd->resetPending = 0;
+               hd->numTMrequests = 0;
+
+               /* 6. If there was an internal command,
+                * wake this process up.
+                */
+               if (hd->cmdPtr) {
+                       /*
+                        * Wake up the original calling thread
+                        */
+                       hd->pLocal = &hd->localReply;
+                       hd->pLocal->completion = MPT_SCANDV_DID_RESET;
+                       scandv_wait_done = 1;
+                       wake_up(&scandv_waitq);
+                       hd->cmdPtr = NULL;
+               }
+
+               /* 7. Flush doneQ
+                */
+               flush_doneQ(hd);
+
+               dtmprintk((MYIOC_s_WARN_FMT "Post-Reset handling complete.\n",
+                       ioc->name));
+       }
+
+       return 1;               /* currently means nothing really */
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
+{
+       MPT_SCSI_HOST *hd;
+       u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
+
+       dprintk((MYIOC_s_INFO_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n",
+                       ioc->name, 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...
+                */
+               break;
+
+       case MPI_EVENT_INTEGRATED_RAID:                 /* 0B */
+#ifndef MPTSCSIH_DISABLE_DOMAIN_VALIDATION
+               /* negoNvram set to 0 if DV enabled and to USE_NVRAM if 
+                * if DV disabled. Need to check for target mode.
+                */
+               hd = NULL;
+               if (ioc->sh)
+                       hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
+
+               if (hd && (hd->is_spi) && (hd->negoNvram == 0)) {
+                       ScsiCfgData     *pSpi;
+                       Ioc3PhysDisk_t  *pPDisk;
+                       int              numPDisk;
+                       u8               reason;
+                       u8               physDiskNum;
+                       
+                       reason = (le32_to_cpu(pEvReply->Data[0]) & 0x00FF0000) >> 16;
+                       if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) {
+                               /* New or replaced disk. 
+                                * Set DV flag and schedule DV.
+                                */
+                               pSpi = &ioc->spi_data;
+                               physDiskNum = (le32_to_cpu(pEvReply->Data[0]) & 0xFF000000) >> 24;
+                               if (pSpi->pIocPg3) {
+                                       pPDisk =  pSpi->pIocPg3->PhysDisk;
+                                       numPDisk =pSpi->pIocPg3->NumPhysDisks;
+
+                                       while (numPDisk) {
+                                               if (physDiskNum == pPDisk->PhysDiskNum) {
+                                                       pSpi->dvStatus[pPDisk->PhysDiskID] = MPT_SCSICFG_NEED_DV;
+                                                       pSpi->forceDv = MPT_SCSICFG_NEED_DV;
+                                                       ddvtprintk(("NEED_DV set for phys disk id %d\n", pPDisk->PhysDiskID));
+                                                       break;
+                                               }
+                                               pPDisk++;
+                                               numPDisk--;
+                                       }
+                               }
+                       }
+               }
+#endif
+
+#if defined(MPT_DEBUG_DV) || defined(MPT_DEBUG_DV_TINY)
+               printk("Raid Event RF: ");
+               {
+                       u32 *m = (u32 *)pEvReply;
+                       int ii;
+                       int n = (int)pEvReply->MsgLength;
+                       for (ii=6; ii < n; ii++)
+                               printk(" %08x", le32_to_cpu(m[ii]));
+                       printk("\n");
+               }
+#endif
+               break;
+
+       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 "  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;
+
+#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 */
@@ -2222,375 +4283,3096 @@ static const char *PeripheralDeviceTypeString[32] = {
 };
 #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 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().
+ */
+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 "dont 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)) {
+                       *s1 = mptscsih_ASCQ_TablePtr[idx].Description;
+                       return *s1;
+               }
+
+       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_NO_SENSE) {
+               return 0;
+       }
+       if (    (sk==SK_UNIT_ATTENTION  && asc==0x29 && (ascq==0x00 || ascq==0x01))
+            || (sk==SK_NOT_READY       && asc==0x04 && (ascq==0x01 || ascq==0x02))
+            || (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;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     mptscsih_initTarget - Target, LUN alloc/free functionality.
+ *     @hd: Pointer to MPT_SCSI_HOST structure
+ *     @bus_id: Bus number (?)
+ *     @target_id: SCSI target id
+ *     @lun: SCSI LUN id
+ *     @data: Pointer to data
+ *     @dlen: Number of INQUIRY bytes
+ *
+ *     NOTE: It's only SAFE to call this routine if data points to
+ *     sane & valid STANDARD INQUIRY data!
+ *
+ *     Allocate and initialize memory for this target.
+ *     Save inquiry data.
+ *
+ *     Returns pointer to VirtDevice structure.
+ */
+static VirtDevice *
+mptscsih_initTarget(MPT_SCSI_HOST *hd, int bus_id, int target_id, u8 lun, char *data, int dlen)
+{
+       VirtDevice      *vdev;
+       int              sz;
+
+       dprintk((MYIOC_s_INFO_FMT "initTarget (%d,%d,%d) called, hd=%p\n",
+                       hd->ioc->name, bus_id, target_id, lun, hd));
+
+       if ((vdev = hd->Targets[target_id]) == NULL) {
+               if ((vdev = kmalloc(sizeof(VirtDevice), GFP_ATOMIC)) == NULL) {
+                       printk(MYIOC_s_ERR_FMT "initTarget kmalloc(%d) FAILED!\n",
+                                       hd->ioc->name, (int)sizeof(VirtDevice));
+               } else {
+                       memset(vdev, 0, sizeof(VirtDevice));
+                       rwlock_init(&vdev->VdevLock);
+                       Q_INIT(&vdev->WaitQ, void);
+                       Q_INIT(&vdev->SentQ, void);
+                       Q_INIT(&vdev->DoneQ, void);
+                       vdev->tflags = 0;
+                       vdev->ioc_id = hd->ioc->id;
+                       vdev->target_id = target_id;
+                       vdev->bus_id = bus_id;
+
+                       hd->Targets[target_id] = vdev;
+                       dprintk((KERN_INFO "  *NEW* Target structure (id %d) @ %p\n",
+                                       target_id, vdev));
+               }
+       }
+
+       if (vdev) {
+               if (hd->ioc->spi_data.isRaid & (1 << target_id))
+                       vdev->raidVolume = 1;
+               else
+                       vdev->raidVolume = 0;
+       }
+
+       if (vdev && data) {
+               if (!(vdev->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY)) {
+
+                       /* Copy the inquiry data  - if we haven't yet.
+                       */
+                       sz = MIN(dlen, SCSI_STD_INQUIRY_BYTES);
+
+                       memcpy (vdev->inq_data, data, sz);
+                       vdev->tflags |= MPT_TARGET_FLAGS_VALID_INQUIRY;
+
+                       /* Update the target capabilities
+                        */
+                       if (dlen > 56)
+                               mptscsih_setTargetNegoParms(hd, vdev, data[56]);
+                       else
+                               mptscsih_setTargetNegoParms(hd, vdev, 0);
+               }
+
+               /* Is LUN supported? If so, upper 3 bits will be 0
+                * in first byte of inquiry data.
+                */
+               if ((*data & 0xe0) == 0)
+                       vdev->luns |= (1 << lun);
+       }
+
+
+       dprintk((KERN_INFO "  target = %p\n", vdev));
+       return vdev;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *  Update the target negotiation parameters based on the
+ *  the Inquiry data, adapter capabilities, and NVRAM settings.
+ *
+ */
+void mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtDevice *target, char byte56)
+{
+       ScsiCfgData *pspi_data = &hd->ioc->spi_data;
+       int  id = (int) target->target_id;
+       int  nvram;
+       char canQ = 0;
+       u8 width = MPT_NARROW;
+       u8 factor = MPT_ASYNC;
+       u8 offset = 0;
+       u8 version, nfactor;
+       u8 noQas = 1;
+
+       /* Set flags based on Inquiry data
+        */
+       if (target->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY) {
+               version = target->inq_data[2] & 0x03;
+               if (version < 2) {
+                       width = 0;
+                       factor = MPT_ULTRA2;
+                       offset = pspi_data->maxSyncOffset;
+               } else {
+                       if (target->inq_data[7] & 0x20) {
+                               width = 1;
+                       }
+
+                       if (target->inq_data[7] & 0x10) {
+                               /* bits 2 & 3 show DT support
+                                */
+                               if ((byte56 & 0x04) == 0)
+                                       factor = MPT_ULTRA2;
+                               else
+                                       factor = MPT_ULTRA320;
+
+                               /* bit 1 QAS support, non-raid only
+                                */
+                               if ((target->raidVolume == 0) && (byte56 & 0x02) != 0)
+                                       noQas = 0;
+
+                               offset = pspi_data->maxSyncOffset;
+                       } else {
+                               factor = MPT_ASYNC;
+                               offset = 0;
+                       }
+               }
+
+               if (target->inq_data[7] & 0x02) {
+                       canQ = 1;
+               }
+
+               /* Update tflags based on NVRAM settings. (SCSI only)
+                */
+               if (pspi_data->nvram && (pspi_data->nvram[id] != MPT_HOST_NVRAM_INVALID)) {
+                       nvram = pspi_data->nvram[id];
+                       nfactor = (nvram & MPT_NVRAM_SYNC_MASK) >> 8;
+
+                       if (width)
+                               width = nvram & MPT_NVRAM_WIDE_DISABLE ? 0 : 1;
+
+                       if (offset > 0) {
+                               /* Ensure factor is set to the
+                                * maximum of: adapter, nvram, inquiry
+                                */
+                               if (nfactor) {
+                                       if (nfactor < pspi_data->minSyncFactor )
+                                               nfactor = pspi_data->minSyncFactor;
+
+                                       factor = MAX (factor, nfactor);
+                                       if (factor == MPT_ASYNC)
+                                               offset = 0;
+                               } else {
+                                       offset = 0;
+                                       factor = MPT_ASYNC;
+                               }
+                       } else {
+                               factor = MPT_ASYNC;
+                       }
+               }
+
+               /* Make sure data is consistent
+                */
+               if ((!width) && (factor < MPT_ULTRA2)) {
+                       factor = MPT_ULTRA2;
+               }
+
+               /* Save the data to the target structure.
+                */
+               target->minSyncFactor = factor;
+               target->maxOffset = offset;
+               target->maxWidth = width;
+               if (canQ) {
+                       target->tflags |= MPT_TARGET_FLAGS_Q_YES;
+               }
+
+               target->tflags |= MPT_TARGET_FLAGS_VALID_NEGO;
+
+               /* Disable unused features.
+                */
+               target->negoFlags = pspi_data->noQas;
+               if (!width)
+                       target->negoFlags |= MPT_TARGET_NO_NEGO_WIDE;
+
+               if (!offset)
+                       target->negoFlags |= MPT_TARGET_NO_NEGO_SYNC;
+
+               if (noQas)
+                       target->negoFlags |= MPT_TARGET_NO_NEGO_QAS;
+
+               /* GEM, processor WORKAROUND
+                */
+               if (((target->inq_data[0] & 0x1F) == 0x03) || ((target->inq_data[0] & 0x1F) > 0x08)){
+                       target->negoFlags |= (MPT_TARGET_NO_NEGO_WIDE | MPT_TARGET_NO_NEGO_SYNC);
+                       pspi_data->dvStatus[id] |= MPT_SCSICFG_BLK_NEGO;
+               }
+
+               /* Disable QAS if mixed configuration case
+                */
+               if ((noQas) && (!pspi_data->noQas) && ((target->inq_data[0] & 0x1F) == 0x00)){
+                       VirtDevice      *vdev;
+                       int ii;
+
+                       pspi_data->noQas = MPT_TARGET_NO_NEGO_QAS;
+                       for (ii = 0; ii < id; ii++) {
+                               vdev = hd->Targets[id];
+                               if (vdev != NULL)
+                                       vdev->negoFlags |= MPT_TARGET_NO_NEGO_QAS;
+                       }
+               }
+
+       }
+
+       return;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *  Clear sense valid flag.
+ */
+static void clear_sense_flag(MPT_SCSI_HOST *hd, SCSIIORequest_t *pReq)
+{
+       VirtDevice      *target;
+       int              index = (int) pReq->TargetID;
+
+       if ((target = hd->Targets[index])) {
+               target->tflags &= ~MPT_TARGET_FLAGS_VALID_SENSE;
+       }
+
+       return;
+}
+
+/* 
+ * If DV disabled (negoNvram set to USE_NVARM) or if not LUN 0, return.
+ * Else set the NEED_DV flag after Read Capacity Issued (disks) 
+ * or Mode Sense (cdroms). Tapes, key off of Inquiry command.
+ */
+static void mptscsih_set_dvflags(MPT_SCSI_HOST *hd, SCSIIORequest_t *pReq, char *data)
+{
+       u8 cmd = pReq->CDB[0];
+       
+       if (pReq->LUN[1] != 0)
+               return;
+
+       if (hd->negoNvram != 0)
+               return;
+
+       if ((cmd == READ_CAPACITY) || (cmd == MODE_SENSE) || 
+               ((cmd == INQUIRY) && ((data[0] & 0x1F) == 0x01))) {
+               u8 dvStatus = hd->ioc->spi_data.dvStatus[pReq->TargetID];
+               if (!(dvStatus & MPT_SCSICFG_DV_DONE)) {
+                       ScsiCfgData *pSpi = &hd->ioc->spi_data;
+                       if ((pSpi->isRaid & (1 << pReq->TargetID)) && pSpi->pIocPg3) {
+                               /* Set NEED_DV for all hidden disks
+                                */
+                               Ioc3PhysDisk_t *pPDisk =  pSpi->pIocPg3->PhysDisk;
+                               int             numPDisk = pSpi->pIocPg3->NumPhysDisks;
+                               
+                               while (numPDisk) {
+                                       pSpi->dvStatus[pPDisk->PhysDiskID] |= MPT_SCSICFG_NEED_DV;
+                                       ddvtprintk(("NEED_DV set for phys disk id %d\n", pPDisk->PhysDiskID));
+                                       pPDisk++;
+                                       numPDisk--;
+                               }
+                       }
+                       pSpi->dvStatus[pReq->TargetID] |= MPT_SCSICFG_NEED_DV;
+                       ddvtprintk(("NEED_DV set for visible disk id %d\n", 
+                                       pReq->TargetID));
+               };
+       }
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * If no Target, bus reset on 1st I/O. Set the flag to 
+ * prevent any future negotiations to this device.
+ */
+static void mptscsih_no_negotiate(MPT_SCSI_HOST *hd, int target_id)
+{
+
+       if ((hd->Targets) && (hd->Targets[target_id] == NULL))
+               hd->ioc->spi_data.dvStatus[target_id] |= MPT_SCSICFG_BLK_NEGO;
+
+       return;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *  SCSI Config Page functionality ...
+ */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*     mptscsih_setDevicePage1Flags  - add Requested and Configuration fields flags
+ *     based on width, factor and offset parameters.
+ *     @width: bus width
+ *     @factor: sync factor
+ *     @offset: sync offset
+ *     @requestedPtr: pointer to requested values (updated)
+ *     @configurationPtr: pointer to configuration values (updated)
+ *     @flags: flags to block WDTR or SDTR negotiation
+ *
+ *     Return: None.
+ *
+ *     Remark: Called by writeSDP1 and _dv_params
+ */
+static void
+mptscsih_setDevicePage1Flags (u8 width, u8 factor, u8 offset, int *requestedPtr, int *configurationPtr, u8 flags)
+{
+       u8 nowide = flags & MPT_TARGET_NO_NEGO_WIDE;
+       u8 nosync = flags & MPT_TARGET_NO_NEGO_SYNC;
+
+       *configurationPtr = 0;
+       *requestedPtr = width ? MPI_SCSIDEVPAGE1_RP_WIDE : 0;
+       *requestedPtr |= (offset << 16) | (factor << 8);
+
+       if (width && offset && !nowide && !nosync) {
+               if (factor < MPT_ULTRA160) {
+                       *requestedPtr |= (MPI_SCSIDEVPAGE1_RP_IU + MPI_SCSIDEVPAGE1_RP_DT);
+                       if ((flags & MPT_TARGET_NO_NEGO_QAS) == 0)
+                               *requestedPtr |= MPI_SCSIDEVPAGE1_RP_QAS;
+               } else if (factor < MPT_ULTRA2) {
+                       *requestedPtr |= MPI_SCSIDEVPAGE1_RP_DT;
+               }
+       }
+
+       if (nowide)
+               *configurationPtr |= MPI_SCSIDEVPAGE1_CONF_WDTR_DISALLOWED;
+
+       if (nosync)
+               *configurationPtr |= MPI_SCSIDEVPAGE1_CONF_SDTR_DISALLOWED;
+
+       return;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*     mptscsih_writeSDP1  - write SCSI Device Page 1
+ *     @hd: Pointer to a SCSI Host Strucutre
+ *     @portnum: IOC port number
+ *     @target_id: writeSDP1 for single ID
+ *     @flags: MPT_SCSICFG_ALL_IDS, MPT_SCSICFG_USE_NVRAM, MPT_SCSICFG_BLK_NEGO
+ *
+ *     Return: -EFAULT if read of config page header fails
+ *             or 0 if success.
+ *
+ *     Remark: If a target has been found, the settings from the
+ *             target structure are used, else the device is set
+ *             to async/narrow.
+ *
+ *     Remark: Called during init and after a FW reload.
+ *     Remark: We do not wait for a return, write pages sequentially.
+ */
+static int
+mptscsih_writeSDP1(MPT_SCSI_HOST *hd, int portnum, int target_id, int flags)
+{
+       MPT_ADAPTER             *ioc = hd->ioc;
+       Config_t                *pReq = NULL;
+       SCSIDevicePage1_t       *pData = NULL;
+       VirtDevice              *pTarget = NULL;
+       MPT_FRAME_HDR           *mf;
+       dma_addr_t               dataDma;
+       u16                      req_idx;
+       u32                      frameOffset;
+       u32                      requested, configuration, flagsLength;
+       int                      ii, nvram;
+       int                      id = 0, maxid = 0;
+       u8                       width;
+       u8                       factor;
+       u8                       offset;
+       u8                       bus = 0;
+       u8                       negoFlags;
+
+       if (ioc->spi_data.sdp1length == 0)
+               return 0;
+
+       if (flags & MPT_SCSICFG_ALL_IDS) {
+               id = 0;
+               maxid = ioc->sh->max_id - 1;
+       } else if (ioc->sh) {
+               id = target_id;
+               maxid = MIN(id, ioc->sh->max_id - 1);
+       }
+
+       for (; id <= maxid; id++) {
+               if (id == ioc->pfacts[portnum].PortSCSIID)
+                       continue;
+
+               if (flags & MPT_SCSICFG_USE_NVRAM) {
+                       /* Use NVRAM, adapter maximums and target settings.
+                        * Data over-riden by target structure information, if present
+                        */
+                       width = ioc->spi_data.maxBusWidth;
+                       offset = ioc->spi_data.maxSyncOffset;
+                       factor = ioc->spi_data.minSyncFactor;
+                       if (ioc->spi_data.nvram && (ioc->spi_data.nvram[id] != MPT_HOST_NVRAM_INVALID)) {
+                               nvram = ioc->spi_data.nvram[id];
+
+                               if (width)
+                                       width = nvram & MPT_NVRAM_WIDE_DISABLE ? 0 : 1;
+
+                               if (offset > 0) {
+                                       factor = (nvram & MPT_NVRAM_SYNC_MASK) >> 8;
+                                       if (factor == 0) {
+                                               /* Key for async */
+                                               factor = MPT_ASYNC;
+                                               offset = 0;
+                                       } else if (factor < ioc->spi_data.minSyncFactor) {
+                                               factor = ioc->spi_data.minSyncFactor;
+                                       }
+                               } else
+                                       factor = MPT_ASYNC;
+                       }
+
+                       /* Set the negotiation flags.
+                        */
+                       negoFlags = ioc->spi_data.noQas;
+                       if (!width)
+                               negoFlags |= MPT_TARGET_NO_NEGO_WIDE;
+       
+                       if (!offset)
+                               negoFlags |= MPT_TARGET_NO_NEGO_SYNC;
+               } else {
+                       width = 0;
+                       factor = MPT_ASYNC;
+                       offset = 0;
+                       negoFlags = MPT_TARGET_NO_NEGO_SYNC;
+               }
+
+               /* If id is not a raid volume, get the updated
+                * transmission settings from the target structure.
+                */
+               if (hd->Targets && (pTarget = hd->Targets[id]) && !pTarget->raidVolume) {
+                       width = pTarget->maxWidth;
+                       factor = pTarget->minSyncFactor;
+                       offset = pTarget->maxOffset;
+                       negoFlags = pTarget->negoFlags;
+                       pTarget = NULL;
+               }
+
+               if (flags & MPT_SCSICFG_BLK_NEGO)
+                       negoFlags = MPT_TARGET_NO_NEGO_WIDE | MPT_TARGET_NO_NEGO_SYNC;
+
+               /* REMOVE - can this be removed without problems?????
+               else if (negoFlags == (MPT_TARGET_NO_NEGO_WIDE | MPT_TARGET_NO_NEGO_SYNC))
+                       continue;
+               */
+
+               mptscsih_setDevicePage1Flags(width, factor, offset,
+                                       &requested, &configuration, negoFlags);
+
+
+               /* Get a MF for this command.
+                */
+               if ((mf = mpt_get_msg_frame(ScsiDoneCtx, ioc->id)) == NULL) {
+                       dprintk((MYIOC_s_WARN_FMT "write SDP1: no msg frames!\n",
+                                               ioc->name));
+                       return -EAGAIN;
+               }
+
+               /* Set the request and the data pointers.
+                * Request takes: 36 bytes (32 bit SGE)
+                * SCSI Device Page 1 requires 16 bytes
+                * 40 + 16 <= size of SCSI IO Request = 56 bytes
+                * and MF size >= 64 bytes.
+                * Place data at end of MF.
+                */
+               pReq = (Config_t *)mf;
+
+               req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
+               frameOffset = ioc->req_sz - sizeof(SCSIDevicePage1_t);
+
+               pData = (SCSIDevicePage1_t *)((u8 *) mf + frameOffset);
+               dataDma = ioc->req_frames_dma + (req_idx * ioc->req_sz) + frameOffset;
+
+               /* Complete the request frame (same for all requests).
+                */
+               pReq->Action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
+               pReq->Reserved = 0;
+               pReq->ChainOffset = 0;
+               pReq->Function = MPI_FUNCTION_CONFIG;
+               pReq->Reserved1[0] = 0;
+               pReq->Reserved1[1] = 0;
+               pReq->Reserved1[2] = 0;
+               pReq->MsgFlags = 0;
+               for (ii=0; ii < 8; ii++) {
+                       pReq->Reserved2[ii] = 0;
+               }
+               pReq->Header.PageVersion = ioc->spi_data.sdp1version;
+               pReq->Header.PageLength = ioc->spi_data.sdp1length;
+               pReq->Header.PageNumber = 1;
+               pReq->Header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
+               pReq->PageAddress = cpu_to_le32(id | (bus << 8 ));
+
+               /* Add a SGE to the config request.
+                */
+               flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE | ioc->spi_data.sdp1length * 4;
+
+               mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, dataDma);
+
+               /* Set up the common data portion
+                */
+               pData->Header.PageVersion = pReq->Header.PageVersion;
+               pData->Header.PageLength = pReq->Header.PageLength;
+               pData->Header.PageNumber = pReq->Header.PageNumber;
+               pData->Header.PageType = pReq->Header.PageType;
+               pData->RequestedParameters = cpu_to_le32(requested);
+               pData->Reserved = 0;
+               pData->Configuration = cpu_to_le32(configuration);
+
+               dprintk((MYIOC_s_INFO_FMT 
+                       "write SDP1: id %d pgaddr 0x%x req 0x%x config 0x%x\n",
+                               ioc->name, id, (id | (bus<<8)), 
+                               requested, configuration));
+
+               mptscsih_put_msgframe(ScsiDoneCtx, ioc->id, mf);
+       }
+
+       return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*     mptscsih_taskmgmt_timeout - Call back for timeout on a
+ *     task management request.
+ *     @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
+ *
+ */
+static void mptscsih_taskmgmt_timeout(unsigned long data)
+{
+       MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *) data;
+
+       dtmprintk((KERN_WARNING MYNAM ": %s: mptscsih_taskmgmt_timeout: "
+                  "TM request timed out!\n", hd->ioc->name));
+
+       /* Delete the timer that triggered this callback.
+        * Remark: del_timer checks to make sure timer is active
+        * before deleting.
+        */
+       del_timer(&hd->TMtimer);
+
+#ifdef MPT_SCSI_USE_NEW_EH
+       /* Set the error flag to 1 so that the function that started the
+        * task management request knows it timed out.
+        */
+       hd->tmState = TM_STATE_ERROR;
+#endif
+
+       /* Call the reset handler. Already had a TM request
+        * timeout - so issue a diagnostic reset
+        */
+       if (mpt_HardResetHandler(hd->ioc, NO_SLEEP) < 0) {
+               printk((KERN_WARNING " Firmware Reload FAILED!!\n"));
+       }
+#ifdef MPT_SCSI_USE_NEW_EH
+       else {
+               /* Because we have reset the IOC, no TM requests can be
+                * pending.  So let's make sure the tmPending flag is reset.
+                */
+               nehprintk((KERN_WARNING MYNAM 
+                          ": %s: mptscsih_taskmgmt_timeout\n", 
+                          hd->ioc->name));
+               hd->tmPending = 0;
+       }
+#endif
+
+       return;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *  Bus Scan and Domain Validation functionality ...
+ */
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     mptscsih_scandv_complete - Scan and DV callback routine registered
+ *     to Fustion MPT (base) driver.
+ *
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @mf: Pointer to original MPT request frame
+ *     @mr: 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.
+ *
+ *     Remark: Sets a completion code and (possibly) saves sense data
+ *     in the IOC member localReply structure.
+ *     Used ONLY for bus scan, DV and other internal commands.
+ */
+static int
+mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
+{
+       MPT_SCSI_HOST   *hd;
+       SCSIIORequest_t *pReq;
+       int              completionCode;
+       u16              req_idx;
+
+       if ((mf == NULL) ||
+           (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) {
+               printk(MYIOC_s_ERR_FMT
+                       "ScanDvComplete, %s req frame ptr! (=%p)\n",
+                               ioc->name, mf?"BAD":"NULL", (void *) mf);
+               goto wakeup;
+       }
+
+       hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
+       del_timer(&hd->timer);
+       req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
+       hd->ScsiLookup[req_idx] = NULL;
+       pReq = (SCSIIORequest_t *) mf;
+
+       if (mf != hd->cmdPtr) {
+               printk(MYIOC_s_WARN_FMT "ScanDvComplete (mf=%p, cmdPtr=%p)\n",
+                               hd->ioc->name, (void *)mf, (void *) hd->cmdPtr);
+       }
+       hd->cmdPtr = NULL;
+
+       ddvprintk((MYIOC_s_INFO_FMT "ScanDvComplete (mf=%p,mr=%p)\n",
+                       hd->ioc->name, mf, mr));
+
+       atomic_dec(&queue_depth);
+
+       hd->pLocal = &hd->localReply;
+
+       /* If target struct exists, clear sense valid flag.
+        */
+       clear_sense_flag(hd, pReq);
+
+       if (mr == NULL) {
+               completionCode = MPT_SCANDV_GOOD;
+       } else {
+               SCSIIOReply_t   *pReply;
+               u16              status;
+
+               pReply = (SCSIIOReply_t *) mr;
+
+               status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
+
+               ddvprintk((KERN_NOTICE "  IOCStatus=%04xh, SCSIState=%02xh, SCSIStatus=%02xh, IOCLogInfo=%08xh\n",
+                            status, pReply->SCSIState, pReply->SCSIStatus,
+                            le32_to_cpu(pReply->IOCLogInfo)));
+
+               switch(status) {
+
+               case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE:       /* 0x0043 */
+                       completionCode = MPT_SCANDV_SELECTION_TIMEOUT;
+                       break;
+
+               case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR:          /* 0x0046 */
+               case MPI_IOCSTATUS_SCSI_TASK_TERMINATED:        /* 0x0048 */
+               case MPI_IOCSTATUS_SCSI_IOC_TERMINATED:         /* 0x004B */
+               case MPI_IOCSTATUS_SCSI_EXT_TERMINATED:         /* 0x004C */
+                       completionCode = MPT_SCANDV_DID_RESET;
+                       break;
+
+               case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN:          /* 0x0045 */
+               case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR:        /* 0x0040 */
+               case MPI_IOCSTATUS_SUCCESS:                     /* 0x0000 */
+                       if (pReply->Function == MPI_FUNCTION_CONFIG) {
+                               ConfigReply_t *pr = (ConfigReply_t *)mr;
+                               completionCode = MPT_SCANDV_GOOD;
+                               hd->pLocal->header.PageVersion = pr->Header.PageVersion;
+                               hd->pLocal->header.PageLength = pr->Header.PageLength;
+                               hd->pLocal->header.PageNumber = pr->Header.PageNumber;
+                               hd->pLocal->header.PageType = pr->Header.PageType;
+
+                       } else if (pReply->Function == MPI_FUNCTION_RAID_ACTION) {
+                               /* If the RAID Volume request is successful,
+                                * return GOOD, else indicate that
+                                * some type of error occurred.
+                                */
+                               MpiRaidActionReply_t    *pr = (MpiRaidActionReply_t *)mr;
+                               if (pr->ActionStatus == MPI_RAID_ACTION_ASTATUS_SUCCESS)
+                                       completionCode = MPT_SCANDV_GOOD;
+                               else
+                                       completionCode = MPT_SCANDV_SOME_ERROR;
+
+                       } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
+                               VirtDevice      *target;
+                               u8              *sense_data;
+                               int              sz;
+
+                               /* save sense data in global & target structure
+                                */
+                               completionCode = MPT_SCANDV_SENSE;
+                               hd->pLocal->scsiStatus = pReply->SCSIStatus;
+                               sense_data = ((u8 *)hd->ioc->sense_buf_pool +
+                                       (req_idx * MPT_SENSE_BUFFER_ALLOC));
+
+                               sz = MIN (pReq->SenseBufferLength,
+                                                       SCSI_STD_SENSE_BYTES);
+                               memcpy(hd->pLocal->sense, sense_data, sz);
+
+                               target = hd->Targets[pReq->TargetID];
+                               if (target) {
+                                       memcpy(target->sense, sense_data, sz);
+                                       target->tflags
+                                               |= MPT_TARGET_FLAGS_VALID_SENSE;
+                               }
+
+                               ddvprintk((KERN_NOTICE "  Check Condition, sense ptr %p\n",
+                                               sense_data));
+                       } else if (pReply->SCSIState & (MPI_SCSI_STATE_AUTOSENSE_FAILED |
+                                                       MPI_SCSI_STATE_NO_SCSI_STATUS)) {
+                               completionCode = MPT_SCANDV_DID_RESET;
+                       } else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED) {
+                               completionCode = MPT_SCANDV_DID_RESET;
+                       } else {
+                               /* If no error, this will be equivalent
+                                * to MPT_SCANDV_GOOD
+                                */
+                               completionCode = (int) pReply->SCSIStatus;
+                       }
+                       break;
+
+               case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR:         /* 0x0047 */
+                       if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
+                               completionCode = MPT_SCANDV_DID_RESET;
+                       else
+                               completionCode = MPT_SCANDV_SOME_ERROR;
+                       break;
+
+               default:
+                       completionCode = MPT_SCANDV_SOME_ERROR;
+                       break;
+
+               }       /* switch(status) */
+
+               ddvprintk((KERN_NOTICE "  completionCode set to %08xh\n",
+                               completionCode));
+       } /* end of address reply case */
+
+       hd->pLocal->completion = completionCode;
+
+       /* MF and RF are freed in mpt_interrupt
+        */
+wakeup:
+       /* Free Chain buffers (will never chain) in scan or dv */
+       //mptscsih_freeChainBuffers(hd, req_idx);
+
+       /*
+        * Wake up the original calling thread
+        */
+       scandv_wait_done = 1;
+       wake_up(&scandv_waitq);
+
+       return 1;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*     mptscsih_timer_expired - Call back for timer process.
+ *     Used only for dv functionality.
+ *     @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
+ *
+ */
+static void mptscsih_timer_expired(unsigned long data)
+{
+       MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *) data;
+#ifndef MPT_SCSI_USE_NEW_EH
+       unsigned long  flags;
+#endif
+
+
+       ddvprintk((MYIOC_s_WARN_FMT "Timer Expired! Cmd %p\n", hd->ioc->name, hd->cmdPtr));
+
+       if (hd->cmdPtr) {
+               MPIHeader_t *cmd = (MPIHeader_t *)hd->cmdPtr;
+
+               if (cmd->Function == MPI_FUNCTION_SCSI_IO_REQUEST) {
+                       /* Desire to issue a task management request here.
+                        * TM requests MUST be single threaded.
+                        * If old eh code and no TM current, issue request.
+                        * If new eh code, do nothing. Wait for OS cmd timeout
+                        *      for bus reset.
+                        */
+#ifndef MPT_SCSI_USE_NEW_EH
+                       spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
+                       if (hd->tmPending) {
+                               spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+                               return;
+                       } else 
+                               hd->tmPending = 1;
+                       spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+
+                       if (mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
+                                                       0, 0, 0, NO_SLEEP) < 0) {
+                               printk(MYIOC_s_WARN_FMT "TM FAILED!\n", hd->ioc->name);
+                       }
+#else
+                       ddvtprintk((MYIOC_s_NOTE_FMT "DV Cmd Timeout: NoOp\n", hd->ioc->name));
+#endif
+               } else {
+                       /* Perform a FW reload */
+                       if (mpt_HardResetHandler(hd->ioc, NO_SLEEP) < 0) {
+                               printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", hd->ioc->name);
+                       }
+               }
+       } else {
+               /* This should NEVER happen */
+               printk(MYIOC_s_WARN_FMT "Null cmdPtr!!!!\n", hd->ioc->name);
+       }
+
+       /* No more processing.
+        * TM call will generate an interrupt for SCSI TM Management.
+        * The FW will reply to all outstanding commands, callback will finish cleanup.
+        * Hard reset clean-up will free all resources.
+        */
+       ddvprintk((MYIOC_s_WARN_FMT "Timer Expired Complete!\n", hd->ioc->name));
+
+       return;
+}
+
+#ifndef MPTSCSIH_DISABLE_DOMAIN_VALIDATION
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*     mptscsih_do_raid - Format and Issue a RAID volume request message.
+ *     @hd: Pointer to scsi host structure
+ *     @action: What do be done.
+ *     @id: Logical target id.
+ *     @bus: Target locations bus.
+ *
+ *     Returns: < 0 on a fatal error
+ *             0 on success
+ *
+ *     Remark: Wait to return until reply processed by the ISR.
+ */
+static int
+mptscsih_do_raid(MPT_SCSI_HOST *hd, u8 action, INTERNAL_CMD *io)
+{
+       MpiRaidActionRequest_t  *pReq;
+       MPT_FRAME_HDR           *mf;
+       int                     in_isr;
+
+       in_isr = in_interrupt();
+       if (in_isr) {
+               dprintk((MYIOC_s_WARN_FMT "Internal raid request not allowed in ISR context!\n",
+                                       hd->ioc->name));
+               return -EPERM;
+       }
 
-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
-};
+       /* Get and Populate a free Frame
+        */
+       if ((mf = mpt_get_msg_frame(ScsiScanDvCtx, hd->ioc->id)) == NULL) {
+               ddvprintk((MYIOC_s_WARN_FMT "_do_raid: no msg frames!\n",
+                                       hd->ioc->name));
+               return -EAGAIN;
+       }
+       pReq = (MpiRaidActionRequest_t *)mf;
+       pReq->Action = action;
+       pReq->Reserved1 = 0;
+       pReq->ChainOffset = 0;
+       pReq->Function = MPI_FUNCTION_RAID_ACTION;
+       pReq->VolumeID = io->id;
+       pReq->VolumeBus = io->bus;
+       pReq->PhysDiskNum = io->physDiskNum;
+       pReq->MsgFlags = 0;
+       pReq->Reserved2 = 0;
+       pReq->ActionDataWord = 0; /* Reserved for this action */
+       //pReq->ActionDataSGE = 0;
+
+       mpt_add_sge((char *)&pReq->ActionDataSGE, 
+               MPT_SGE_FLAGS_SSIMPLE_READ | 0, (dma_addr_t) -1);
+
+       ddvprintk((MYIOC_s_INFO_FMT "RAID Volume action %x id %d\n",
+                       hd->ioc->name, action, io->id));
+
+       hd->pLocal = NULL;
+       hd->timer.expires = jiffies + HZ*2; /* 2 second timeout */
+       scandv_wait_done = 0;
+
+       /* Save cmd pointer, for resource free if timeout or
+        * FW reload occurs
+        */
+       hd->cmdPtr = mf;
+
+       add_timer(&hd->timer);
+       mptscsih_put_msgframe(ScsiScanDvCtx, hd->ioc->id, mf);
+       wait_event(scandv_waitq, scandv_wait_done);
+
+       if ((hd->pLocal == NULL) || (hd->pLocal->completion != MPT_SCANDV_GOOD))
+               return -1;
+
+       return 0;
+}
+#endif /* ~MPTSCSIH_DISABLE_DOMAIN_VALIDATION */
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mptscsih_do_cmd - Do internal command.
+ *     @hd: MPT_SCSI_HOST pointer
+ *     @io: INTERNAL_CMD pointer.
+ *
+ *     Issue the specified internally generated command and do command
+ *     specific cleanup. For bus scan / DV only.
+ *     NOTES: If command is Inquiry and status is good,
+ *     initialize a target structure, save the data
+ *
+ *     Remark: Single threaded access only.
+ *
+ *     Return:
+ *             < 0 if an illegal command or no resources
+ *
+ *                0 if good
+ *
+ *              > 0 if command complete but some type of completion error.
+ */
+static int
+mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
+{
+       MPT_FRAME_HDR   *mf;
+       SCSIIORequest_t *pScsiReq;
+       SCSIIORequest_t  ReqCopy;
+       int              my_idx, ii, dir;
+       int              rc, cmdTimeout;
+       int             in_isr;
+       char             cmdLen;
+       char             CDB[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+       char             cmd = io->cmd;
+
+       in_isr = in_interrupt();
+       if (in_isr) {
+               dprintk((MYIOC_s_WARN_FMT "Internal SCSI IO request not allowed in ISR context!\n",
+                                       hd->ioc->name));
+               return -EPERM;
+       }
+
+
+       /* Set command specific information
+        */
+       switch (cmd) {
+       case CMD_Inquiry:
+               cmdLen = 6;
+               dir = MPI_SCSIIO_CONTROL_READ;
+               CDB[0] = cmd;
+               CDB[4] = io->size;
+               cmdTimeout = 10;
+               break;
+
+       case CMD_TestUnitReady:
+               cmdLen = 6;
+               dir = MPI_SCSIIO_CONTROL_READ;
+               cmdTimeout = 10;
+               break;
+
+       case CMD_StartStopUnit:
+               cmdLen = 6;
+               dir = MPI_SCSIIO_CONTROL_READ;
+               CDB[0] = cmd;
+               CDB[4] = 1;     /*Spin up the disk */
+               cmdTimeout = 15;
+               break;
+
+       case CMD_ReadBuffer:
+               cmdLen = 10;
+               dir = MPI_SCSIIO_CONTROL_READ;
+               CDB[0] = cmd;
+               if (io->flags & MPT_ICFLAG_ECHO) {
+                       CDB[1] = 0x0A;
+               } else {
+                       CDB[1] = 0x02;
+               }
+
+               if (io->flags & MPT_ICFLAG_BUF_CAP) {
+                       CDB[1] |= 0x01;
+               }
+               CDB[6] = (io->size >> 16) & 0xFF;
+               CDB[7] = (io->size >>  8) & 0xFF;
+               CDB[8] = io->size & 0xFF;
+               cmdTimeout = 10;
+               break;
+
+       case CMD_WriteBuffer:
+               cmdLen = 10;
+               dir = MPI_SCSIIO_CONTROL_WRITE;
+               CDB[0] = cmd;
+               if (io->flags & MPT_ICFLAG_ECHO) {
+                       CDB[1] = 0x0A;
+               } else {
+                       CDB[1] = 0x02;
+               }
+               CDB[6] = (io->size >> 16) & 0xFF;
+               CDB[7] = (io->size >>  8) & 0xFF;
+               CDB[8] = io->size & 0xFF;
+               cmdTimeout = 10;
+               break;
+
+       case CMD_Reserve6:
+               cmdLen = 6;
+               dir = MPI_SCSIIO_CONTROL_READ;
+               CDB[0] = cmd;
+               cmdTimeout = 10;
+               break;
+
+       case CMD_Release6:
+               cmdLen = 6;
+               dir = MPI_SCSIIO_CONTROL_READ;
+               CDB[0] = cmd;
+               cmdTimeout = 10;
+               break;
+
+       case CMD_SynchronizeCache:
+               cmdLen = 10;
+               dir = MPI_SCSIIO_CONTROL_READ;
+               CDB[0] = cmd;
+//             CDB[1] = 0x02;  /* set immediate bit */
+               cmdTimeout = 10;
+               break;
+
+       default:
+               /* Error Case */
+               return -EFAULT;
+       }
+
+       /* Get and Populate a free Frame
+        */
+       if ((mf = mpt_get_msg_frame(ScsiScanDvCtx, hd->ioc->id)) == NULL) {
+               ddvprintk((MYIOC_s_WARN_FMT "No msg frames!\n",
+                                       hd->ioc->name));
+               return -EBUSY;
+       }
+
+       pScsiReq = (SCSIIORequest_t *) mf;
+
+       /* Get the request index */
+       my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
+       ADD_INDEX_LOG(my_idx); /* for debug */
+
+       if (io->flags & MPT_ICFLAG_PHYS_DISK) {
+               pScsiReq->TargetID = io->physDiskNum;
+               pScsiReq->Bus = 0;
+               pScsiReq->ChainOffset = 0;
+               pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
+       } else {
+               pScsiReq->TargetID = io->id;
+               pScsiReq->Bus = io->bus;
+               pScsiReq->ChainOffset = 0;
+               pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
+       }
+
+       pScsiReq->CDBLength = cmdLen;
+       pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
+
+       pScsiReq->Reserved = 0;
+
+       pScsiReq->MsgFlags = mpt_msg_flags();
+       /* MsgContext set in mpt_get_msg_fram call  */
+
+       for (ii=0; ii < 8; ii++)
+               pScsiReq->LUN[ii] = 0;
+       pScsiReq->LUN[1] = io->lun;
+
+       if (io->flags & MPT_ICFLAG_TAGGED_CMD)
+               pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_SIMPLEQ);
+       else
+               pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
+
+       for (ii=0; ii < 16; ii++)
+               pScsiReq->CDB[ii] = CDB[ii];
+
+       pScsiReq->DataLength = cpu_to_le32(io->size);
+       pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma
+                                          + (my_idx * MPT_SENSE_BUFFER_ALLOC));
+
+       ddvprintk((MYIOC_s_INFO_FMT "Sending Command 0x%x for (%d:%d:%d)\n",
+                       hd->ioc->name, cmd, io->bus, io->id, io->lun));
+
+       if (dir == MPI_SCSIIO_CONTROL_READ) {
+               mpt_add_sge((char *) &pScsiReq->SGL,
+                       MPT_SGE_FLAGS_SSIMPLE_READ | io->size,
+                       io->data_dma);
+       } else {
+               mpt_add_sge((char *) &pScsiReq->SGL,
+                       MPT_SGE_FLAGS_SSIMPLE_WRITE | io->size,
+                       io->data_dma);
+       }
+
+       /* The ISR will free the request frame, but we need
+        * the information to initialize the target. Duplicate.
+        */
+       memcpy(&ReqCopy, pScsiReq, sizeof(SCSIIORequest_t));
+
+       /* Issue this command after:
+        *      finish init
+        *      add timer
+        * Wait until the reply has been received
+        *  ScsiScanDvCtx callback function will
+        *      set hd->pLocal;
+        *      set scandv_wait_done and call wake_up
+        */
+       hd->pLocal = NULL;
+       hd->timer.expires = jiffies + HZ*cmdTimeout;
+       scandv_wait_done = 0;
+
+       /* Save cmd pointer, for resource free if timeout or
+        * FW reload occurs
+        */
+       hd->cmdPtr = mf;
+
+       add_timer(&hd->timer);
+       mptscsih_put_msgframe(ScsiScanDvCtx, hd->ioc->id, mf);
+       wait_event(scandv_waitq, scandv_wait_done);
+
+       if (hd->pLocal) {
+               rc = hd->pLocal->completion;
+               hd->pLocal->skip = 0;
+
+               /* Always set fatal error codes in some cases.
+                */
+               if (rc == MPT_SCANDV_SELECTION_TIMEOUT)
+                       rc = -ENXIO;
+               else if (rc == MPT_SCANDV_SOME_ERROR)
+                       rc =  -rc;
+       } else {
+               rc = -EFAULT;
+               /* This should never happen. */
+               ddvprintk((MYIOC_s_INFO_FMT "_do_cmd: Null pLocal!!!\n",
+                               hd->ioc->name));
+       }
+
+       return rc;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mptscsih_synchronize_cache - Send SYNCHRONIZE_CACHE to all disks.
+ *     @hd: Pointer to MPT_SCSI_HOST structure
+ *     @portnum: IOC port number
+ *
+ *     Uses the ISR, but with special processing.
+ *     MUST be single-threaded.
+ *
+ *     Return: 0 on completion
+ */
+static int
+mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, int portnum)
+{
+       MPT_ADAPTER             *ioc= hd->ioc;
+       VirtDevice              *pTarget = NULL;
+       SCSIDevicePage1_t       *pcfg1Data = NULL;
+       INTERNAL_CMD             iocmd;
+       CONFIGPARMS              cfg;
+       dma_addr_t               cfg1_dma_addr = -1;
+       ConfigPageHeader_t       header1;
+       int                      bus = 0;
+       int                      id = 0;
+       int                      lun = 0;
+       int                      hostId = ioc->pfacts[portnum].PortSCSIID;
+       int                      max_id;
+       int                      requested, configuration, data;
+       int                      doConfig = 0;
+       u8                       flags, factor;
+
+       max_id = ioc->sh->max_id - 1;
+
+       /* Following parameters will not change
+        * in this routine.
+        */
+       iocmd.cmd = CMD_SynchronizeCache;
+       iocmd.flags = 0;
+       iocmd.physDiskNum = -1;
+       iocmd.data = NULL;
+       iocmd.data_dma = -1;
+       iocmd.size = 0;
+       iocmd.rsvd = iocmd.rsvd2 = 0;
+
+       /* No SCSI hosts
+        */
+       if (hd->Targets == NULL)
+               return 0;
+
+       /* Skip the host
+        */
+       if (id == hostId)
+               id++;
+
+       /* Write SDP1 for all SCSI devices 
+        * Alloc memory and set up config buffer
+        */
+       if (hd->is_spi) {
+               if (ioc->spi_data.sdp1length > 0) {
+                       pcfg1Data = (SCSIDevicePage1_t *)pci_alloc_consistent(ioc->pcidev,
+                                        ioc->spi_data.sdp1length * 4, &cfg1_dma_addr);
+       
+                       if (pcfg1Data != NULL) {
+                               doConfig = 1;
+                               header1.PageVersion = ioc->spi_data.sdp1version;
+                               header1.PageLength = ioc->spi_data.sdp1length;
+                               header1.PageNumber = 1;
+                               header1.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
+                               cfg.hdr = &header1;
+                               cfg.physAddr = cfg1_dma_addr;
+                               cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
+                               cfg.dir = 1;
+                               cfg.timeout = 0;
+                       }
+               }
+       }
+
+       /* loop through all devices on this port
+        */
+       while (bus < MPT_MAX_BUS) {
+               iocmd.bus = bus;
+               iocmd.id = id;
+               pTarget = hd->Targets[(int)id];
+
+               if (doConfig) {
+
+                       /* Set the negotiation flags */
+                       if (pTarget && (pTarget = hd->Targets[id]) && !pTarget->raidVolume) {
+                               flags = pTarget->negoFlags;
+                       } else {
+                               flags = hd->ioc->spi_data.noQas;
+                               if (hd->ioc->spi_data.nvram && (hd->ioc->spi_data.nvram[id] != MPT_HOST_NVRAM_INVALID)) {
+                                       data = hd->ioc->spi_data.nvram[id];
+       
+                                       if (data & MPT_NVRAM_WIDE_DISABLE)
+                                               flags |= MPT_TARGET_NO_NEGO_WIDE;
+
+                                       factor = (data & MPT_NVRAM_SYNC_MASK) >> MPT_NVRAM_SYNC_SHIFT;
+                                       if ((factor == 0) || (factor == MPT_ASYNC))
+                                               flags |= MPT_TARGET_NO_NEGO_SYNC;
+                               }
+                       }
+       
+                       /* Force to async, narrow */
+                       mptscsih_setDevicePage1Flags(0, MPT_ASYNC, 0, &requested,
+                                       &configuration, flags);
+                       pcfg1Data->RequestedParameters = le32_to_cpu(requested);
+                       pcfg1Data->Reserved = 0;
+                       pcfg1Data->Configuration = le32_to_cpu(configuration);
+                       cfg.pageAddr = (bus<<8) | id;
+                       mpt_config(hd->ioc, &cfg);
+               }
+
+               /* If target Ptr NULL or if this target is NOT a disk, skip.
+                */
+       //      if (pTarget && ((pTarget->inq_data[0] & 0x1F) == 0)) {
+               if (pTarget) {
+                       for (lun=0; lun <= MPT_LAST_LUN; lun++) {
+                               /* If LUN present, issue the command
+                                */
+                               if (pTarget->luns & (1<<lun)) {
+                                       iocmd.lun = lun;
+                                       (void) mptscsih_do_cmd(hd, &iocmd);
+                               }
+                       }
+               }
+
+               /* get next relevant device */
+               id++;
+
+               if (id == hostId)
+                       id++;
+
+               if (id > max_id) {
+                       id = 0;
+                       bus++;
+               }
+       }
+
+       if (pcfg1Data) {
+               pci_free_consistent(ioc->pcidev, header1.PageLength * 4, pcfg1Data, cfg1_dma_addr);
+       }
+
+       return 0;
+}
+
+#ifndef MPTSCSIH_DISABLE_DOMAIN_VALIDATION
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mptscsih_domainValidation - Top level handler for domain validation.
+ *     @hd: Pointer to MPT_SCSI_HOST structure.
+ *
+ *     Uses the ISR, but with special processing.
+ *     Called from schedule, should not be in interrupt mode.
+ *     While thread alive, do dv for all devices needing dv
+ *
+ *     Return: None.
+ */
+static void
+mptscsih_domainValidation(void *arg)
+{
+       MPT_SCSI_HOST           *hd = NULL;
+       MPT_ADAPTER             *ioc = NULL;
+       unsigned long            flags;
+       int                      id, maxid, dvStatus, did;
+       int                      ii, isPhysDisk;
+       u8                       oldQas;
+
+       spin_lock_irqsave(&dvtaskQ_lock, flags);
+       dvtaskQ_active = 1;
+       if (dvtaskQ_release) {
+               dvtaskQ_active = 0;
+               spin_unlock_irqrestore(&dvtaskQ_lock, flags);
+               return;
+       }
+       spin_unlock_irqrestore(&dvtaskQ_lock, flags);
+
+       /* For this ioc, loop through all devices and do dv to each device.
+        * When complete with this ioc, search through the ioc list, and 
+        * for each scsi ioc found, do dv for all devices. Exit when no
+        * device needs dv.
+        */
+       did = 1;
+       while (did) {
+               did = 0;
+               for (ioc = mpt_adapter_find_first(); ioc != NULL; ioc = mpt_adapter_find_next(ioc)) {
+                       spin_lock_irqsave(&dvtaskQ_lock, flags);
+                       if (dvtaskQ_release) {
+                               dvtaskQ_active = 0;
+                               spin_unlock_irqrestore(&dvtaskQ_lock, flags);
+                               return;
+                       }
+                       spin_unlock_irqrestore(&dvtaskQ_lock, flags);
+
+                       set_current_state(TASK_INTERRUPTIBLE);
+                       schedule_timeout(HZ/4);
+
+                       /* DV only to SCSI adapters */
+                       if ((int)ioc->chip_type <= (int)FC929)
+                               continue;
+                       
+                       /* Make sure everything looks ok */
+                       if (ioc->sh == NULL)
+                               continue;
+
+                       hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
+                       if (hd == NULL)
+                               continue;
+
+                       maxid = MIN (ioc->sh->max_id, MPT_MAX_SCSI_DEVICES);
+
+                       for (id = 0; id < maxid; id++) {
+                               oldQas = hd->ioc->spi_data.noQas;
+                               spin_lock_irqsave(&dvtaskQ_lock, flags);
+                               if (dvtaskQ_release) {
+                                       dvtaskQ_active = 0;
+                                       spin_unlock_irqrestore(&dvtaskQ_lock, flags);
+                                       return;
+                               }
+                               spin_unlock_irqrestore(&dvtaskQ_lock, flags);
+                               dvStatus = hd->ioc->spi_data.dvStatus[id];
+
+                               if (dvStatus & MPT_SCSICFG_NEED_DV) {
+
+                                       hd->ioc->spi_data.dvStatus[id] |= MPT_SCSICFG_DV_PENDING;
+                                       hd->ioc->spi_data.dvStatus[id] &= ~MPT_SCSICFG_NEED_DV;
+
+                                       set_current_state(TASK_INTERRUPTIBLE);
+                                       schedule_timeout(HZ/4);
+
+                                       /* If hidden phys disk, block IO's to all
+                                        *      raid volumes
+                                        * else, process normally
+                                        */
+                                       isPhysDisk = mptscsih_is_phys_disk(ioc, id);
+                                       if (isPhysDisk) {
+                                               for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
+                                                       if (hd->ioc->spi_data.isRaid & (1 << ii)) {
+                                                               hd->ioc->spi_data.dvStatus[ii] |= MPT_SCSICFG_DV_PENDING;
+                                                       }
+                                               }
+                                       }
+
+                                       mptscsih_doDv(hd, 0, id);
+                                       did++;
+                                       hd->ioc->spi_data.dvStatus[id] |= MPT_SCSICFG_DV_DONE;
+                                       hd->ioc->spi_data.dvStatus[id] &= ~MPT_SCSICFG_DV_PENDING;
+
+                                       if (isPhysDisk) {
+                                               for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
+                                                       if (hd->ioc->spi_data.isRaid & (1 << ii)) {
+                                                               hd->ioc->spi_data.dvStatus[ii] &= ~MPT_SCSICFG_DV_PENDING;
+                                                       }
+                                               }
+                                       }
+
+                                       /* Post OS IOs that were pended while
+                                        * DV running.
+                                        */
+                                       post_pendingQ_commands(hd);
+
+                                       if ((!oldQas) && (hd->ioc->spi_data.noQas))
+                                               mptscsih_qas_check(hd);
+                               }
+                       }
+               }
+       }
+
+       spin_lock_irqsave(&dvtaskQ_lock, flags);
+       dvtaskQ_active = 0;
+       spin_unlock_irqrestore(&dvtaskQ_lock, flags);
+
+       return;
+}
+
+/* Search IOC page 3 to determine if this is hidden physical disk
+ */
+static int mptscsih_is_phys_disk(MPT_ADAPTER *ioc, int id)
+{
+       if (ioc->spi_data.pIocPg3) {
+               Ioc3PhysDisk_t *pPDisk =  ioc->spi_data.pIocPg3->PhysDisk;
+               int             numPDisk = ioc->spi_data.pIocPg3->NumPhysDisks;
+
+               while (numPDisk) {
+                       if (pPDisk->PhysDiskID == id) {
+                               return 1;
+                       }
+                       pPDisk++;
+                       numPDisk--;
+               }
+       }
+       return 0;
+}
 
-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
-};
+/* Write SDP1 if no QAS has been enabled
+ */
+static void mptscsih_qas_check(MPT_SCSI_HOST *hd)
+{
+       VirtDevice *pTarget = NULL;
+       int ii;
+       int change = 0;
 
-#define SPECIAL_ASCQ(c,q) \
-       (((c) == 0x40 && (q) != 0x00) || ((c) == 0x4D) || ((c) == 0x70))
+       if (hd->Targets == NULL)
+               return;
+
+       for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
+               change = 0;
+               pTarget = hd->Targets[ii];
+
+               if ((pTarget != NULL) && (!pTarget->raidVolume)) {
+                       if ((pTarget->negoFlags & hd->ioc->spi_data.noQas) == 0) {
+                               change = 1;
+                               pTarget->negoFlags |= hd->ioc->spi_data.noQas;
+                       }
+               } else {
+                       if (mptscsih_is_phys_disk(hd->ioc, ii) == 1)
+                               change = 1;
+               }
+
+               if ((change) && (hd->ioc->spi_data.dvStatus[ii] & MPT_SCSICFG_DV_DONE))
+                       mptscsih_writeSDP1(hd, 0, ii, 0);
+       }
+       return;
+}
+
+
+
+#define MPT_GET_NVRAM_VALS     0x01
+#define MPT_UPDATE_MAX         0x02
+#define MPT_SET_MAX            0x04
+#define MPT_SET_MIN            0x08
+#define MPT_FALLBACK           0x10
+#define MPT_SAVE               0x20
 
-#if 0
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*
- *  Sense_Key_Specific() - If Sense_Key_Specific_Valid bit is set,
- *                        then print additional information via
- *                        a call to SDMS_SystemAlert().
+/**
+ *     mptscsih_doDv - Perform domain validation to a target.
+ *     @hd: Pointer to MPT_SCSI_HOST structure.
+ *     @portnum: IOC port number.
+ *     @target: Physical ID of this target
+ *
+ *     Uses the ISR, but with special processing.
+ *     MUST be single-threaded.
+ *     Test will exit if target is at async & narrow.
  *
- *  Return: nothing
+ *     Return: None.
  */
-static void Sense_Key_Specific(IO_Info_t *ioop, char *msg1)
+static void
+mptscsih_doDv(MPT_SCSI_HOST *hd, int portnum, int id)
 {
-       u8      *sd;
-       u8       BadValue;
-       u8       SenseKey;
-       int      Offset;
-       int      len = strlen(msg1);
+       MPT_ADAPTER             *ioc = hd->ioc;
+       VirtDevice              *pTarget = NULL;
+       SCSIDevicePage1_t       *pcfg1Data = NULL;
+       SCSIDevicePage0_t       *pcfg0Data = NULL;
+       u8                      *pbuf1 = NULL;
+       u8                      *pbuf2 = NULL;
+       u8                      *pDvBuf = NULL;
+       dma_addr_t               dvbuf_dma = -1;
+       dma_addr_t               buf1_dma = -1;
+       dma_addr_t               buf2_dma = -1;
+       dma_addr_t               cfg1_dma_addr = -1;
+       dma_addr_t               cfg0_dma_addr = -1;
+       ConfigPageHeader_t       header1;
+       ConfigPageHeader_t       header0;
+       DVPARAMETERS             dv;
+       INTERNAL_CMD             iocmd;
+       CONFIGPARMS              cfg;
+       int                      dv_alloc = 0;
+       int                      rc, sz = 0;
+       int                      bufsize = 0;
+       int                      dataBufSize = 0;
+       int                      echoBufSize = 0;
+       int                      notDone;
+       int                      patt;
+       int                      repeat;
+       char                     firstPass = 1;
+       char                     doFallback = 0;
+       char                     readPage0;
+       char                     bus, lun;
+       char                     inq0 = 0;
+
+       if (ioc->spi_data.sdp1length == 0)
+               return;
 
-       sd = ioop->sensePtr;
-       if (SD_Additional_Sense_Length(sd) < 8)
+       if (ioc->spi_data.sdp0length == 0)
                return;
 
-       SenseKey = SD_Sense_Key(sd);
+       if (id == ioc->pfacts[portnum].PortSCSIID)
+               return;
 
-       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);
+       lun = 0;
+       bus = 0;
+       ddvtprintk((MYIOC_s_NOTE_FMT 
+                       "DV started: numIOs %d bus=%d, id %d dv @ %p\n",
+                       ioc->name, atomic_read(&queue_depth), bus, id, &dv));
+
+       /* Prep DV structure
+        */
+       memset (&dv, 0, sizeof(DVPARAMETERS));
+       dv.id = id;
+
+       /* Populate tmax with the current maximum
+        * transfer parameters for this target.
+        * Exit if narrow and async.
+        */
+       dv.cmd = MPT_GET_NVRAM_VALS;
+       mptscsih_dv_parms(hd, &dv, NULL);
+       if ((!dv.max.width) && (!dv.max.offset))
+               return;
+
+       /* Prep SCSI IO structure
+        */
+       iocmd.id = id;
+       iocmd.bus = bus;
+       iocmd.lun = lun;
+       iocmd.flags = 0;
+       iocmd.physDiskNum = -1;
+       iocmd.rsvd = iocmd.rsvd2 = 0;
+
+       /* Use tagged commands if possible.
+        */
+       pTarget = hd->Targets[id];
+       if (pTarget && (pTarget->tflags & MPT_TARGET_FLAGS_Q_YES))
+               iocmd.flags |= MPT_ICFLAG_TAGGED_CMD;
+
+       if (pTarget && (pTarget->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY)) {
+               /* Another GEM workaround. Check peripheral device type,
+                * if PROCESSOR, quit DV.
+                */
+               if (((pTarget->inq_data[0] & 0x1F) == 0x03) || ((pTarget->inq_data[0] & 0x1F) > 0x08)) {
+                       pTarget->negoFlags |= (MPT_TARGET_NO_NEGO_WIDE | MPT_TARGET_NO_NEGO_SYNC);
+                       return;
+               }
+       }
+
+       /* Prep cfg structure
+        */
+       cfg.pageAddr = (bus<<8) | id;
+       cfg.hdr = NULL;
+
+       /* Prep SDP0 header
+        */
+       header0.PageVersion = ioc->spi_data.sdp0version;
+       header0.PageLength = ioc->spi_data.sdp0length;
+       header0.PageNumber = 0;
+       header0.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
+
+       /* Prep SDP1 header
+        */
+       header1.PageVersion = ioc->spi_data.sdp1version;
+       header1.PageLength = ioc->spi_data.sdp1length;
+       header1.PageNumber = 1;
+       header1.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
+
+       if (header0.PageLength & 1)
+               dv_alloc = (header0.PageLength * 4) + 4;
+
+       dv_alloc +=  (2048 + (header1.PageLength * 4));
+
+       pDvBuf = pci_alloc_consistent(ioc->pcidev, dv_alloc, &dvbuf_dma);
+       if (pDvBuf == NULL)
+               return;
+
+       sz = 0;
+       pbuf1 = (u8 *)pDvBuf;
+       buf1_dma = dvbuf_dma;
+       sz +=1024;
+
+       pbuf2 = (u8 *) (pDvBuf + sz);
+       buf2_dma = dvbuf_dma + sz;
+       sz +=1024;
+
+       pcfg0Data = (SCSIDevicePage0_t *) (pDvBuf + sz);
+       cfg0_dma_addr = dvbuf_dma + sz;
+       sz += header0.PageLength * 4;
+
+       /* 8-byte alignment
+        */
+       if (header0.PageLength & 1)
+               sz += 4;
+
+       pcfg1Data = (SCSIDevicePage1_t *) (pDvBuf + sz);
+       cfg1_dma_addr = dvbuf_dma + sz;
+
+       /* Skip this ID? Set cfg.hdr to force config page write
+        */
+       if ((ioc->spi_data.nvram[id] != MPT_HOST_NVRAM_INVALID) &&
+                       (!(ioc->spi_data.nvram[id] & MPT_NVRAM_ID_SCAN_ENABLE))) { 
+
+               ddvprintk((MYIOC_s_NOTE_FMT "DV Skipped: bus, id, lun (%d, %d, %d)\n",
+                       ioc->name, bus, id, lun));
+
+               dv.cmd = MPT_SET_MAX;
+               mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
+               cfg.hdr = &header1;
+               goto target_done;
+       }
+
+       /* Finish iocmd inititialization - hidden or visible disk? */
+       if (ioc->spi_data.pIocPg3) {
+               /* Searc IOC page 3 for matching id
+                */
+               Ioc3PhysDisk_t *pPDisk =  ioc->spi_data.pIocPg3->PhysDisk;
+               int             numPDisk = ioc->spi_data.pIocPg3->NumPhysDisks;
+
+               while (numPDisk) {
+                       if (pPDisk->PhysDiskID == id) {
+                               /* match */
+                               iocmd.flags |= MPT_ICFLAG_PHYS_DISK;
+                               iocmd.physDiskNum = pPDisk->PhysDiskNum;
+
+                               /* Quiesce the IM
+                                */
+                               if (mptscsih_do_raid(hd, MPI_RAID_ACTION_QUIESCE_PHYS_IO, &iocmd) < 0) {
+                                       ddvprintk((MYIOC_s_ERR_FMT "RAID Queisce FAILED!\n", ioc->name));
+                                       goto target_done;
+                               }
+                               break;
+                       }
+                       pPDisk++;
+                       numPDisk--;
+               }
+       }
+
+       /* RAID Volume ID's may double for a physical device. If RAID but
+        * not a physical ID as well, skip DV.
+        */
+       if ((hd->ioc->spi_data.isRaid & (1 << id)) && !(iocmd.flags & MPT_ICFLAG_PHYS_DISK))
+               goto target_done;
+
+
+       /* Basic Test.
+        * Async & Narrow - Inquiry
+        * Async & Narrow - Inquiry
+        * Maximum transfer rate - Inquiry
+        * Compare buffers:
+        *      If compare, test complete.
+        *      If miscompare and first pass, repeat
+        *      If miscompare and not first pass, fall back and repeat
+        */
+       hd->pLocal = NULL;
+       readPage0 = 0;
+       sz = SCSI_STD_INQUIRY_BYTES;
+       while (1) {
+               ddvprintk((MYIOC_s_NOTE_FMT "DV: Start Basic test.\n", ioc->name));
+               dv.cmd = MPT_SET_MIN;
+               mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
+
+               cfg.hdr = &header1;
+               cfg.physAddr = cfg1_dma_addr;
+               cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
+               cfg.dir = 1;
+               if (mpt_config(hd->ioc, &cfg) != 0)
+                       goto target_done;
+
+               iocmd.cmd = CMD_Inquiry;
+               iocmd.data_dma = buf1_dma;
+               iocmd.data = pbuf1;
+               iocmd.size = sz;
+               if (mptscsih_do_cmd(hd, &iocmd) < 0)
+                       goto target_done;
+
+               /* Another GEM workaround. Check peripheral device type,
+                * if PROCESSOR, quit DV.
+                */
+               if (((pbuf1[0] & 0x1F) == 0x03) || ((pbuf1[0] & 0x1F) > 0x08))
+                       goto target_done;
+
+               if (mptscsih_do_cmd(hd, &iocmd) < 0)
+                       goto target_done;
+
+               if (doFallback)
+                       dv.cmd = MPT_FALLBACK;
+               else
+                       dv.cmd = MPT_SET_MAX;
+
+               mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
+               if (mpt_config(hd->ioc, &cfg) != 0)
+                       goto target_done;
+
+               if ((!dv.now.width) && (!dv.now.offset))
+                       goto target_done;
+
+               iocmd.cmd = CMD_Inquiry;
+               iocmd.data_dma = buf2_dma;
+               iocmd.data = pbuf2;
+               iocmd.size = sz;
+               if (mptscsih_do_cmd(hd, &iocmd) < 0)
+                       goto target_done;
+               else if (hd->pLocal == NULL)
+                       goto target_done;
+               else {
+                       /* Save the return code.
+                        * If this is the first pass,
+                        * read SCSI Device Page 0
+                        * and update the target max parameters.
+                        */
+                       rc = hd->pLocal->completion;
+                       doFallback = 0;
+                       if (rc == MPT_SCANDV_GOOD) {
+                               if (!readPage0) {
+                                       u32 sdp0_info;
+                                       u32 sdp0_nego;
+
+                                       cfg.hdr = &header0;
+                                       cfg.physAddr = cfg0_dma_addr;
+                                       cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+                                       cfg.dir = 0;
+                                       if (mpt_config(hd->ioc, &cfg) != 0)
+                                               goto target_done;
+
+                                       sdp0_info = le32_to_cpu(pcfg0Data->Information) & 0x0E;
+                                       sdp0_nego = (le32_to_cpu(pcfg0Data->NegotiatedParameters) & 0xFF00 ) >> 8;
+
+                                       /* Quantum and Fujitsu workarounds.
+                                        * Quantum: PPR U320 -> PPR reply with Ultra2 and wide
+                                        * Fujitsu: PPR U320 -> Msg Reject and Ultra2 and wide
+                                        * Resetart with a request for U160.
+                                        */
+                                       if ((dv.now.factor == MPT_ULTRA320) && (sdp0_nego == MPT_ULTRA2)) { 
+                                                       doFallback = 1;
+                                       } else {
+                                               dv.cmd = MPT_UPDATE_MAX;
+                                               mptscsih_dv_parms(hd, &dv, (void *)pcfg0Data);
+                                               /* Update the SCSI device page 1 area
+                                                */
+                                               pcfg1Data->RequestedParameters = pcfg0Data->NegotiatedParameters;
+                                               readPage0 = 1;
+                                       }
+                               }
+
+                               /* Quantum workaround. Restart this test will the fallback
+                                * flag set.
+                                */
+                               if (doFallback == 0) {
+                                       if (memcmp(pbuf1, pbuf2, sz) != 0) {
+                                               if (!firstPass)
+                                                       doFallback = 1;
+                                       } else
+                                               break;  /* test complete */
+                               }
+
+
+                       } else if ((rc == MPT_SCANDV_DID_RESET) || (rc == MPT_SCANDV_SENSE))
+                               doFallback = 1; /* set fallback flag */
+                       else
+                               goto target_done;
+
+                       firstPass = 0;
+               }
+       }
+       ddvprintk((MYIOC_s_NOTE_FMT "DV: Basic test completed OK.\n", ioc->name));
+       inq0 = (*pbuf1) & 0x1F;
+
+       /* Continue only for disks
+        */
+       if (inq0 != 0)
+               goto target_done;
+
+       /* Start the Enhanced Test.
+        * 0) issue TUR to clear out check conditions
+        * 1) read capacity of echo (regular) buffer
+        * 2) reserve device
+        * 3) do write-read-compare data pattern test
+        * 4) release
+        * 5) update nego parms to target struct
+        */
+       cfg.hdr = &header1;
+       cfg.physAddr = cfg1_dma_addr;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
+       cfg.dir = 1;
+
+       iocmd.cmd = CMD_TestUnitReady;
+       iocmd.data_dma = -1;
+       iocmd.data = NULL;
+       iocmd.size = 0;
+       notDone = 1;
+       while (notDone) {
+               if (mptscsih_do_cmd(hd, &iocmd) < 0)
+                       goto target_done;
+
+               if (hd->pLocal == NULL)
+                       goto target_done;
+
+               rc = hd->pLocal->completion;
+               if (rc == MPT_SCANDV_GOOD)
+                       notDone = 0;
+               else if (rc == MPT_SCANDV_SENSE) {
+                       u8 skey = hd->pLocal->sense[2] & 0x0F;
+                       u8 asc = hd->pLocal->sense[12];
+                       u8 ascq = hd->pLocal->sense[13];
+                       ddvprintk((MYIOC_s_INFO_FMT
+                               "SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n",
+                               ioc->name, skey, asc, ascq));
+
+                       if (skey == SK_UNIT_ATTENTION)
+                               notDone++; /* repeat */
+                       else if ((skey == SK_NOT_READY) &&
+                                       (asc == 0x04)&&(ascq == 0x01)) {
+                               /* wait then repeat */
+                               mdelay (2000);
+                               notDone++;
+                       } else if ((skey == SK_NOT_READY) && (asc == 0x3A)) {
+                               /* no medium, try read test anyway */
+                               notDone = 0;
+                       } else {
+                               /* All other errors are fatal.
+                                */
+                               ddvprintk((MYIOC_s_INFO_FMT "DV: fatal error.",
+                                               ioc->name));
+                               goto target_done;
+                       }
+               } else
+                       goto target_done;
+       }
+
+       iocmd.cmd = CMD_ReadBuffer;
+       iocmd.data_dma = buf1_dma;
+       iocmd.data = pbuf1;
+       iocmd.size = 4;
+       iocmd.flags |= MPT_ICFLAG_BUF_CAP;
+
+       dataBufSize = 0;
+       echoBufSize = 0;
+       for (patt = 0; patt < 2; patt++) {
+               if (patt == 0)
+                       iocmd.flags |= MPT_ICFLAG_ECHO;
+               else
+                       iocmd.flags &= ~MPT_ICFLAG_ECHO;
+
+               notDone = 1;
+               while (notDone) {
+                       bufsize = 0;
+
+                       /* If not ready after 8 trials,
+                        * give up on this device.
+                        */
+                       if (notDone > 8)
+                               goto target_done;
+
+                       if (mptscsih_do_cmd(hd, &iocmd) < 0)
+                               goto target_done;
+                       else if (hd->pLocal == NULL)
+                               goto target_done;
+                       else {
+                               rc = hd->pLocal->completion;
+                               ddvprintk(("ReadBuffer Comp Code %d", rc));
+                               ddvprintk(("  buff: %0x %0x %0x %0x\n",
+                                       pbuf1[0], pbuf1[1], pbuf1[2], pbuf1[3]));
+
+                               if (rc == MPT_SCANDV_GOOD) {
+                                       notDone = 0;
+                                       if (iocmd.flags & MPT_ICFLAG_ECHO) {
+                                               bufsize =  ((pbuf1[2] & 0x1F) <<8) | pbuf1[3];
+                                       } else {
+                                               bufsize =  pbuf1[1]<<16 | pbuf1[2]<<8 | pbuf1[3];
+                                       }
+                               } else if (rc == MPT_SCANDV_SENSE) {
+                                       u8 skey = hd->pLocal->sense[2] & 0x0F;
+                                       u8 asc = hd->pLocal->sense[12];
+                                       u8 ascq = hd->pLocal->sense[13];
+                                       ddvprintk((MYIOC_s_INFO_FMT
+                                               "SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n",
+                                               ioc->name, skey, asc, ascq));
+                                       if (skey == SK_ILLEGAL_REQUEST) {
+                                               notDone = 0;
+                                       } else if (skey == SK_UNIT_ATTENTION) {
+                                               notDone++; /* repeat */
+                                       } else if ((skey == SK_NOT_READY) &&
+                                               (asc == 0x04)&&(ascq == 0x01)) {
+                                               /* wait then repeat */
+                                               mdelay (2000);
+                                               notDone++;
+                                       } else {
+                                               /* All other errors are fatal.
+                                                */
+                                               ddvprintk((MYIOC_s_INFO_FMT "DV: fatal error.",
+                                                       ioc->name));
+                                               goto target_done;
+                                       }
+                               } else {
+                                       /* All other errors are fatal
+                                        */
+                                       goto target_done;
+                               }
+                       }
+               }
+
+               if (iocmd.flags & MPT_ICFLAG_ECHO)
+                       echoBufSize = bufsize;
+               else
+                       dataBufSize = bufsize;
+       }
+       sz = 0;
+       iocmd.flags &= ~MPT_ICFLAG_BUF_CAP;
+
+       /* Use echo buffers if possible,
+        * Exit if both buffers are 0.
+        */
+       if (echoBufSize > 0) {
+               iocmd.flags |= MPT_ICFLAG_ECHO;
+               if (dataBufSize > 0)
+                       bufsize = MIN(echoBufSize, dataBufSize);
+               else
+                       bufsize = echoBufSize;
+       } else if (dataBufSize == 0)
+               goto target_done;
+
+       ddvprintk((MYIOC_s_INFO_FMT "%s Buffer Capacity %d\n", ioc->name,
+               (iocmd.flags & MPT_ICFLAG_ECHO) ? "Echo" : " ", bufsize));
+
+       /* Data buffers for write-read-compare test max 1K.
+        */
+       sz = MIN(bufsize, 1024);
+
+       /* --- loop ----
+        * On first pass, always issue a reserve.
+        * On additional loops, only if a reset has occurred.
+        * iocmd.flags indicates if echo or regular buffer
+        */
+       for (patt = 0; patt < 4; patt++) {
+               ddvprintk(("Pattern %d\n", patt));
+               if ((iocmd.flags & MPT_ICFLAG_RESERVED) && (iocmd.flags & MPT_ICFLAG_DID_RESET)) {
+                       iocmd.cmd = CMD_TestUnitReady;
+                       iocmd.data_dma = -1;
+                       iocmd.data = NULL;
+                       iocmd.size = 0;
+                       if (mptscsih_do_cmd(hd, &iocmd) < 0)
+                               goto target_done;
+
+                       iocmd.cmd = CMD_Release6;
+                       iocmd.data_dma = -1;
+                       iocmd.data = NULL;
+                       iocmd.size = 0;
+                       if (mptscsih_do_cmd(hd, &iocmd) < 0)
+                               goto target_done;
+                       else if (hd->pLocal == NULL)
+                               goto target_done;
+                       else {
+                               rc = hd->pLocal->completion;
+                               ddvprintk(("Release rc %d\n", rc));
+                               if (rc == MPT_SCANDV_GOOD)
+                                       iocmd.flags &= ~MPT_ICFLAG_RESERVED;
+                               else
+                                       goto target_done;
+                       }
+                       iocmd.flags &= ~MPT_ICFLAG_RESERVED;
+               }
+               iocmd.flags &= ~MPT_ICFLAG_DID_RESET;
+
+               repeat = 5;
+               while (repeat && (!(iocmd.flags & MPT_ICFLAG_RESERVED))) {
+                       iocmd.cmd = CMD_Reserve6;
+                       iocmd.data_dma = -1;
+                       iocmd.data = NULL;
+                       iocmd.size = 0;
+                       if (mptscsih_do_cmd(hd, &iocmd) < 0)
+                               goto target_done;
+                       else if (hd->pLocal == NULL)
+                               goto target_done;
+                       else {
+                               rc = hd->pLocal->completion;
+                               if (rc == MPT_SCANDV_GOOD) {
+                                       iocmd.flags |= MPT_ICFLAG_RESERVED;
+                               } else if (rc == MPT_SCANDV_SENSE) {
+                                       /* Wait if coming ready
+                                        */
+                                       u8 skey = hd->pLocal->sense[2] & 0x0F;
+                                       u8 asc = hd->pLocal->sense[12];
+                                       u8 ascq = hd->pLocal->sense[13];
+                                       ddvprintk((MYIOC_s_INFO_FMT
+                                               "DV: Reserve Failed: ", ioc->name));
+                                       ddvprintk(("SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n",
+                                                       skey, asc, ascq));
+
+                                       if ((skey == SK_NOT_READY) && (asc == 0x04)&&
+                                                                       (ascq == 0x01)) {
+                                               /* wait then repeat */
+                                               mdelay (2000);
+                                               notDone++;
+                                       } else {
+                                               ddvprintk((MYIOC_s_INFO_FMT 
+                                                       "DV: Reserved Failed.", ioc->name));
+                                               goto target_done;
+                                       }
+                               } else {
+                                       ddvprintk((MYIOC_s_INFO_FMT "DV: Reserved Failed.",
+                                                        ioc->name));
+                                       goto target_done;
+                               }
+                       }
+               }
+
+               mptscsih_fillbuf(pbuf1, sz, patt, 1);
+               iocmd.cmd = CMD_WriteBuffer;
+               iocmd.data_dma = buf1_dma;
+               iocmd.data = pbuf1;
+               iocmd.size = sz;
+               if (mptscsih_do_cmd(hd, &iocmd) < 0)
+                       goto target_done;
+               else if (hd->pLocal == NULL)
+                       goto target_done;
+               else {
+                       rc = hd->pLocal->completion;
+                       if (rc == MPT_SCANDV_GOOD)
+                               ;               /* Issue read buffer */
+                       else if (rc == MPT_SCANDV_DID_RESET) {
+                               /* If using echo buffers, reset to data buffers.
+                                * Else do Fallback and restart
+                                * this test (re-issue reserve
+                                * because of bus reset).
+                                */
+                               if ((iocmd.flags & MPT_ICFLAG_ECHO) && (dataBufSize >= bufsize)) {
+                                       iocmd.flags &= ~MPT_ICFLAG_ECHO;
+                               } else {
+                                       dv.cmd = MPT_FALLBACK;
+                                       mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
+
+                                       if (mpt_config(hd->ioc, &cfg) != 0)
+                                               goto target_done;
+
+                                       if ((!dv.now.width) && (!dv.now.offset))
+                                               goto target_done;
+                               }
+
+                               iocmd.flags |= MPT_ICFLAG_DID_RESET;
+                               patt = -1;
+                               continue;
+                       } else if (rc == MPT_SCANDV_SENSE) {
+                               /* Restart data test if UA, else quit.
+                                */
+                               u8 skey = hd->pLocal->sense[2] & 0x0F;
+                               ddvprintk((MYIOC_s_INFO_FMT
+                                       "SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n", ioc->name, skey,
+                                       hd->pLocal->sense[12], hd->pLocal->sense[13]));
+                               if (skey == SK_UNIT_ATTENTION) {
+                                       patt = -1;
+                                       continue;
+                               } else if (skey == SK_ILLEGAL_REQUEST) {
+                                       if (iocmd.flags & MPT_ICFLAG_ECHO) {
+                                               if (dataBufSize >= bufsize) {
+                                                       iocmd.flags &= ~MPT_ICFLAG_ECHO;
+                                                       patt = -1;
+                                                       continue;
+                                               }
+                                       } 
+                                       goto target_done;
+                               }
+                               else
+                                       goto target_done;
+                       } else {
+                               /* fatal error */
+                               goto target_done;
+                       }
+               }
+
+               iocmd.cmd = CMD_ReadBuffer;
+               iocmd.data_dma = buf2_dma;
+               iocmd.data = pbuf2;
+               iocmd.size = sz;
+               if (mptscsih_do_cmd(hd, &iocmd) < 0)
+                       goto target_done;
+               else if (hd->pLocal == NULL)
+                       goto target_done;
+               else {
+                       rc = hd->pLocal->completion;
+                       if (rc == MPT_SCANDV_GOOD) {
+                                /* If buffers compare,
+                                 * go to next pattern,
+                                 * else, do a fallback and restart
+                                 * data transfer test.
+                                 */
+                               if (memcmp (pbuf1, pbuf2, sz) == 0) {
+                                       ; /* goto next pattern */
+                               } else {
+                                       /* Miscompare with Echo buffer, go to data buffer,
+                                        * if that buffer exists.
+                                        * Miscompare with Data buffer, check first 4 bytes,
+                                        * some devices return capacity. Exit in this case.
+                                        */
+                                       if (iocmd.flags & MPT_ICFLAG_ECHO) {
+                                               if (dataBufSize >= bufsize)
+                                                       iocmd.flags &= ~MPT_ICFLAG_ECHO;
+                                               else
+                                                       goto target_done;
+                                       } else {
+                                               if (dataBufSize == (pbuf2[1]<<16 | pbuf2[2]<<8 | pbuf2[3])) {
+                                                       /* Argh. Device returning wrong data.
+                                                        * Quit DV for this device.
+                                                        */
+                                                       goto target_done;
+                                               }
+
+                                               /* Had an actual miscompare. Slow down.*/
+                                               dv.cmd = MPT_FALLBACK;
+                                               mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
+
+                                               if (mpt_config(hd->ioc, &cfg) != 0)
+                                                       goto target_done;
+
+                                               if ((!dv.now.width) && (!dv.now.offset))
+                                                       goto target_done;
+                                       }
+
+                                       patt = -1;
+                                       continue;
+                               }
+                       } else if (rc == MPT_SCANDV_DID_RESET) {
+                               /* Do Fallback and restart
+                                * this test (re-issue reserve
+                                * because of bus reset).
+                                */
+                               dv.cmd = MPT_FALLBACK;
+                               mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
+
+                               if (mpt_config(hd->ioc, &cfg) != 0)
+                                        goto target_done;
+
+                               if ((!dv.now.width) && (!dv.now.offset))
+                                       goto target_done;
+
+                               iocmd.flags |= MPT_ICFLAG_DID_RESET;
+                               patt = -1;
+                               continue;
+                       } else if (rc == MPT_SCANDV_SENSE) {
+                               /* Restart data test if UA, else quit.
+                                */
+                               u8 skey = hd->pLocal->sense[2] & 0x0F;
+                               ddvprintk((MYIOC_s_INFO_FMT
+                                       "SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n", ioc->name, skey,
+                                       hd->pLocal->sense[12], hd->pLocal->sense[13]));
+                               if (skey == SK_UNIT_ATTENTION) {
+                                       patt = -1;
+                                       continue;
+                               }
+                               else
+                                       goto target_done;
+                       } else {
+                               /* fatal error */
+                               goto target_done;
+                       }
+               }
+
+       } /* --- end of patt loop ---- */
+
+target_done:
+       if (iocmd.flags & MPT_ICFLAG_RESERVED) {
+               iocmd.cmd = CMD_Release6;
+               iocmd.data_dma = -1;
+               iocmd.data = NULL;
+               iocmd.size = 0;
+               if (mptscsih_do_cmd(hd, &iocmd) < 0)
+                       printk(MYIOC_s_INFO_FMT "DV: Release failed. id %d",
+                                       ioc->name, id);
+               else if (hd->pLocal) {
+                       if (hd->pLocal->completion == MPT_SCANDV_GOOD)
+                               iocmd.flags &= ~MPT_ICFLAG_RESERVED;
                } else {
-                       BadValue = ioop->dataPtr[Offset];
-                       len += sprintf(msg1+len, "\n  Illegal DATA value=%02Xh found at DATA ",
-                                       BadValue);
+                       printk(MYIOC_s_INFO_FMT "DV: Release failed. id %d", 
+                                               ioc->name, id);
+               }
+       }
+
+
+       /* Set if cfg1_dma_addr contents is valid
+        */
+       if (cfg.hdr != NULL) {
+
+               /* If disk, not U320, disable QAS
+                */
+               if ((inq0 == 0) && (dv.now.factor > MPT_ULTRA320))
+                       hd->ioc->spi_data.noQas = MPT_TARGET_NO_NEGO_QAS;
+
+               dv.cmd = MPT_SAVE;
+               mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
+
+               /* Save the final negotiated settings to
+                * SCSI device page 1.
+                */
+               cfg.hdr = &header1;
+               cfg.physAddr = cfg1_dma_addr;
+               cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
+               cfg.dir = 1;
+               mpt_config(hd->ioc, &cfg);
+       }
+
+       /* If this is a RAID Passthrough, enable internal IOs
+        */
+       if (iocmd.flags & MPT_ICFLAG_PHYS_DISK) {
+               if (mptscsih_do_raid(hd, MPI_RAID_ACTION_ENABLE_PHYS_IO, &iocmd) < 0)
+                       ddvprintk((MYIOC_s_ERR_FMT "RAID Queisce FAILED!\n", ioc->name));
+       }
+
+       /* Done with the DV scan of the current target
+        */
+       if (pDvBuf)
+               pci_free_consistent(ioc->pcidev, dv_alloc, pDvBuf, dvbuf_dma);
+
+       ddvtprintk((MYIOC_s_INFO_FMT "DV Done. IOs outstanding = %d\n",
+                       ioc->name, atomic_read(&queue_depth)));
+
+       return;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*     mptscsih_dv_parms - perform a variety of operations on the
+ *     parameters used for negotiation.
+ *     @hd: Pointer to a SCSI host.
+ *     @dv: Pointer to a structure that contains the maximum and current
+ *             negotiated parameters.
+ */
+static void
+mptscsih_dv_parms(MPT_SCSI_HOST *hd, DVPARAMETERS *dv,void *pPage)
+{
+       VirtDevice              *pTarget = NULL;
+       SCSIDevicePage0_t       *pPage0 = NULL;
+       SCSIDevicePage1_t       *pPage1 = NULL;
+       int                     val = 0, data, configuration;
+       u8                      width = 0;
+       u8                      offset = 0;
+       u8                      factor = 0;
+       u8                      negoFlags = 0;
+       u8                      cmd = dv->cmd;
+       u8                      id = dv->id;
+
+       switch (cmd) {
+       case MPT_GET_NVRAM_VALS:
+               ddvprintk((MYIOC_s_NOTE_FMT "Getting NVRAM: ",
+                                                        hd->ioc->name));
+               /* Get the NVRAM values and save in tmax
+                * If not an LVD bus, the adapter minSyncFactor has been
+                * already throttled back.
+                */
+               if ((hd->Targets)&&((pTarget = hd->Targets[(int)id]) != NULL) && !pTarget->raidVolume) {
+                       width = pTarget->maxWidth;
+                       offset = pTarget->maxOffset;
+                       factor = pTarget->minSyncFactor;
+                       negoFlags = pTarget->negoFlags;
+               } else {
+                       if (hd->ioc->spi_data.nvram && (hd->ioc->spi_data.nvram[id] != MPT_HOST_NVRAM_INVALID)) {
+                               data = hd->ioc->spi_data.nvram[id];
+                               width = data & MPT_NVRAM_WIDE_DISABLE ? 0 : 1;
+                               if ((offset = hd->ioc->spi_data.maxSyncOffset) == 0)
+                                       factor = MPT_ASYNC;
+                               else {
+                                       factor = (data & MPT_NVRAM_SYNC_MASK) >> MPT_NVRAM_SYNC_SHIFT;
+                                       if ((factor == 0) || (factor == MPT_ASYNC)){
+                                               factor = MPT_ASYNC;
+                                               offset = 0;
+                                       }
+                               }
+                       } else {
+                               width = MPT_NARROW;
+                               offset = 0;
+                               factor = MPT_ASYNC;
+                       }
+
+                       /* Set the negotiation flags */
+                       negoFlags = hd->ioc->spi_data.noQas;
+                       if (!width)
+                               negoFlags |= MPT_TARGET_NO_NEGO_WIDE;
+
+                       if (!offset)
+                               negoFlags |= MPT_TARGET_NO_NEGO_SYNC;
+               }
+
+               /* limit by adapter capabilities */
+               width = MIN(width, hd->ioc->spi_data.maxBusWidth);
+               offset = MIN(offset, hd->ioc->spi_data.maxSyncOffset);
+               factor = MAX(factor, hd->ioc->spi_data.minSyncFactor);
+
+               /* Check Consistency */
+               if (offset && (factor < MPT_ULTRA2) && !width)
+                       factor = MPT_ULTRA2;
+
+               dv->max.width = width;
+               dv->max.offset = offset;
+               dv->max.factor = factor;
+               dv->max.flags = negoFlags;
+               ddvprintk((" width %d, factor %x, offset %x flags %x\n",
+                               width, factor, offset, negoFlags));
+               break;
+
+       case MPT_UPDATE_MAX:
+               ddvprintk((MYIOC_s_NOTE_FMT
+                       "Updating with SDP0 Data: ", hd->ioc->name));
+               /* Update tmax values with those from Device Page 0.*/
+               pPage0 = (SCSIDevicePage0_t *) pPage;
+               if (pPage0) {
+                       val = cpu_to_le32(pPage0->NegotiatedParameters);
+                       dv->max.width = val & MPI_SCSIDEVPAGE0_NP_WIDE ? 1 : 0;
+                       dv->max.offset = (val&MPI_SCSIDEVPAGE0_NP_NEG_SYNC_OFFSET_MASK) >> 16;
+                       dv->max.factor = (val&MPI_SCSIDEVPAGE0_NP_NEG_SYNC_PERIOD_MASK) >> 8;
+               }
+
+               dv->now.width = dv->max.width;
+               dv->now.offset = dv->max.offset;
+               dv->now.factor = dv->max.factor;
+               ddvprintk(("width %d, factor %x, offset %x, flags %x\n",
+                               dv->now.width, dv->now.factor, dv->now.offset, dv->now.flags));
+               break;
+
+       case MPT_SET_MAX:
+               ddvprintk((MYIOC_s_NOTE_FMT "Setting Max: ",
+                                                               hd->ioc->name));
+               /* Set current to the max values. Update the config page.*/
+               dv->now.width = dv->max.width;
+               dv->now.offset = dv->max.offset;
+               dv->now.factor = dv->max.factor;
+               dv->now.flags = dv->max.flags;
+
+               pPage1 = (SCSIDevicePage1_t *)pPage;
+               if (pPage1) {
+                       mptscsih_setDevicePage1Flags (dv->now.width, dv->now.factor,
+                               dv->now.offset, &val, &configuration, dv->now.flags);
+                       pPage1->RequestedParameters = le32_to_cpu(val);
+                       pPage1->Reserved = 0;
+                       pPage1->Configuration = le32_to_cpu(configuration);
+
+               }
+
+               ddvprintk(("width %d, factor %x, offset %x request %x, config %x\n",
+                               dv->now.width, dv->now.factor, dv->now.offset, val, configuration));
+               break;
+
+       case MPT_SET_MIN:
+               ddvprintk((MYIOC_s_NOTE_FMT "Setting Min: ",
+                                                               hd->ioc->name));
+               /* Set page to asynchronous and narrow 
+                * Do not update now, breaks fallback routine. */
+               width = MPT_NARROW;
+               offset = 0;
+               factor = MPT_ASYNC;
+               negoFlags = dv->max.flags;
+
+               pPage1 = (SCSIDevicePage1_t *)pPage;
+               if (pPage1) {
+                       mptscsih_setDevicePage1Flags (width, factor,
+                               offset, &val, &configuration, negoFlags);
+                       pPage1->RequestedParameters = le32_to_cpu(val);
+                       pPage1->Reserved = 0;
+                       pPage1->Configuration = le32_to_cpu(configuration);
+               }
+               ddvprintk(("width %d, factor %x, offset %x request %x config %x\n",
+                               dv->now.width, dv->now.factor,
+                               dv->now.offset, val, configuration));
+               break;
+
+       case MPT_FALLBACK:
+               ddvprintk((MYIOC_s_NOTE_FMT
+                       "Fallback: Start: offset %d, factor %x, width %d \n",
+                               hd->ioc->name, dv->now.offset, 
+                               dv->now.factor, dv->now.width));
+               width = dv->now.width;
+               offset = dv->now.offset;
+               factor = dv->now.factor;
+               if ((offset) && (dv->max.width)) {
+                       if (factor < MPT_ULTRA160)
+                               factor = MPT_ULTRA160;
+                       else if (factor < MPT_ULTRA2) {
+                               factor = MPT_ULTRA2;
+                               width = MPT_WIDE;
+                       } else if ((factor == MPT_ULTRA2) && width) {
+                               factor = MPT_ULTRA2;
+                               width = MPT_NARROW;
+                       } else if (factor < MPT_ULTRA) {
+                               factor = MPT_ULTRA;
+                               width = MPT_WIDE;
+                       } else if ((factor == MPT_ULTRA) && width) {
+                               factor = MPT_ULTRA;
+                               width = MPT_NARROW;
+                       } else if (factor < MPT_FAST) {
+                               factor = MPT_FAST;
+                               width = MPT_WIDE;
+                       } else if ((factor == MPT_FAST) && width) {
+                               factor = MPT_FAST;
+                               width = MPT_NARROW;
+                       } else if (factor < MPT_SCSI) {
+                               factor = MPT_SCSI;
+                               width = MPT_WIDE;
+                       } else if ((factor == MPT_SCSI) && width) {
+                               factor = MPT_SCSI;
+                               width = MPT_NARROW;
+                       } else {
+                               factor = MPT_ASYNC;
+                               offset = 0;
+                       }
+
+               } else if (offset) {
+                       width = MPT_NARROW;
+                       if (factor < MPT_ULTRA)
+                               factor = MPT_ULTRA;
+                       else if (factor < MPT_FAST)
+                               factor = MPT_FAST;
+                       else if (factor < MPT_SCSI)
+                               factor = MPT_SCSI;
+                       else {
+                               factor = MPT_ASYNC;
+                               offset = 0;
+                       }
+
+               } else {
+                       width = MPT_NARROW;
+                       factor = MPT_ASYNC;
                }
-               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));
+               dv->max.flags |= MPT_TARGET_NO_NEGO_QAS;
+
+               dv->now.width = width;
+               dv->now.offset = offset;
+               dv->now.factor = factor;
+               dv->now.flags = dv->max.flags;
+
+               pPage1 = (SCSIDevicePage1_t *)pPage;
+               if (pPage1) {
+                       mptscsih_setDevicePage1Flags (width, factor, offset, &val,
+                                               &configuration, dv->now.flags);
+
+                       pPage1->RequestedParameters = le32_to_cpu(val);
+                       pPage1->Reserved = 0;
+                       pPage1->Configuration = le32_to_cpu(configuration);
                }
-       }
-}
-#endif
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-static int dump_cdb(char *foo, unsigned char *cdb)
-{
-       int i, grpCode, cdbLen;
-       int l = 0;
+               ddvprintk(("Finish: offset %d, factor %x, width %d, request %x config %x\n",
+                            dv->now.offset, dv->now.factor, dv->now.width, val, configuration));
+               break;
 
-       grpCode = cdb[0] >> 5;
-       if (grpCode < 1)
-               cdbLen = 6;
-       else if (grpCode < 3)
-               cdbLen = 10;
-       else if (grpCode == 5)
-               cdbLen = 12;
-       else
-               cdbLen = 16;
+       case MPT_SAVE:
+               ddvprintk((MYIOC_s_NOTE_FMT
+                       "Saving to Target structure: ", hd->ioc->name));
+               ddvprintk(("offset %d, factor %x, width %d \n",
+                            dv->now.offset, dv->now.factor, dv->now.width));
 
-       for (i=0; i < cdbLen; i++)
-               l += sprintf(foo+l, " %02X", cdb[i]);
+               /* Save these values to target structures
+                * or overwrite nvram (phys disks only).
+                */
 
-       return l;
-}
+               if ((hd->Targets)&&((pTarget = hd->Targets[(int)id]) != NULL) && !pTarget->raidVolume ) {
+                       pTarget->maxWidth = dv->now.width;
+                       pTarget->maxOffset = dv->now.offset;
+                       pTarget->minSyncFactor = dv->now.factor;
+                       pTarget->negoFlags = dv->now.flags;
+               } else {
+                       /* Preserv all flags, use
+                        * read-modify-write algorithm
+                        */
+                       if (hd->ioc->spi_data.nvram) {
+                               data = hd->ioc->spi_data.nvram[id];
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-static int dump_sd(char *foo, unsigned char *sd)
-{
-       int snsLen = 8 + SD_Additional_Sense_Length(sd);
-       int l = 0;
-       int i;
+                               if (dv->now.width)
+                                       data &= ~MPT_NVRAM_WIDE_DISABLE;
+                               else
+                                       data |= MPT_NVRAM_WIDE_DISABLE;
 
-       for (i=0; i < MIN(snsLen,18); i++)
-               l += sprintf(foo+l, " %02X", sd[i]);
-       l += sprintf(foo+l, "%s", snsLen>18 ? " ..." : "");
+                               if (!dv->now.offset)
+                                       factor = MPT_ASYNC;
 
-       return l;
+                               data &= ~MPT_NVRAM_SYNC_MASK;
+                               data |= (dv->now.factor << MPT_NVRAM_SYNC_SHIFT) & MPT_NVRAM_SYNC_MASK;
+
+                               hd->ioc->spi_data.nvram[id] = data;
+                       }
+               }
+               break;
+       }
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*  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)
+/*     mptscsih_fillbuf - fill a buffer with a special data pattern
+ *             cleanup. For bus scan only.
+ *
+ *     @buffer: Pointer to data buffer to be filled.
+ *     @size: Number of bytes to fill
+ *     @index: Pattern index
+ *     @width: bus width, 0 (8 bits) or 1 (16 bits)
+ */
+static void
+mptscsih_fillbuf(char *buffer, int size, int index, int width)
 {
-       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";
+       char *ptr = buffer;
+       int ii;
+       char byte;
+       short val;
 
-       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;
+       switch (index) {
+       case 0:
 
-       *s1 = *s2 = *s3 = *s4 = "";             /* set'em all to the empty "" string */
+               if (width) {
+                       /* Pattern:  0000 FFFF 0000 FFFF
+                        */
+                       for (ii=0; ii < size; ii++, ptr++) {
+                               if (ii & 0x02)
+                                       *ptr = 0xFF;
+                               else
+                                       *ptr = 0x00;
+                       }
+               } else {
+                       /* Pattern:  00 FF 00 FF
+                        */
+                       for (ii=0; ii < size; ii++, ptr++) {
+                               if (ii & 0x01)
+                                       *ptr = 0xFF;
+                               else
+                                       *ptr = 0x00;
+                       }
+               }
+               break;
 
-       /* CHECKME! Need lock/sem?
-        *  Update and examine for isense module presense.
-        */
-       mptscsih_ASCQ_TablePtr = (ASCQ_Table_t *)mpt_v_ASCQ_TablePtr;
+       case 1:
+               if (width) {
+                       /* Pattern:  5555 AAAA 5555 AAAA 5555
+                        */
+                       for (ii=0; ii < size; ii++, ptr++) {
+                               if (ii & 0x02)
+                                       *ptr = 0xAA;
+                               else
+                                       *ptr = 0x55;
+                       }
+               } else {
+                       /* Pattern:  55 AA 55 AA 55
+                        */
+                       for (ii=0; ii < size; ii++, ptr++) {
+                               if (ii & 0x01)
+                                       *ptr = 0xAA;
+                               else
+                                       *ptr = 0x55;
+                       }
+               }
+               break;
 
-       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 }
+       case 2:
+               /* Pattern:  00 01 02 03 04 05
+                * ... FE FF 00 01..
                 */
-               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;
+               for (ii=0; ii < size; ii++, ptr++)
+                       *ptr = (char) ii;
+               break;
 
-       /*  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);
+       case 3:
+               if (width) {
+                       /* Wide Pattern:  FFFE 0001 FFFD 0002
+                        * ...  4000 DFFF 8000 EFFF
+                        */
+                       byte = 0;
+                       for (ii=0; ii < size/2; ii++) {
+                               /* Create the base pattern
+                                */
+                               val = (1 << byte);
+                               /* every 64 (0x40) bytes flip the pattern
+                                * since we fill 2 bytes / iteration,
+                                * test for ii = 0x20
+                                */
+                               if (ii & 0x20)
+                                       val = ~(val);
+
+                               if (ii & 0x01) {
+                                       *ptr = (char)( (val & 0xFF00) >> 8);
+                                       ptr++;
+                                       *ptr = (char)(val & 0xFF);
+                                       byte++;
+                                       byte &= 0x0F;
+                               } else {
+                                       val = ~val;
+                                       *ptr = (char)( (val & 0xFF00) >> 8);
+                                       ptr++;
+                                       *ptr = (char)(val & 0xFF);
+                               }
 
-       if ((ASC >= 0x80) || (ASCQ >= 0x80))
-               *s1 = ascq_vendor_uniq;
-       else
-               *s1 = ascq_noone;
+                               ptr++;
+                       }
+               } else {
+                       /* Narrow Pattern:  FE 01 FD 02 FB 04
+                        * .. 7F 80 01 FE 02 FD ...  80 7F
+                        */
+                       byte = 0;
+                       for (ii=0; ii < size; ii++, ptr++) {
+                               /* Base pattern - first 32 bytes
+                                */
+                               if (ii & 0x01) {
+                                       *ptr = (1 << byte);
+                                       byte++;
+                                       byte &= 0x07;
+                               } else {
+                                       *ptr = (char) (~(1 << byte));
+                               }
 
-       return *s1;
+                               /* Flip the pattern every 32 bytes
+                                */
+                               if (ii & 0x20)
+                                       *ptr = ~(*ptr);
+                       }
+               }
+               break;
+       }
 }
+#endif /* ~MPTSCSIH_DISABLE_DOMAIN_VALIDATION */
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*
- *  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"
- *---
+/* Commandline Parsing routines and defines.
+ *
+ * insmod format:
+ *     insmod mptscsih mptscsih="width:1 dv:n factor:0x09"
+ *  boot format:
+ *     mptscsih=width:1,dv:n,factor:0x8
+ *
  */
+#ifdef MODULE
+#define        ARG_SEP ' '
+#else
+#define        ARG_SEP ','
+#endif
 
-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;
-       }
+static char setup_token[] __initdata =
+       "dv:"
+       "width:"
+       "factor:"
+       ;       /* DONNOT REMOVE THIS ';' */
 
-       /*
-        *  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;
+#define OPT_DV                 1
+#define OPT_MAX_WIDTH          2
+#define OPT_MIN_SYNC_FACTOR    3
 
-       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;
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+__init get_setup_token(char *p)
+{
+       char *cur = setup_token;
+       char *pc;
+       int i = 0;
+
+       while (cur != NULL && (pc = strchr(cur, ':')) != NULL) {
+               ++pc;
+               ++i;
+               if (!strncmp(p, cur, pc - cur))
+                       return i;
+               cur = pc;
        }
+       return 0;
+}
 
-       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]];
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+__init mptscsih_setup(char *str)
+{
+       char *cur = str;
+       char *pc, *pv;
+       unsigned long val;
+       int  c;
+
+       while (cur != NULL && (pc = strchr(cur, ':')) != NULL) {
+               char *pe;
+
+               val = 0;
+               pv = pc;
+               c = *++pv;
+
+               if      (c == 'n')
+                       val = 0;
+               else if (c == 'y')
+                       val = 1;
+               else
+                       val = (int) simple_strtoul(pv, &pe, 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 );
+               printk("Found Token: %s, value %x\n", cur, (int)val);
+               switch (get_setup_token(cur)) {
+               case OPT_DV:
+                       driver_setup.dv = val;
+                       break;
 
-       {
-               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);
-               }
-       }
+               case OPT_MAX_WIDTH:
+                       driver_setup.max_width = val;
+                       break;
 
-#if 0
-       if (SPECIAL_ASCQ(asc,ascq))
-               l += sprintf(foo+l, " (%02Xh)", ascq);
-#endif
+               case OPT_MIN_SYNC_FACTOR:
+                       driver_setup.min_sync_fac = val;
+                       break;
 
-       PrintF(("%s\n", foo));
+               default:
+                       printk("mptscsih_setup: unexpected boot option '%.*s' ignored\n", (int)(pc-cur+1), cur);
+                       break;
+               }
 
-       return l;
+               if ((cur = strchr(cur, ARG_SEP)) != NULL)
+                       ++cur;
+       }
+       return 1;
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
index ec2fbc81dd376e9ea4ec179c90b94cfcd4fc29b9..c26ec0fe184567def15e00880afccf605ed4c9ab 100644 (file)
  *
  *      (see also mptbase.c)
  *
- *  Copyright (c) 1999-2001 LSI Logic Corporation
+ *  Copyright (c) 1999-2002 LSI Logic Corporation
  *  Originally By: Steven J. Ralston
- *  (mailto:Steve.Ralston@lsil.com)
+ *  (mailto:netscape.net)
+ *  (mailto:Pam.Delaney@lsil.com)
  *
- *  $Id: mptscsih.h,v 1.7 2001/01/11 16:56:43 sralston Exp $
+ *  $Id: mptscsih.h,v 1.18 2002/06/06 15:32:52 pdelaney Exp $
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
  *     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
+/*
+ *     Try to keep these at 2^N-1
+ */
+#define MPT_FC_CAN_QUEUE       63
+//#define MPT_SCSI_CAN_QUEUE   31
+#define MPT_SCSI_CAN_QUEUE     MPT_FC_CAN_QUEUE
+#define MPT_SCSI_CMD_PER_LUN    7
+
+#define MPT_SCSI_SG_DEPTH      40
+
+/* To disable domain validation, uncomment the
+ * following line. No effect for FC devices.
+ * For SCSI devices, driver will negotiate to
+ * NVRAM settings (if available) or to maximum adapter
+ * capabilities.
+ */
+/* #define MPTSCSIH_DISABLE_DOMAIN_VALIDATION */
+
+
+/* SCSI driver setup structure. Settings can be overridden
+ * by command line options.
+ */
+#define MPTSCSIH_DOMAIN_VALIDATION      1
+#define MPTSCSIH_MAX_WIDTH              1
+#define MPTSCSIH_MIN_SYNC               0x08
+
+struct mptscsih_driver_setup
+{
+        u8      dv;
+        u8      max_width;
+        u8      min_sync_fac;
+};
+
+
+#define MPTSCSIH_DRIVER_SETUP                   \
+{                                               \
+        MPTSCSIH_DOMAIN_VALIDATION,             \
+        MPTSCSIH_MAX_WIDTH,                     \
+        MPTSCSIH_MIN_SYNC,                      \
+}
+
+
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
 #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_select_queue_depths     mptscsih_select_queue_depths
 
 #define x_scsi_taskmgmt_bh     mptscsih_taskmgmt_bh
 #define x_scsi_old_abort       mptscsih_old_abort
 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 *);*/
+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_select_queue_depths(struct Scsi_Host *, Scsi_Device *);
 extern void             x_scsi_taskmgmt_bh(void *);
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
@@ -177,6 +213,33 @@ extern     void             x_scsi_taskmgmt_bh(void *);
 
 #ifdef MPT_SCSI_USE_NEW_EH
 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,1)
+
+#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:          x_scsi_host_reset,      \
+       bios_param:                     x_scsi_bios_param,      \
+       can_queue:                      MPT_SCSI_CAN_QUEUE,     \
+       this_id:                        -1,                     \
+       sg_tablesize:                   MPT_SCSI_SG_DEPTH,      \
+       cmd_per_lun:                    MPT_SCSI_CMD_PER_LUN,   \
+       unchecked_isa_dma:              0,                      \
+       use_clustering:                 ENABLE_CLUSTERING,      \
+}
+
+#else  /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,1) */
+
 #define MPT_SCSIHOST {                                         \
        next:                           NULL,                   \
        PROC_SCSI_DECL                                          \
@@ -194,13 +257,16 @@ extern    void             x_scsi_taskmgmt_bh(void *);
        bios_param:                     x_scsi_bios_param,      \
        can_queue:                      MPT_SCSI_CAN_QUEUE,     \
        this_id:                        -1,                     \
-       sg_tablesize:                   25,                     \
+       sg_tablesize:                   MPT_SCSI_SG_DEPTH,      \
        cmd_per_lun:                    MPT_SCSI_CMD_PER_LUN,   \
        unchecked_isa_dma:              0,                      \
        use_clustering:                 ENABLE_CLUSTERING,      \
+       use_new_eh_code:                1                       \
 }
 
-#else
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,1) */
+
+#else /* MPT_SCSI_USE_NEW_EH */
 
 #define MPT_SCSIHOST {                                         \
        next:                           NULL,                   \
@@ -216,12 +282,12 @@ extern    void             x_scsi_taskmgmt_bh(void *);
        bios_param:                     x_scsi_bios_param,      \
        can_queue:                      MPT_SCSI_CAN_QUEUE,     \
        this_id:                        -1,                     \
-       sg_tablesize:                   25,                     \
+       sg_tablesize:                   MPT_SCSI_SG_DEPTH,      \
        cmd_per_lun:                    MPT_SCSI_CMD_PER_LUN,   \
        unchecked_isa_dma:              0,                      \
        use_clustering:                 ENABLE_CLUSTERING       \
 }
-#endif
+#endif  /* MPT_SCSI_USE_NEW_EH */
 
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
index 421b6e3667bdb0c60e2c3f995b0c17f957492861..0dd95e8d37eef7c119074a20d4337699f5f57720 100644 (file)
@@ -4,11 +4,12 @@
  *      (Ultimately) SCSI-3 definitions; for now, inheriting
  *      SCSI-2 definitions.
  *
- *  Copyright (c) 1996-2001 Steven J. Ralston
+ *  Copyright (c) 1996-2002 Steven J. Ralston
  *  Written By: Steven J. Ralston (19960517)
- *  (mailto:Steve.Ralston@lsil.com)
+ *  (mailto:sjralston1@netscape.net)
+ *  (mailto:Pam.Delaney@lsil.com)
  *
- *  $Id: scsi3.h,v 1.5 2001/04/06 14:31:32 sralston Exp $
+ *  $Id: scsi3.h,v 1.9 2002/02/27 18:45:02 sralston Exp $
  */
 
 #ifndef SCSI3_H_INCLUDED
 #define CMD_Write10            0x2A
 #define CMD_WriteVerify        0x2E
 #define CMD_Verify             0x2F
+#define CMD_SynchronizeCache   0x35
 #define CMD_ReadDefectData     0x37
+#define CMD_WriteBuffer        0x3B
+#define CMD_ReadBuffer         0x3C
 #define CMD_ReadLong           0x3E
 #define CMD_LogSelect          0x4C
 #define CMD_LogSense           0x4D