]> xenbits.xensource.com Git - xenclient/kernel.git/commitdiff
MPT Fusion driver 4.00.07.00 from qlogic
authort_jeang <devnull@localhost>
Tue, 6 Jan 2009 12:06:00 +0000 (12:06 +0000)
committert_jeang <devnull@localhost>
Tue, 6 Jan 2009 12:06:00 +0000 (12:06 +0000)
http://scale.ad.xensource.com/confluence/download/attachments/1409154/DellDrivers.zip?version=1
-> DellDrivers.zip/mptlinux_4.00.07.00_2.tgz -> mptlinux-4.00.07.00-src.tar

28 files changed:
buildconfigs/conf.linux/mptlinux [new file with mode: 0644]
drivers/message/fusion/Kconfig
drivers/message/fusion/Makefile
drivers/message/fusion/csmi/csmisas.c [new file with mode: 0644]
drivers/message/fusion/csmi/csmisas.h [new file with mode: 0644]
drivers/message/fusion/linux_compat.h
drivers/message/fusion/lsi/mpi.h
drivers/message/fusion/lsi/mpi_cnfg.h
drivers/message/fusion/lsi/mpi_history.txt
drivers/message/fusion/lsi/mpi_ioc.h
drivers/message/fusion/lsi/mpi_log_sas.h
drivers/message/fusion/lsi/mpi_raid.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
drivers/message/fusion/mptdebug.h
drivers/message/fusion/mptfc.c
drivers/message/fusion/mptlan.c
drivers/message/fusion/mptlan.h
drivers/message/fusion/mptsas.c
drivers/message/fusion/mptsas.h
drivers/message/fusion/mptscsih.c
drivers/message/fusion/mptscsih.h
drivers/message/fusion/mptspi.c
drivers/message/fusion/rejected_ioctls/diag_buffer.c [new file with mode: 0644]
drivers/message/fusion/rejected_ioctls/diag_buffer.h [new file with mode: 0644]

diff --git a/buildconfigs/conf.linux/mptlinux b/buildconfigs/conf.linux/mptlinux
new file mode 100644 (file)
index 0000000..d1181c8
--- /dev/null
@@ -0,0 +1,2 @@
+CONFIG_FUSION_MAX_FC_SGE=256
+# CONFIG_FUSION_LOGGING is not set
index 3c44a2fc4efbe437ae80438f2a958472671187c4..011b1b3943eb75f7164ae2f9d3b1be37ea5cb87d 100644 (file)
@@ -1,15 +1,19 @@
 
-menu "Fusion MPT device support"
+menuconfig FUSION
+       bool "Fusion MPT device support"
        depends on PCI
+       ---help---
+       Say Y here to get to see options for Fusion Message
+       Passing Technology (MPT) drivers.
+       This option alone does not add any kernel code.
+
+       If you say N, all options in this submenu will be skipped and disabled.
 
-config FUSION
-       bool
-       default n
+if FUSION
 
 config FUSION_SPI
        tristate "Fusion MPT ScsiHost drivers for SPI"
        depends on PCI && SCSI
-       select FUSION
        select SCSI_SPI_ATTRS
        ---help---
          SCSI HOST support for a parallel SCSI host adapters.
@@ -25,7 +29,6 @@ config FUSION_SPI
 config FUSION_FC
        tristate "Fusion MPT ScsiHost drivers for FC"
        depends on PCI && SCSI
-       select FUSION
        select SCSI_FC_ATTRS
        ---help---
          SCSI HOST support for a Fiber Channel host adapters.
@@ -38,12 +41,13 @@ config FUSION_FC
          LSIFC929
          LSIFC929X
          LSIFC929XL
+         LSIFC949X
+         LSIFC949E
          Brocade FC 410/420
 
 config FUSION_SAS
        tristate "Fusion MPT ScsiHost drivers for SAS"
        depends on PCI && SCSI
-       select FUSION
        select SCSI_SAS_ATTRS
        ---help---
          SCSI HOST support for a SAS host adapters.
@@ -54,16 +58,28 @@ config FUSION_SAS
          LSISAS1068
          LSISAS1064E
          LSISAS1068E
+         LSISAS1078
 
 config FUSION_MAX_SGE
-       int "Maximum number of scatter gather entries (16 - 128)"
-       depends on FUSION
+       int "Maximum number of scatter gather entries for SAS and SPI (16 - 128)"
        default "128"
        range 16 128
        help
          This option allows you to specify the maximum number of scatter-
          gather entries per I/O. The driver default is 128, which matches
-         SCSI_MAX_PHYS_SEGMENTS. However, it may decreased down to 16.
+         SAFE_PHYS_SEGMENTS.  However, it may decreased down to 16.
+         Decreasing this parameter will reduce memory requirements
+         on a per controller instance.
+
+config FUSION_MAX_FC_SGE
+       int "Maximum number of scatter gather entries for FC (16 - 256)"
+       depends on FUSION_FC
+       default "256"
+       range 16 256
+       help
+         This option allows you to specify the maximum number of scatter-
+         gather entries per I/O. The driver default is 256, which matches
+         MAX_PHYS_SEGMENTS.  However, it may decreased down to 16.
          Decreasing this parameter will reduce memory requirements
          on a per controller instance.
 
@@ -105,7 +121,6 @@ config FUSION_LAN
 
 config FUSION_LOGGING
        bool "Fusion MPT logging facility"
-       depends on FUSION
        ---help---
          This turns on a logging facility that can be used to debug a number
          of Fusion MPT related problems.
@@ -114,7 +129,7 @@ config FUSION_LOGGING
 
          echo [level] > /sys/class/scsi_host/host#/debug_level
 
-         There are various debug levels that an be found in the source:
+         There are various debug levels that can be found in the source:
          file:drivers/message/fusion/mptdebug.h
 
-endmenu
+endif # FUSION
index 95c9532cb07ca693cd39a6f37a49c9debe3db9d6..9253d8054479bf4ccc85055f5e68e3951d70cbef 100644 (file)
@@ -1,12 +1,17 @@
-# Fusion MPT drivers; recognized debug defines...
+#
+# LSI Logic  mpt fusion
+#
+
+# csmi ioctls enable
+EXTRA_CFLAGS += -DCPQ_CIM
+EXTRA_CFLAGS += -DDIAG_BUFFER_SUPPORT
+
+EXTRA_CFLAGS += -DCONFIG_FUSION_LOGGING
 
 # enable verbose logging
 # CONFIG_FUSION_LOGGING needs to be enabled in Kconfig
 #EXTRA_CFLAGS += -DMPT_DEBUG_VERBOSE
 
-
-#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-} LSI_LOGIC
-
 obj-$(CONFIG_FUSION_SPI)       += mptbase.o mptscsih.o mptspi.o
 obj-$(CONFIG_FUSION_FC)                += mptbase.o mptscsih.o mptfc.o
 obj-$(CONFIG_FUSION_SAS)       += mptbase.o mptscsih.o mptsas.o
diff --git a/drivers/message/fusion/csmi/csmisas.c b/drivers/message/fusion/csmi/csmisas.c
new file mode 100644 (file)
index 0000000..d4a95fb
--- /dev/null
@@ -0,0 +1,5892 @@
+/*
+ *  linux/drivers/message/fusion/csmi/csmisas.c
+ *      For use with LSI Logic PCI chip/adapter(s)
+ *      running LSI Logic Fusion MPT (Message Passing Technology) firmware.
+ *
+ *  Copyright (c) 1999-2007 LSI Logic Corporation
+ *  (mailto:DL-MPTFusionLinux@lsi.com)
+ */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; version 2 of the License.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    NO WARRANTY
+    THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+    CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+    LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+    MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+    solely responsible for determining the appropriateness of using and
+    distributing the Program and assumes all risks associated with its
+    exercise of rights under this Agreement, including but not limited to
+    the risks and costs of program errors, damage to or loss of data,
+    programs or equipment, and unavailability or interruption of operations.
+
+    DISCLAIMER OF LIABILITY
+    NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+    DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
+    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+    TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+    USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+    HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+#define MPT_CSMI_DESCRIPTION "LSI Logic Corporation: Fusion MPT Driver "MPT_LINUX_VERSION_COMMON
+#define csmisas_is_this_sas_cntr(ioc) (ioc->bus_type == SAS) ? 1 : 0
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0))
+#define __user
+#include <asm/div64.h>
+#endif
+
+static int csmisas_do_raid(MPT_ADAPTER *ioc, u8 action, u8 PhysDiskNum, u8 VolumeBus,
+    u8 VolumeId, pMpiRaidActionReply_t reply);
+static u8  map_sas_status_to_csmi(u8 mpi_sas_status);
+
+/**
+ * reverse_byte_order64
+ *
+ * @data64
+ *
+ **/
+static u64
+reverse_byte_order64(u64 data64)
+{
+       int i;
+       u64 rc;
+       u8  *inWord = (u8*)&data64, *outWord = (u8*)&rc;
+
+       for (i = 0 ; i < 8 ; i++)
+               outWord[i] = inWord[7-i];
+
+       return rc;
+}
+
+/**
+ * csmisas_is_sata
+ *
+ * @phys_disk
+ *
+ **/
+static int
+csmisas_is_sata(RaidPhysDiskPage0_t *phys_disk)
+{
+       if ((phys_disk->ExtDiskIdentifier[0] == 'A') &&
+           (phys_disk->ExtDiskIdentifier[1] == 'T') &&
+           (phys_disk->ExtDiskIdentifier[2] == 'A'))
+               return 1;
+       else
+               return 0;
+}
+
+/**
+ * csmisas_is_end_device
+ *
+ * @attached
+ *
+ **/
+static inline int
+csmisas_is_end_device(struct mptsas_devinfo * attached)
+{
+       if ((attached->sas_address) &&
+           (attached->device_info &
+           MPI_SAS_DEVICE_INFO_END_DEVICE) &&
+           ((attached->device_info &
+           MPI_SAS_DEVICE_INFO_SSP_TARGET) |
+           (attached->device_info &
+           MPI_SAS_DEVICE_INFO_STP_TARGET) |
+           (attached->device_info &
+           MPI_SAS_DEVICE_INFO_SATA_DEVICE)))
+               return 1;
+       else
+               return 0;
+}
+
+/**
+ * csmisas_is_phys_disk
+ *
+ * returns (1) success (0) fail - not a phys disk
+ **/
+static int
+csmisas_is_phys_disk(MPT_ADAPTER *ioc, int channel, int id)
+{
+       struct inactive_raid_component_info *component_info;
+       int i;
+       int rc = 0;
+
+       if (!ioc->raid_data.pIocPg3)
+               goto out;
+       for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
+               if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) &&
+                   (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) {
+                       rc = 1;
+                       goto out;
+               }
+       }
+
+       /*
+        * Check inactive list for matching phys disks
+        */
+       if (list_empty(&ioc->raid_data.inactive_list))
+               goto out;
+
+       down(&ioc->raid_data.inactive_list_mutex);
+       list_for_each_entry(component_info, &ioc->raid_data.inactive_list,
+           list) {
+               if ((component_info->d.PhysDiskID == id) &&
+                   (component_info->d.PhysDiskBus == channel))
+                       rc = 1;
+       }
+       up(&ioc->raid_data.inactive_list_mutex);
+
+ out:
+       return rc;
+}
+
+/**
+ * csmisas_raid_id_to_num
+ *
+ * Obtains the phys disk num for given H:C:T nexus
+ *
+ * input (channel/id)
+ * output (phys disk number - used by SCSI_IO_PASSTHRU to access hidden component)
+ *
+ * returns - signed return means failure
+ **/
+static s8
+csmisas_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id)
+{
+       struct inactive_raid_component_info *component_info;
+       int i;
+       s8 rc = -ENXIO;
+
+       if (!ioc->raid_data.pIocPg3)
+               goto out;
+       for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
+               if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) &&
+                   (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) {
+                       rc = ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum;
+                       goto out;
+               }
+       }
+
+       /*
+        * Check inactive list for matching phys disks
+        */
+       if (list_empty(&ioc->raid_data.inactive_list))
+               goto out;
+
+       down(&ioc->raid_data.inactive_list_mutex);
+       list_for_each_entry(component_info, &ioc->raid_data.inactive_list,
+           list) {
+               if ((component_info->d.PhysDiskID == id) &&
+                   (component_info->d.PhysDiskBus == channel))
+                       rc = component_info->d.PhysDiskNum;
+       }
+       up(&ioc->raid_data.inactive_list_mutex);
+
+ out:
+       return rc;
+}
+
+/**
+ * csmisas_get_device_component_by_os
+ *
+ * Obtain device component object by operating system mapping
+ *
+ * @ioc
+ * @channel
+ * @id
+ *
+ **/
+static struct sas_device_info *
+csmisas_get_device_component_by_os(MPT_ADAPTER *ioc, u8 channel, u8 id)
+{
+       struct sas_device_info *sas_info, *p;
+
+       sas_info = NULL;
+
+       down(&ioc->sas_device_info_mutex);
+       list_for_each_entry(p, &ioc->sas_device_info_list, list) {
+               if (p->os.channel == channel && p->os.id == id) {
+                       sas_info = p;
+                       goto out;
+               }
+       }
+
+ out:
+       up(&ioc->sas_device_info_mutex);
+       return sas_info;
+}
+
+/**
+ * csmisas_get_device_component
+ *
+ * Obtain device component object by firmware system mapping
+ *
+ * @ioc
+ * @channel
+ * @id
+ *
+ **/
+static struct sas_device_info *
+csmisas_get_device_component_by_fw(MPT_ADAPTER *ioc, u8 channel, u8 id)
+{
+       struct sas_device_info *sas_info, *p;
+
+       sas_info = NULL;
+
+       down(&ioc->sas_device_info_mutex);
+       list_for_each_entry(p, &ioc->sas_device_info_list, list) {
+               if (p->fw.channel == channel && p->fw.id == id) {
+                       sas_info = p;
+                       goto out;
+               }
+       }
+
+ out:
+       up(&ioc->sas_device_info_mutex);
+       return sas_info;
+}
+
+
+/**
+ * csmisas_get_device_component_by_sas_addr
+ *
+ * Obtain device component object by sas address
+ *
+ * @ioc
+ * @channel
+ * @id
+ *
+ **/
+static struct sas_device_info *
+csmisas_get_device_component_by_sas_addr(MPT_ADAPTER *ioc, u64 sas_address)
+{
+       struct sas_device_info *sas_info, *p;
+
+       sas_info = NULL;
+
+       down(&ioc->sas_device_info_mutex);
+       list_for_each_entry(p, &ioc->sas_device_info_list, list) {
+               if (p->sas_address == sas_address) {
+                       sas_info = p;
+                       goto out;
+               }
+       }
+
+ out:
+       up(&ioc->sas_device_info_mutex);
+       return sas_info;
+}
+
+/**
+ * csmisas_send_command_wait
+ *
+ * Send mf to firmware
+ *
+ * @ioc
+ * @mf
+ * @timeout - timeout
+ *
+ *     Return: 0 for success
+ *     non-zero, failure
+ **/
+static int
+csmisas_send_command_wait(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, unsigned long timeout)
+{
+       int rc;
+       unsigned long timeleft;
+
+       timeout = max_t(unsigned long, MPT_IOCTL_DEFAULT_TIMEOUT, timeout);
+       rc = 0;
+       timeleft = 0;
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0))
+
+       INITIALIZE_IOCTL_STATUS(ioc->ioctl_cmds.status)
+       ioc->ioctl_cmds.wait_done = 0;
+       ioc->ioctl_cmds.timer.expires = jiffies + (MPT_JIFFY * timeout);
+       ioc->ioctl_cmds.status |= MPT_MGMT_STATUS_TIMER_ACTIVE;
+       ADD_TIMER(&ioc->ioctl_cmds.timer);
+       mpt_put_msg_frame(mptctl_id, ioc, mf);
+       WAIT_EVENT(mptctl_wait, ioc->ioctl_cmds.wait_done);
+
+#elif (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16))
+
+       INITIALIZE_IOCTL_STATUS(ioc->ioctl_cmds.status)
+       ioc->ioctl_cmds.wait_done = 0;
+       mpt_put_msg_frame(mptctl_id, ioc, mf);
+
+       if ((wait_event_timeout(mptctl_wait,
+           ioc->ioctl_cmds.wait_done == 1, HZ * timeout) <=0) &&
+           ioc->ioctl_cmds.wait_done != 1 ) {
+               mptctl_timeout_expired(ioc,mf);
+               mpt_free_msg_frame(ioc, mf);
+               rc = -1;
+       }
+
+#else
+
+       SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context,
+           mf->u.hdr.MsgContext);
+       INITIALIZE_MGMT_STATUS(ioc->ioctl_cmds.status)
+       mpt_put_msg_frame(mptctl_id, ioc, mf);
+       timeleft = wait_for_completion_timeout(&ioc->ioctl_cmds.done, timeout*HZ);
+       if (!(ioc->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
+               rc = -1;
+               printk("%s: failed\n", __FUNCTION__);
+               if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) {
+                       mpt_free_msg_frame(ioc, mf);
+                       CLEAR_MGMT_STATUS(ioc->ioctl_cmds.status)
+                       return rc;
+               }
+               if (!timeleft)
+                       mptctl_timeout_expired(ioc, mf);
+       }
+       SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context, 0);
+#endif
+       return rc;
+}
+
+/**
+ * csmisas_send_handshake_wait
+ *
+ * Handshake a mf to firmware
+ *
+ * @ioc
+ * @mf
+ * @mf_size
+ * @timeout - timeout
+ *
+ *     Return: 0 for success
+ *     non-zero, failure
+ **/
+static int
+csmisas_send_handshake_wait(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, unsigned long timeout)
+{
+       int rc;
+       unsigned long timeleft;
+
+       timeout = max_t(unsigned long, MPT_IOCTL_DEFAULT_TIMEOUT, timeout);
+       rc = 0;
+       timeleft = 0;
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0))
+
+       INITIALIZE_IOCTL_STATUS(ioc->taskmgmt_cmds.status)
+       ioc->taskmgmt_cmds.timer.expires = jiffies + (MPT_JIFFY*timeout);
+       ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_TIMER_ACTIVE;
+       ioc->taskmgmt_cmds.wait_done = 0;
+       ADD_TIMER(&ioc->taskmgmt_cmds.timer);
+       rc = mpt_send_special_message(mptctl_taskmgmt_id, ioc,
+           sizeof(SCSITaskMgmt_t), (u32*)mf, timeout, CAN_SLEEP);
+       if (rc != 0)
+               return rc;
+       WAIT_EVENT(mptctl_taskmgmt_wait, ioc->taskmgmt_cmds.wait_done);
+
+#elif (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16))
+
+       INITIALIZE_IOCTL_STATUS(ioc->taskmgmt_cmds.status)
+       ioc->taskmgmt_cmds.wait_done = 0;
+       rc = mpt_send_special_message(mptctl_taskmgmt_id, ioc,
+           sizeof(SCSITaskMgmt_t), (u32*)mf, timeout, CAN_SLEEP);
+       if (rc != 0)
+               return rc;
+       if ((wait_event_timeout(mptctl_taskmgmt_wait,
+           ioc->taskmgmt_cmds.wait_done == 1, HZ * timeout) <=0) &&
+           ioc->taskmgmt_cmds.wait_done != 1 ) {
+               mptctl_timeout_expired(ioc, mf);
+               mpt_free_msg_frame(ioc, mf);
+               rc = -1;
+       }
+
+#else
+       INITIALIZE_MGMT_STATUS(ioc->taskmgmt_cmds.status)
+       mpt_put_msg_frame_hi_pri(mptctl_taskmgmt_id, ioc, mf);
+       timeleft = wait_for_completion_timeout(&ioc->taskmgmt_cmds.done, timeout*HZ);
+       if (!(ioc->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
+               rc = -1;
+               printk("%s: failed\n", __FUNCTION__);
+               mpt_clear_taskmgmt_in_progress_flag(ioc);
+               if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) {
+                       mpt_free_msg_frame(ioc, mf);
+                       CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status)
+                       return rc;
+               }
+               if (!timeleft)
+                       mptctl_timeout_expired(ioc, mf);
+       }
+#endif
+       return rc;
+}
+
+/**
+ *     csmisas_get_number_hotspares - returns num hot spares in this ioc
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *
+ *     Return: number of hotspares
+ *
+ **/
+static int
+csmisas_get_number_hotspares(MPT_ADAPTER *ioc)
+{
+       ConfigPageHeader_t       hdr;
+       CONFIGPARMS              cfg;
+       IOCPage5_t               *buffer = NULL;
+       dma_addr_t               dma_handle;
+       int                      data_sz;
+       int                      rc;
+
+       memset(&hdr, 0, sizeof(ConfigPageHeader_t));
+       memset(&cfg, 0, sizeof(CONFIGPARMS));
+
+       rc = 0;
+       data_sz = 0;
+       hdr.PageNumber = 5;
+       hdr.PageType = MPI_CONFIG_PAGETYPE_IOC;
+       cfg.cfghdr.hdr = &hdr;
+       cfg.physAddr = -1;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+       cfg.timeout = MPT_IOCTL_DEFAULT_TIMEOUT;
+
+       if (mpt_config(ioc, &cfg) != 0)
+               goto get_ioc_pg5;
+
+       if (hdr.PageLength == 0)
+               goto get_ioc_pg5;
+
+       data_sz = hdr.PageLength * 4;
+       buffer = (IOCPage5_t *) pci_alloc_consistent(ioc->pcidev,
+               data_sz, &dma_handle);
+       if (!buffer)
+               goto get_ioc_pg5;
+
+       memset((u8 *)buffer, 0, data_sz);
+       cfg.physAddr = dma_handle;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+
+       if (mpt_config(ioc, &cfg) != 0)
+               goto get_ioc_pg5;
+
+       rc = buffer->NumHotSpares;
+
+ get_ioc_pg5:
+
+       if (buffer)
+               pci_free_consistent(ioc->pcidev, data_sz,
+                   (u8 *) buffer, dma_handle);
+
+       return rc;
+}
+
+
+/**
+ *     csmisas_get_ioc_pg5 - ioc Page 5 hot spares
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @pIocPage5: ioc page 5
+ *     @data_size: expected data size(units=bytes)
+ *
+ *     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
+csmisas_get_ioc_pg5(MPT_ADAPTER *ioc, IOCPage5_t *iocPage5, int data_size)
+{
+       ConfigPageHeader_t       hdr;
+       CONFIGPARMS              cfg;
+       IOCPage5_t               *buffer = NULL;
+       dma_addr_t               dma_handle;
+       int                      data_sz;
+       int                      rc;
+
+       memset(&hdr, 0, sizeof(ConfigPageHeader_t));
+       memset(&cfg, 0, sizeof(CONFIGPARMS));
+
+       rc = 0;
+       data_sz = 0;
+       hdr.PageNumber = 5;
+       hdr.PageType = MPI_CONFIG_PAGETYPE_IOC;
+       cfg.cfghdr.hdr = &hdr;
+       cfg.physAddr = -1;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+       cfg.timeout = MPT_IOCTL_DEFAULT_TIMEOUT;
+
+       if ((rc = mpt_config(ioc, &cfg)) != 0)
+               goto get_ioc_pg5;
+
+       if (hdr.PageLength == 0) {
+               rc = -EFAULT;
+               goto get_ioc_pg5;
+       }
+
+       data_sz = hdr.PageLength * 4;
+       buffer = (IOCPage5_t *) pci_alloc_consistent(ioc->pcidev,
+               data_sz, &dma_handle);
+       if (!buffer) {
+               rc = -ENOMEM;
+               goto get_ioc_pg5;
+       }
+
+       memset((u8 *)buffer, 0, data_sz);
+       cfg.physAddr = dma_handle;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+
+       if ((rc = mpt_config(ioc, &cfg)) != 0)
+               goto get_ioc_pg5;
+
+       memcpy(iocPage5, buffer, data_size);
+
+ get_ioc_pg5:
+
+       if (buffer)
+               pci_free_consistent(ioc->pcidev, data_sz,
+                   (u8 *) buffer, dma_handle);
+
+       return rc;
+}
+
+/**
+ *     csmisas_sas_device_pg0 - sas device page 0
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @mptsas_devinfo: structure found in mptsas.h
+ *     @form, @form_specific - defines the Page Address field in the config page
+ *             (pls refer to chapter 5.1 in the mpi spec)
+ *
+ *     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
+csmisas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info,
+               u32 form, u32 form_specific)
+{
+       ConfigExtendedPageHeader_t hdr;
+       CONFIGPARMS cfg;
+       SasDevicePage0_t *buffer;
+       dma_addr_t dma_handle;
+       u64 sas_address;
+       int rc;
+
+       rc = 0;
+       hdr.PageVersion = MPI_SASDEVICE0_PAGEVERSION;
+       hdr.ExtPageLength = 0;
+       hdr.PageNumber = 0;
+       hdr.Reserved1 = 0;
+       hdr.Reserved2 = 0;
+       hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
+       hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE;
+
+       cfg.cfghdr.ehdr = &hdr;
+       cfg.pageAddr = form + form_specific;
+       cfg.physAddr = -1;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+       cfg.dir = 0;    /* read */
+       cfg.timeout = 10;
+
+       memset(device_info, 0, sizeof(struct mptsas_devinfo));
+       if ((rc = mpt_config(ioc, &cfg)) != 0)
+               goto out;
+
+       if (!hdr.ExtPageLength) {
+               rc = -ENXIO;
+               goto out;
+       }
+
+       buffer = pci_alloc_consistent(ioc->pcidev,
+           hdr.ExtPageLength * 4, &dma_handle);
+       if (!buffer) {
+               rc = -ENOMEM;
+               goto out;
+       }
+
+       cfg.physAddr = dma_handle;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+
+       if ((rc = mpt_config(ioc, &cfg)) != 0)
+               goto out_free_consistent;
+
+       device_info->handle = le16_to_cpu(buffer->DevHandle);
+       device_info->handle_parent = le16_to_cpu(buffer->ParentDevHandle);
+       device_info->handle_enclosure =
+           le16_to_cpu(buffer->EnclosureHandle);
+       device_info->slot = le16_to_cpu(buffer->Slot);
+       device_info->phy_id = buffer->PhyNum;
+       device_info->port_id = buffer->PhysicalPort;
+       device_info->id = buffer->TargetID;
+       device_info->channel = buffer->Bus;
+       memcpy(&sas_address, &buffer->SASAddress, sizeof(u64));
+       device_info->sas_address = le64_to_cpu(sas_address);
+       device_info->device_info =
+           le32_to_cpu(buffer->DeviceInfo);
+
+ out_free_consistent:
+       pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
+                           buffer, dma_handle);
+ out:
+       return rc;
+}
+
+/**
+ * Routine for the CSMI Sas Get Driver Info command.
+ *
+ * Outputs:    None.
+ * Return:     0 if successful
+ *             -EFAULT if data unavailable
+ *             -ENODEV if no such device/adapter
+ **/
+static int
+csmisas_get_driver_info(unsigned long arg)
+{
+
+       CSMI_SAS_DRIVER_INFO_BUFFER __user *uarg = (void __user *) arg;
+       CSMI_SAS_DRIVER_INFO_BUFFER     karg;
+       MPT_ADAPTER     *ioc = NULL;
+       int             iocnum;
+
+       if (copy_from_user(&karg, uarg, sizeof(CSMI_SAS_DRIVER_INFO_BUFFER))) {
+               printk(KERN_ERR "%s@%d::%s - "
+             "Unable to read in csmi_sas_get_driver_info_buffer struct @ %p\n",
+                   __FILE__, __LINE__, __FUNCTION__, uarg);
+               return -EFAULT;
+       }
+
+       if (((iocnum = mpt_verify_adapter(karg.IoctlHeader.IOControllerNumber,
+           &ioc)) < 0) || (ioc == NULL)) {
+               printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n",
+                   __FILE__, __FUNCTION__, __LINE__, iocnum);
+               return -ENODEV;
+       }
+
+       if (!csmisas_is_this_sas_cntr(ioc)) {
+               printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n",
+                   __FILE__, __FUNCTION__, __LINE__, iocnum);
+               return -ENODEV;
+       }
+
+       dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__));
+
+       /* Fill in the data and return the structure to the calling
+        * program
+        */
+       memcpy( karg.Information.szName, MPT_MISCDEV_BASENAME,
+           sizeof(MPT_MISCDEV_BASENAME));
+       memcpy( karg.Information.szDescription, MPT_CSMI_DESCRIPTION,
+           sizeof(MPT_CSMI_DESCRIPTION));
+
+       karg.Information.usMajorRevision = MPT_LINUX_MAJOR_VERSION;
+       karg.Information.usMinorRevision = MPT_LINUX_MINOR_VERSION;
+       karg.Information.usBuildRevision = MPT_LINUX_BUILD_VERSION;
+       karg.Information.usReleaseRevision = MPT_LINUX_RELEASE_VERSION;
+
+       karg.Information.usCSMIMajorRevision = CSMI_MAJOR_REVISION;
+       karg.Information.usCSMIMinorRevision = CSMI_MINOR_REVISION;
+
+       karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS;
+
+       /* Copy the data from kernel memory to user memory
+        */
+       if (copy_to_user(uarg, &karg,
+               sizeof(CSMI_SAS_DRIVER_INFO_BUFFER))) {
+               printk(KERN_ERR "%s@%d::%s - "
+                  "Unable to write out csmi_sas_get_driver_info_buffer @ %p\n",
+                   __FILE__, __LINE__, __FUNCTION__, uarg);
+               return -EFAULT;
+       }
+
+       dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__));
+       return 0;
+}
+
+/**
+ * Prototype Routine for the CSMI_SAS_GET_CNTLR_CONFIG command.
+ *
+ * Outputs:    None.
+ * Return:     0 if successful
+ *             -EFAULT if data unavailable
+ *             -ENODEV if no such device/adapter
+ **/
+static int
+csmisas_get_cntlr_config(unsigned long arg)
+{
+
+       CSMI_SAS_CNTLR_CONFIG_BUFFER __user *uarg = (void __user *) arg;
+       CSMI_SAS_CNTLR_CONFIG_BUFFER    karg;
+       MPT_ADAPTER     *ioc = NULL;
+       int             iocnum;
+       u64             mem_phys;
+
+       if (copy_from_user(&karg, uarg, sizeof(CSMI_SAS_CNTLR_CONFIG_BUFFER))) {
+               printk(KERN_ERR "%s@%d::%s - "
+            "Unable to read in csmi_sas_get_cntlr_config_buffer struct @ %p\n",
+                   __FILE__, __LINE__, __FUNCTION__, uarg);
+               return -EFAULT;
+       }
+
+       if (((iocnum = mpt_verify_adapter(karg.IoctlHeader.IOControllerNumber,
+           &ioc)) < 0) || (ioc == NULL)) {
+               printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n",
+                   __FILE__, __FUNCTION__, __LINE__, iocnum);
+               karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_INVALID_PARAMETER;
+               return -ENODEV;
+       }
+
+       if (!csmisas_is_this_sas_cntr(ioc)) {
+               printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n",
+                   __FILE__, __FUNCTION__, __LINE__, iocnum);
+               return -ENODEV;
+       }
+
+       dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__));
+
+       /* Clear the struct before filling in data. */
+       memset( &karg.Configuration, 0, sizeof(CSMI_SAS_CNTLR_CONFIG));
+
+       /* Fill in the data and return the structure to the calling
+        * program
+        */
+
+       karg.Configuration.uBaseIoAddress = ioc->pio_mem_phys;
+       karg.Configuration.BaseMemoryAddress.uLowPart = ioc->mem_phys;
+       if (sizeof(ioc->mem_phys) == sizeof(u64)) {
+               mem_phys = ioc->mem_phys;
+               karg.Configuration.BaseMemoryAddress.uHighPart =
+                   (u32)(mem_phys >> 32);
+       }
+
+       karg.Configuration.uBoardID = (ioc->pcidev->subsystem_device << 16) |
+           (ioc->pcidev->subsystem_vendor);
+
+       karg.Configuration.usSlotNumber =
+           (ioc->pci_slot_number = 0xff) ?
+           SLOT_NUMBER_UNKNOWN : ioc->pci_slot_number;
+       karg.Configuration.bControllerClass = CSMI_SAS_CNTLR_CLASS_HBA;
+       karg.Configuration.bIoBusType = CSMI_SAS_BUS_TYPE_PCI;
+       karg.Configuration.BusAddress.PciAddress.bBusNumber =
+           ioc->pcidev->bus->number;
+       karg.Configuration.BusAddress.PciAddress.bDeviceNumber =
+           PCI_SLOT(ioc->pcidev->devfn);
+       karg.Configuration.BusAddress.PciAddress.bFunctionNumber =
+           PCI_FUNC(ioc->pcidev->devfn);
+       karg.Configuration.BusAddress.PciAddress.bReserved = 0;
+       memcpy( &karg.Configuration.szSerialNumber, ioc->board_tracer, 16 );
+       karg.Configuration.usMajorRevision = ioc->facts.FWVersion.Struct.Major;
+       karg.Configuration.usMinorRevision = ioc->facts.FWVersion.Struct.Minor;
+       karg.Configuration.usBuildRevision = ioc->facts.FWVersion.Struct.Unit;
+       karg.Configuration.usReleaseRevision = ioc->facts.FWVersion.Struct.Dev;
+       karg.Configuration.usBIOSMajorRevision =
+           (ioc->biosVersion & 0xFF000000) >> 24;
+       karg.Configuration.usBIOSMinorRevision =
+           (ioc->biosVersion & 0x00FF0000) >> 16;
+       karg.Configuration.usBIOSBuildRevision =
+           (ioc->biosVersion & 0x0000FF00) >> 8;
+       karg.Configuration.usBIOSReleaseRevision =
+           (ioc->biosVersion & 0x000000FF);
+       karg.Configuration.uControllerFlags = CSMI_SAS_CNTLR_SAS_HBA |
+           CSMI_SAS_CNTLR_FWD_SUPPORT | CSMI_SAS_CNTLR_FWD_ONLINE |
+           CSMI_SAS_CNTLR_FWD_SRESET ;
+
+       /*
+        * Enabling CSMI_SAS_CNTLR_SAS_RAID bit when IR fw detected
+        */
+       if (ioc->ir_firmware)
+               karg.Configuration.uControllerFlags |= CSMI_SAS_CNTLR_SAS_RAID;
+
+       karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS;
+
+       /* All Rrom entries will be zero. Skip them. */
+       /* bReserved will also be zeros. */
+       /* Copy the data from kernel memory to user memory
+        */
+       if (copy_to_user(uarg, &karg,
+               sizeof(CSMI_SAS_DRIVER_INFO_BUFFER))) {
+               printk(KERN_ERR "%s@%d::%s - "
+               "Unable to write out csmi_sas_get_driver_info_buffer @ %p\n",
+                   __FILE__, __LINE__, __FUNCTION__, uarg);
+               return -EFAULT;
+       }
+
+       dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__));
+       return 0;
+}
+
+/**
+ * Prototype Routine for the CSMI Sas Get Controller Status command.
+ *
+ * Outputs:    None.
+ * Return:     0 if successful
+ *             -EFAULT if data unavailable
+ *             -ENODEV if no such device/adapter
+ **/
+static int
+csmisas_get_cntlr_status(unsigned long arg)
+{
+
+       CSMI_SAS_CNTLR_STATUS_BUFFER  __user *uarg = (void __user *) arg;
+       MPT_ADAPTER             *ioc = NULL;
+       CSMI_SAS_CNTLR_STATUS_BUFFER    karg;
+       int                     iocnum;
+       int                     rc;
+
+       if (copy_from_user(&karg, uarg, sizeof(CSMI_SAS_CNTLR_STATUS_BUFFER))) {
+               printk(KERN_ERR "%s@%d::%s - "
+            "Unable to read in csmi_sas_get_cntlr_status_buffer struct @ %p\n",
+                   __FILE__, __LINE__, __FUNCTION__, uarg);
+               return -EFAULT;
+       }
+
+       if (((iocnum = mpt_verify_adapter(karg.IoctlHeader.IOControllerNumber,
+           &ioc)) < 0) || (ioc == NULL)) {
+               printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n",
+                   __FILE__, __FUNCTION__, __LINE__, iocnum);
+               return -ENODEV;
+       }
+
+       if (!csmisas_is_this_sas_cntr(ioc)) {
+               printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n",
+                   __FILE__, __FUNCTION__, __LINE__, iocnum);
+               return -ENODEV;
+       }
+
+       dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__));
+
+       /* Fill in the data and return the structure to the calling
+        * program
+        */
+
+       rc = mpt_GetIocState(ioc, 1);
+       switch (rc) {
+       case MPI_IOC_STATE_OPERATIONAL:
+               karg.Status.uStatus =  CSMI_SAS_CNTLR_STATUS_GOOD;
+               karg.Status.uOfflineReason = 0;
+               break;
+
+       case MPI_IOC_STATE_FAULT:
+               karg.Status.uStatus = CSMI_SAS_CNTLR_STATUS_FAILED;
+               karg.Status.uOfflineReason = 0;
+               break;
+
+       case MPI_IOC_STATE_RESET:
+       case MPI_IOC_STATE_READY:
+       default:
+               karg.Status.uStatus =  CSMI_SAS_CNTLR_STATUS_OFFLINE;
+               karg.Status.uOfflineReason =
+                   CSMI_SAS_OFFLINE_REASON_INITIALIZING;
+               break;
+       }
+
+       memset(&karg.Status.bReserved, 0, 28);
+
+       karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS;
+
+       /* Copy the data from kernel memory to user memory
+        */
+       if (copy_to_user(uarg, &karg,
+               sizeof(CSMI_SAS_CNTLR_STATUS_BUFFER))) {
+               printk(KERN_ERR "%s@%d::%s - "
+                   "Unable to write out csmi_sas_get_cntlr_status @ %p\n",
+                   __FILE__, __LINE__, __FUNCTION__, uarg);
+               return -EFAULT;
+       }
+
+       dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__));
+       return 0;
+}
+
+/**
+ * Prototype Routine for the CSMI Sas Get Phy Info command.
+ *
+ * Outputs:    None.
+ * Return:     0 if successful
+ *             -EFAULT if data unavailable
+ *             -ENODEV if no such device/adapter
+ **/
+static int
+csmisas_get_phy_info(unsigned long arg)
+{
+       CSMI_SAS_PHY_INFO_BUFFER __user *uarg = (void __user *) arg;
+       CSMI_SAS_PHY_INFO_BUFFER  *karg;
+       MPT_ADAPTER             *ioc = NULL;
+       ConfigExtendedPageHeader_t  hdr;
+       CONFIGPARMS             cfg;
+       SasIOUnitPage0_t        *sasIoUnitPg0;
+       dma_addr_t              sasIoUnitPg0_dma;
+       int                     sasIoUnitPg0_data_sz;
+       SasPhyPage0_t           *sasPhyPg0;
+       dma_addr_t              sasPhyPg0_dma;
+       int                     sasPhyPg0_data_sz;
+       u16                     protocol;
+       int                     iocnum;
+       int                     rc;
+       int                     ii;
+       u64                     sas_address;
+       struct mptsas_devinfo   device_info;
+       int                     memory_pages;
+
+       sasIoUnitPg0=NULL;
+       sasPhyPg0=NULL;
+       sasIoUnitPg0_data_sz=0;
+       sasPhyPg0_data_sz=0;
+
+       memory_pages = get_order(sizeof(CSMI_SAS_PHY_INFO_BUFFER));
+       karg = (CSMI_SAS_PHY_INFO_BUFFER *)__get_free_pages(
+               GFP_KERNEL, memory_pages);
+       if (!karg){
+               printk(KERN_ERR "%s@%d::%s() - "
+                       "Unable to malloc CSMI_SAS_PHY_INFO_BUFFER "
+                       "malloc_data_sz=%d memory_pages=%d\n",
+                       __FILE__, __LINE__, __FUNCTION__,
+                       (int)sizeof(CSMI_SAS_PHY_INFO_BUFFER), memory_pages);
+               return -ENOMEM;
+       }
+
+       memset(karg, 0, sizeof(*karg));
+
+       if (copy_from_user(karg, uarg, sizeof(CSMI_SAS_PHY_INFO_BUFFER))) {
+               printk(KERN_ERR "%s@%d::%s - "
+               "Unable to read in csmisas_get_phy_info_buffer struct @ %p\n",
+                   __FILE__, __LINE__, __FUNCTION__, uarg);
+               free_pages((unsigned long)karg, memory_pages);
+               return -EFAULT;
+       }
+
+       if (((iocnum = mpt_verify_adapter(karg->IoctlHeader.IOControllerNumber,
+           &ioc)) < 0) || (ioc == NULL)) {
+               printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n",
+                   __FILE__, __FUNCTION__, __LINE__, iocnum);
+               free_pages((unsigned long)karg, memory_pages);
+               return -ENODEV;
+       }
+
+       if (!csmisas_is_this_sas_cntr(ioc)) {
+               printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n",
+                   __FILE__, __FUNCTION__, __LINE__, iocnum);
+               free_pages((unsigned long)karg, memory_pages);
+               return -ENODEV;
+       }
+
+       dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__));
+
+       /* Fill in the data and return the structure to the calling
+        * program
+        */
+
+       /* Issue a config request to get the number of phys
+        */
+       hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION;
+       hdr.ExtPageLength = 0;
+       hdr.PageNumber = 0;
+       hdr.Reserved1 = 0;
+       hdr.Reserved2 = 0;
+       hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
+       hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
+
+       cfg.cfghdr.ehdr = &hdr;
+       cfg.physAddr = -1;
+       cfg.pageAddr = 0;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+       cfg.dir = 0;    /* read */
+       cfg.timeout = MPT_IOCTL_DEFAULT_TIMEOUT;
+
+       if ((rc = mpt_config(ioc, &cfg)) != 0) {
+               /* Don't check if this failed.  Already in a
+                * failure case.
+                */
+               dcsmisasprintk(ioc, printk(KERN_ERR
+                   ": FAILED: MPI_SASIOUNITPAGE0_PAGEVERSION: HEADER\n"));
+               dcsmisasprintk(ioc, printk(": rc=%x\n",rc));
+               karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+               goto sas_get_phy_info_exit;
+       }
+
+       if (hdr.ExtPageLength == 0) {
+               /* Don't check if this failed.  Already in a
+                * failure case.
+                */
+               dcsmisasprintk(ioc, printk(KERN_ERR ": hdr.ExtPageLength == 0\n"));
+               karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+               goto sas_get_phy_info_exit;
+       }
+
+       sasIoUnitPg0_data_sz = hdr.ExtPageLength * 4;
+       rc = -ENOMEM;
+
+       sasIoUnitPg0 = (SasIOUnitPage0_t *) pci_alloc_consistent(ioc->pcidev,
+           sasIoUnitPg0_data_sz, &sasIoUnitPg0_dma);
+
+       if (!sasIoUnitPg0) {
+               dcsmisasprintk(ioc, printk(KERN_ERR ": pci_alloc_consistent: FAILED\n"));
+               karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+               goto sas_get_phy_info_exit;
+       }
+
+       memset((u8 *)sasIoUnitPg0, 0, sasIoUnitPg0_data_sz);
+       cfg.physAddr = sasIoUnitPg0_dma;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+
+       if ((rc = mpt_config(ioc, &cfg)) != 0) {
+
+               /* Don't check if this failed.  Already in a
+                * failure case.
+                */
+               dcsmisasprintk(ioc, printk(KERN_ERR
+                   ": FAILED: MPI_SASIOUNITPAGE0_PAGEVERSION: PAGE\n"));
+               dcsmisasprintk(ioc, printk(KERN_ERR ": rc=%x\n",rc));
+               karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+               goto sas_get_phy_info_exit;
+       }
+
+       /* Number of Phys. */
+       karg->Information.bNumberOfPhys = sasIoUnitPg0->NumPhys;
+
+       /* Fill in information for each phy. */
+       for (ii = 0; ii < karg->Information.bNumberOfPhys; ii++) {
+
+/* EDM : dump IO Unit Page 0 data*/
+               dcsmisasprintk(ioc, printk(KERN_DEBUG "---- IO UNIT PAGE 0 ------------\n"));
+               dcsmisasprintk(ioc, printk(KERN_DEBUG "Handle=0x%X\n",
+                   le16_to_cpu(sasIoUnitPg0->PhyData[ii].AttachedDeviceHandle)));
+               dcsmisasprintk(ioc, printk(KERN_DEBUG "Controller Handle=0x%X\n",
+                   le16_to_cpu(sasIoUnitPg0->PhyData[ii].ControllerDevHandle)));
+               dcsmisasprintk(ioc, printk(KERN_DEBUG "Port=0x%X\n",
+                   sasIoUnitPg0->PhyData[ii].Port));
+               dcsmisasprintk(ioc, printk(KERN_DEBUG "Port Flags=0x%X\n",
+                   sasIoUnitPg0->PhyData[ii].PortFlags));
+               dcsmisasprintk(ioc, printk(KERN_DEBUG "PHY Flags=0x%X\n",
+                   sasIoUnitPg0->PhyData[ii].PhyFlags));
+               dcsmisasprintk(ioc, printk(KERN_DEBUG "Negotiated Link Rate=0x%X\n",
+                   sasIoUnitPg0->PhyData[ii].NegotiatedLinkRate));
+               dcsmisasprintk(ioc, printk(KERN_DEBUG "Controller PHY Device Info=0x%X\n",
+                   le32_to_cpu(sasIoUnitPg0->PhyData[ii].ControllerPhyDeviceInfo)));
+               dcsmisasprintk(ioc, printk(KERN_DEBUG "DiscoveryStatus=0x%X\n",
+                   le32_to_cpu(sasIoUnitPg0->PhyData[ii].DiscoveryStatus)));
+               dcsmisasprintk(ioc, printk(KERN_DEBUG "\n"));
+/* EDM : debug data */
+
+               /* PHY stuff. */
+               karg->Information.Phy[ii].bPortIdentifier =
+                   sasIoUnitPg0->PhyData[ii].Port;
+
+               /* Get the negotiated link rate for the phy. */
+               switch (sasIoUnitPg0->PhyData[ii].NegotiatedLinkRate) {
+
+               case MPI_SAS_IOUNIT0_RATE_PHY_DISABLED:
+                       karg->Information.Phy[ii].bNegotiatedLinkRate =
+                           CSMI_SAS_PHY_DISABLED;
+                       break;
+
+               case MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION:
+                       karg->Information.Phy[ii].bNegotiatedLinkRate =
+                           CSMI_SAS_LINK_RATE_FAILED;
+                       break;
+
+               case MPI_SAS_IOUNIT0_RATE_SATA_OOB_COMPLETE:
+                       break;
+
+               case MPI_SAS_IOUNIT0_RATE_1_5:
+                       karg->Information.Phy[ii].bNegotiatedLinkRate =
+                           CSMI_SAS_LINK_RATE_1_5_GBPS;
+                       break;
+
+               case MPI_SAS_IOUNIT0_RATE_3_0:
+                       karg->Information.Phy[ii].bNegotiatedLinkRate =
+                           CSMI_SAS_LINK_RATE_3_0_GBPS;
+                       break;
+
+               case MPI_SAS_IOUNIT0_RATE_UNKNOWN:
+               default:
+                       karg->Information.Phy[ii].bNegotiatedLinkRate =
+                           CSMI_SAS_LINK_RATE_UNKNOWN;
+                       break;
+               }
+
+               if (sasIoUnitPg0->PhyData[ii].PortFlags &
+                   MPI_SAS_IOUNIT0_PORT_FLAGS_DISCOVERY_IN_PROGRESS) {
+                       karg->Information.Phy[ii].bAutoDiscover =
+                           CSMI_SAS_DISCOVER_IN_PROGRESS;
+               } else {
+                       karg->Information.Phy[ii].bAutoDiscover =
+                           CSMI_SAS_DISCOVER_COMPLETE;
+               }
+
+               /* Issue a config request to get
+                * phy information.
+                */
+               hdr.PageVersion = MPI_SASPHY0_PAGEVERSION;
+               hdr.ExtPageLength = 0;
+               hdr.PageNumber = 0;
+               hdr.Reserved1 = 0;
+               hdr.Reserved2 = 0;
+               hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
+               hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
+
+               cfg.cfghdr.ehdr = &hdr;
+               cfg.physAddr = -1;
+               cfg.pageAddr = ii;
+               cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+               cfg.dir = 0;    /* read */
+               cfg.timeout = MPT_IOCTL_DEFAULT_TIMEOUT;
+
+               if ((rc = mpt_config(ioc, &cfg)) != 0) {
+                       dcsmisasprintk(ioc, printk(KERN_ERR
+                           ": FAILED: MPI_SASPHY0_PAGEVERSION: HEADER\n"));
+                       dcsmisasprintk(ioc, printk(": rc=%x\n",rc));
+                       karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+                       goto sas_get_phy_info_exit;
+               }
+
+               if (hdr.ExtPageLength == 0) {
+                       dcsmisasprintk(ioc, printk(KERN_ERR ": pci_alloc_consistent: FAILED\n"));
+                       karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+                       goto sas_get_phy_info_exit;
+               }
+
+               sasPhyPg0_data_sz = hdr.ExtPageLength * 4;
+               rc = -ENOMEM;
+
+               sasPhyPg0 = (SasPhyPage0_t *) pci_alloc_consistent(
+                   ioc->pcidev, sasPhyPg0_data_sz, &sasPhyPg0_dma);
+
+               if (! sasPhyPg0) {
+                       dcsmisasprintk(ioc, printk(KERN_ERR ": pci_alloc_consistent: FAILED\n"));
+                       karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+                       goto sas_get_phy_info_exit;
+               }
+
+               memset((u8 *)sasPhyPg0, 0, sasPhyPg0_data_sz);
+               cfg.physAddr = sasPhyPg0_dma;
+               cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+
+               if ((rc = mpt_config(ioc, &cfg)) != 0) {
+                       dcsmisasprintk(ioc, printk(KERN_ERR
+                           ": FAILED: MPI_SASPHY0_PAGEVERSION: PAGE\n"));
+                       dcsmisasprintk(ioc, printk(KERN_ERR ": rc=%x\n",rc));
+                       karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+                       pci_free_consistent(ioc->pcidev, sasPhyPg0_data_sz,
+                           (u8 *) sasPhyPg0, sasPhyPg0_dma);
+                       goto sas_get_phy_info_exit;
+               }
+
+/* EDM : dump PHY Page 0 data*/
+               memcpy(&sas_address, &sasPhyPg0->SASAddress, sizeof(u64));
+               dcsmisasprintk(ioc, printk(KERN_DEBUG "---- SAS PHY PAGE 0 ------------\n"));
+               dcsmisasprintk(ioc, printk(KERN_DEBUG "Handle=0x%X\n",
+                   le16_to_cpu(sasPhyPg0->AttachedDevHandle)));
+               dcsmisasprintk(ioc, printk(KERN_DEBUG "SAS Address=0x%llX\n",
+                   (unsigned long long)sas_address));
+               dcsmisasprintk(ioc, printk(KERN_DEBUG "Attached PHY Identifier=0x%X\n",
+                   sasPhyPg0->AttachedPhyIdentifier));
+               dcsmisasprintk(ioc, printk(KERN_DEBUG "Attached Device Info=0x%X\n",
+                   le32_to_cpu(sasPhyPg0->AttachedDeviceInfo)));
+               dcsmisasprintk(ioc, printk(KERN_DEBUG "Programmed Link Rate=0x%X\n",
+                   sasPhyPg0->ProgrammedLinkRate));
+               dcsmisasprintk(ioc, printk(KERN_DEBUG "Hardware Link Rate=0x%X\n",
+                   sasPhyPg0->HwLinkRate));
+               dcsmisasprintk(ioc, printk(KERN_DEBUG "Change Count=0x%X\n",
+                   sasPhyPg0->ChangeCount));
+               dcsmisasprintk(ioc, printk(KERN_DEBUG "PHY Info=0x%X\n",
+                   le32_to_cpu(sasPhyPg0->PhyInfo)));
+               dcsmisasprintk(ioc, printk(KERN_DEBUG "\n"));
+/* EDM : debug data */
+
+               /* save the data */
+
+               /* Set Max hardware link rate.
+                * This value is hard coded
+                * because the HW link rate
+                * is currently being
+                * overwritten in FW.
+                */
+
+               /* Set Max hardware link rate. */
+               switch (sasPhyPg0->HwLinkRate &
+                   MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
+
+               case MPI_SAS_PHY0_HWRATE_MAX_RATE_1_5:
+                       karg->Information.Phy[ii].bMaximumLinkRate =
+                           CSMI_SAS_LINK_RATE_1_5_GBPS;
+                       break;
+
+               case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
+                       karg->Information.Phy[ii].bMaximumLinkRate =
+                           CSMI_SAS_LINK_RATE_3_0_GBPS;
+                       break;
+               default:
+                       break;
+               }
+
+               /* Set Max programmed link rate. */
+               switch (sasPhyPg0->ProgrammedLinkRate &
+                   MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
+
+               case MPI_SAS_PHY0_PRATE_MAX_RATE_1_5:
+                       karg->Information.Phy[ii].bMaximumLinkRate |=
+                           (CSMI_SAS_PROGRAMMED_LINK_RATE_1_5_GBPS << 4);
+                       break;
+
+               case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
+                       karg->Information.Phy[ii].bMaximumLinkRate |=
+                           (CSMI_SAS_PROGRAMMED_LINK_RATE_3_0_GBPS << 4);
+                       break;
+               default:
+                       break;
+               }
+
+               /* Set Min hardware link rate. */
+               switch (sasPhyPg0->HwLinkRate &
+                   MPI_SAS_PHY0_HWRATE_MIN_RATE_MASK) {
+
+               case MPI_SAS_PHY0_HWRATE_MIN_RATE_1_5:
+                       karg->Information.Phy[ii].bMinimumLinkRate =
+                           CSMI_SAS_LINK_RATE_1_5_GBPS;
+                       break;
+
+               case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
+                       karg->Information.Phy[ii].bMinimumLinkRate =
+                           CSMI_SAS_LINK_RATE_3_0_GBPS;
+                       break;
+               default:
+                       break;
+               }
+
+               /* Set Min programmed link rate. */
+               switch (sasPhyPg0->ProgrammedLinkRate &
+                   MPI_SAS_PHY0_PRATE_MIN_RATE_MASK) {
+
+               case MPI_SAS_PHY0_PRATE_MIN_RATE_1_5:
+                       karg->Information.Phy[ii].bMinimumLinkRate |=
+                           (CSMI_SAS_PROGRAMMED_LINK_RATE_1_5_GBPS << 4);
+                       break;
+
+               case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
+                       karg->Information.Phy[ii].bMinimumLinkRate |=
+                           (CSMI_SAS_PROGRAMMED_LINK_RATE_3_0_GBPS << 4);
+                       break;
+               default:
+                       break;
+               }
+
+               karg->Information.Phy[ii].bPhyChangeCount = sasPhyPg0->ChangeCount;
+               if( sasPhyPg0->PhyInfo & MPI_SAS_PHY0_PHYINFO_VIRTUAL_PHY )
+                       karg->Information.Phy[ii].bPhyFeatures = CSMI_SAS_PHY_VIRTUAL_SMP;
+
+               /* Fill in Attached Device
+                * Initiator Port Protocol.
+                * Bits 6:3
+                * More than one bit can be set.
+                */
+               protocol = le32_to_cpu(sasPhyPg0->AttachedDeviceInfo) & 0x78;
+               karg->Information.Phy[ii].Attached.bInitiatorPortProtocol = 0;
+               if (protocol & MPI_SAS_DEVICE_INFO_SSP_INITIATOR)
+                     karg->Information.Phy[ii].Attached.bInitiatorPortProtocol =
+                           CSMI_SAS_PROTOCOL_SSP;
+               if (protocol & MPI_SAS_DEVICE_INFO_STP_INITIATOR)
+                    karg->Information.Phy[ii].Attached.bInitiatorPortProtocol |=
+                           CSMI_SAS_PROTOCOL_STP;
+               if (protocol & MPI_SAS_DEVICE_INFO_SMP_INITIATOR)
+                    karg->Information.Phy[ii].Attached.bInitiatorPortProtocol |=
+                           CSMI_SAS_PROTOCOL_SMP;
+               if (protocol & MPI_SAS_DEVICE_INFO_SATA_HOST)
+                    karg->Information.Phy[ii].Attached.bInitiatorPortProtocol |=
+                           CSMI_SAS_PROTOCOL_SATA;
+
+               /* Fill in Phy Target Port
+                * Protocol. Bits 10:7
+                * More than one bit can be set.
+                */
+               protocol = le32_to_cpu(sasPhyPg0->AttachedDeviceInfo) & 0x780;
+               karg->Information.Phy[ii].Attached.bTargetPortProtocol = 0;
+               if (protocol & MPI_SAS_DEVICE_INFO_SSP_TARGET)
+                       karg->Information.Phy[ii].Attached.bTargetPortProtocol |=
+                           CSMI_SAS_PROTOCOL_SSP;
+               if (protocol & MPI_SAS_DEVICE_INFO_STP_TARGET)
+                       karg->Information.Phy[ii].Attached.bTargetPortProtocol |=
+                           CSMI_SAS_PROTOCOL_STP;
+               if (protocol & MPI_SAS_DEVICE_INFO_SMP_TARGET)
+                       karg->Information.Phy[ii].Attached.bTargetPortProtocol |=
+                           CSMI_SAS_PROTOCOL_SMP;
+               if (protocol & MPI_SAS_DEVICE_INFO_SATA_DEVICE)
+                       karg->Information.Phy[ii].Attached.bTargetPortProtocol |=
+                           CSMI_SAS_PROTOCOL_SATA;
+
+
+               /* Fill in Attached device type */
+               switch (le32_to_cpu(sasPhyPg0->AttachedDeviceInfo) &
+                   MPI_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) {
+
+               case MPI_SAS_DEVICE_INFO_NO_DEVICE:
+                       karg->Information.Phy[ii].Attached.bDeviceType =
+                           CSMI_SAS_NO_DEVICE_ATTACHED;
+                       break;
+
+               case MPI_SAS_DEVICE_INFO_END_DEVICE:
+                       karg->Information.Phy[ii].Attached.bDeviceType =
+                           CSMI_SAS_END_DEVICE;
+                       break;
+
+               case MPI_SAS_DEVICE_INFO_EDGE_EXPANDER:
+                       karg->Information.Phy[ii].Attached.bDeviceType =
+                           CSMI_SAS_EDGE_EXPANDER_DEVICE;
+                       break;
+
+               case MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER:
+                       karg->Information.Phy[ii].Attached.bDeviceType =
+                           CSMI_SAS_FANOUT_EXPANDER_DEVICE;
+                       break;
+               }
+
+               /* Identify Info. */
+               switch (le32_to_cpu(sasIoUnitPg0->PhyData[ii].ControllerPhyDeviceInfo) &
+                   MPI_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) {
+
+               case MPI_SAS_DEVICE_INFO_NO_DEVICE:
+                       karg->Information.Phy[ii].Identify.bDeviceType =
+                           CSMI_SAS_NO_DEVICE_ATTACHED;
+                       break;
+
+               case MPI_SAS_DEVICE_INFO_END_DEVICE:
+                       karg->Information.Phy[ii].Identify.bDeviceType =
+                           CSMI_SAS_END_DEVICE;
+                       break;
+
+               case MPI_SAS_DEVICE_INFO_EDGE_EXPANDER:
+                       karg->Information.Phy[ii].Identify.bDeviceType =
+                           CSMI_SAS_EDGE_EXPANDER_DEVICE;
+                       break;
+
+               case MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER:
+                       karg->Information.Phy[ii].Identify.bDeviceType =
+                           CSMI_SAS_FANOUT_EXPANDER_DEVICE;
+                       break;
+               }
+
+               /* Fill in Phy Initiator Port Protocol. Bits 6:3
+                * More than one bit can be set, fall through cases.
+                */
+               protocol = le32_to_cpu(
+                   sasIoUnitPg0->PhyData[ii].ControllerPhyDeviceInfo) & 0x78;
+               karg->Information.Phy[ii].Identify.bInitiatorPortProtocol = 0;
+               if( protocol & MPI_SAS_DEVICE_INFO_SSP_INITIATOR )
+                    karg->Information.Phy[ii].Identify.bInitiatorPortProtocol |=
+                           CSMI_SAS_PROTOCOL_SSP;
+               if( protocol & MPI_SAS_DEVICE_INFO_STP_INITIATOR )
+                    karg->Information.Phy[ii].Identify.bInitiatorPortProtocol |=
+                           CSMI_SAS_PROTOCOL_STP;
+               if( protocol & MPI_SAS_DEVICE_INFO_SMP_INITIATOR )
+                    karg->Information.Phy[ii].Identify.bInitiatorPortProtocol |=
+                           CSMI_SAS_PROTOCOL_SMP;
+               if( protocol & MPI_SAS_DEVICE_INFO_SATA_HOST )
+                    karg->Information.Phy[ii].Identify.bInitiatorPortProtocol |=
+                           CSMI_SAS_PROTOCOL_SATA;
+
+               /* Fill in Phy Target Port Protocol. Bits 10:7
+                * More than one bit can be set, fall through cases.
+                */
+               protocol = le32_to_cpu(
+                   sasIoUnitPg0->PhyData[ii].ControllerPhyDeviceInfo) & 0x780;
+               karg->Information.Phy[ii].Identify.bTargetPortProtocol = 0;
+               if( protocol & MPI_SAS_DEVICE_INFO_SSP_TARGET )
+                       karg->Information.Phy[ii].Identify.bTargetPortProtocol |=
+                           CSMI_SAS_PROTOCOL_SSP;
+               if( protocol & MPI_SAS_DEVICE_INFO_STP_TARGET )
+                       karg->Information.Phy[ii].Identify.bTargetPortProtocol |=
+                           CSMI_SAS_PROTOCOL_STP;
+               if( protocol & MPI_SAS_DEVICE_INFO_SMP_TARGET )
+                       karg->Information.Phy[ii].Identify.bTargetPortProtocol |=
+                           CSMI_SAS_PROTOCOL_SMP;
+               if( protocol & MPI_SAS_DEVICE_INFO_SATA_DEVICE )
+                       karg->Information.Phy[ii].Identify.bTargetPortProtocol |=
+                           CSMI_SAS_PROTOCOL_SATA;
+
+               /* Setup SAS Address for the attached device */
+               if (sasPhyPg0->AttachedDevHandle) {
+                       sas_address = reverse_byte_order64(sas_address);
+                       memcpy(karg->Information.Phy[ii].Attached.bSASAddress,
+                           &sas_address, sizeof(u64));
+                       karg->Information.Phy[ii].Attached.bPhyIdentifier =
+                           sasPhyPg0->AttachedPhyIdentifier;
+               }
+
+               /* Setup SAS Address for the parent device */
+               csmisas_sas_device_pg0(ioc, &device_info,
+                   (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
+                   MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
+                   sasIoUnitPg0->PhyData[ii].ControllerDevHandle);
+               sas_address = reverse_byte_order64(device_info.sas_address);
+               memcpy(karg->Information.Phy[ii].Identify.bSASAddress,
+                   &sas_address, sizeof(u64));
+               karg->Information.Phy[ii].Identify.bPhyIdentifier = ii;
+
+               pci_free_consistent(ioc->pcidev, sasPhyPg0_data_sz,
+                   (u8 *) sasPhyPg0, sasPhyPg0_dma);
+       }
+
+sas_get_phy_info_exit:
+
+       if (sasIoUnitPg0)
+               pci_free_consistent(ioc->pcidev, sasIoUnitPg0_data_sz,
+                   (u8 *) sasIoUnitPg0, sasIoUnitPg0_dma);
+
+       /* Copy the data from kernel memory to user memory
+        */
+       if (copy_to_user(uarg, karg,
+           sizeof(CSMI_SAS_PHY_INFO_BUFFER))) {
+               printk(KERN_ERR "%s@%d::%s - "
+                   "Unable to write out csmisas_get_phy_info_buffer @ %p\n",
+                   __FILE__, __LINE__, __FUNCTION__, uarg);
+               free_pages((unsigned long)karg, memory_pages);
+               return -EFAULT;
+       }
+
+       free_pages((unsigned long)karg, memory_pages);
+       dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__));
+       return 0;
+}
+
+/**
+ * Prototype Routine for the CSMI SAS Set PHY Info command.
+ *
+ * Outputs:    None.
+ * Return:     0 if successful
+ *             -EFAULT if data unavailable
+ *             -ENODEV if no such device/adapter
+ **/
+static int
+csmisas_set_phy_info(unsigned long arg)
+{
+       CSMI_SAS_SET_PHY_INFO_BUFFER __user *uarg = (void __user *) arg;
+       CSMI_SAS_SET_PHY_INFO_BUFFER     karg;
+       MPT_ADAPTER                     *ioc = NULL;
+       int                             iocnum;
+
+       if (copy_from_user(&karg, uarg, sizeof(CSMI_SAS_SET_PHY_INFO_BUFFER))) {
+               printk(KERN_ERR "%s@%d::%s() - "
+                   "Unable to read in csmi_sas_set_phy_info struct @ %p\n",
+                   __FILE__, __LINE__, __FUNCTION__, uarg);
+               return -EFAULT;
+       }
+
+       if (((iocnum = mpt_verify_adapter(karg.IoctlHeader.IOControllerNumber,
+           &ioc)) < 0) || (ioc == NULL)) {
+               printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n",
+                   __FILE__, __FUNCTION__, __LINE__, iocnum);
+               return -ENODEV;
+       }
+
+       if (!csmisas_is_this_sas_cntr(ioc)) {
+               printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n",
+                   __FILE__, __FUNCTION__, __LINE__, iocnum);
+               return -ENODEV;
+       }
+
+       dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__));
+
+/* TODO - implement IOCTL here */
+       karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_BAD_CNTL_CODE;
+       dcsmisasprintk(ioc, printk(KERN_DEBUG ": not implemented\n"));
+
+// cim_set_phy_info_exit:
+
+       /* Copy the data from kernel memory to user memory
+        */
+       if (copy_to_user(uarg, &karg,
+                               sizeof(CSMI_SAS_SET_PHY_INFO_BUFFER))) {
+               printk(KERN_ERR "%s@%d::%s() - "
+                       "Unable to write out csmi_sas_set_phy_info @ %p\n",
+                               __FILE__, __LINE__, __FUNCTION__, uarg);
+               return -EFAULT;
+       }
+
+       dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__));
+       return 0;
+
+}
+
+/**
+ * Prototype Routine for the CSMI Sas Get SCSI Address command.
+ *
+ * Outputs:    None.
+ * Return:     0 if successful
+ *             -EFAULT if data unavailable
+ *             -ENODEV if no such device/adapter
+ **/
+static int
+csmisas_get_scsi_address(unsigned long arg)
+{
+       CSMI_SAS_GET_SCSI_ADDRESS_BUFFER __user *uarg = (void __user *) arg;
+       CSMI_SAS_GET_SCSI_ADDRESS_BUFFER         karg;
+       MPT_ADAPTER             *ioc = NULL;
+       int                     iocnum;
+       u64                     sas_address;
+       struct sas_device_info  *sas_info;
+
+       if (copy_from_user(&karg, uarg,
+           sizeof(CSMI_SAS_GET_SCSI_ADDRESS_BUFFER))) {
+               printk(KERN_ERR "%s@%d::%s() - "
+                   "Unable to read in csmi_sas_get_scsi_address struct @ %p\n",
+                   __FILE__, __LINE__, __FUNCTION__, uarg);
+               return -EFAULT;
+       }
+
+       if (((iocnum = mpt_verify_adapter(karg.IoctlHeader.IOControllerNumber,
+           &ioc)) < 0) || (ioc == NULL)) {
+               printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n",
+                   __FILE__, __FUNCTION__, __LINE__, iocnum);
+               return -ENODEV;
+       }
+
+       if (!csmisas_is_this_sas_cntr(ioc)) {
+               printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n",
+                   __FILE__, __FUNCTION__, __LINE__, iocnum);
+               return -ENODEV;
+       }
+
+       dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__));
+
+       /* reverse byte order the sas address */
+       memcpy(&sas_address, karg.bSASAddress, sizeof(u64));
+       sas_address = reverse_byte_order64(sas_address);
+
+       /* Search the list for the matching SAS address. */
+       karg.IoctlHeader.ReturnCode = CSMI_SAS_NO_SCSI_ADDRESS;
+       karg.bPathId = 0;
+       karg.bTargetId = 0;
+       karg.bLun = 0;
+
+       sas_info = csmisas_get_device_component_by_sas_addr(ioc, sas_address);
+       if (!sas_info || sas_info->is_cached || sas_info->is_logical_volume)
+               goto csmisas_get_scsi_address_exit;
+
+       karg.bPathId = sas_info->os.channel;
+       karg.bTargetId = sas_info->os.id;
+       karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS;
+
+ csmisas_get_scsi_address_exit:
+
+       /* Copy the data from kernel memory to user memory
+        */
+       if (copy_to_user(uarg, &karg,
+           sizeof(CSMI_SAS_GET_SCSI_ADDRESS_BUFFER))) {
+               printk(KERN_ERR "%s@%d::%s() - "
+                   "Unable to write out csmi_sas_get_scsi_address @ %p\n",
+                   __FILE__, __LINE__, __FUNCTION__, uarg);
+               return -EFAULT;
+       }
+
+       dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__));
+       return 0;
+}
+
+/**
+ * Prototype Routine for the CSMI Sas Get SCSI Address command.
+ *
+ * Outputs:    None.
+ * Return:     0 if successful
+ *             -EFAULT if data unavailable
+ *             -ENODEV if no such device/adapter
+ **/
+static int
+csmisas_get_sata_signature(unsigned long arg)
+{
+       CSMI_SAS_SATA_SIGNATURE_BUFFER  __user *uarg = (void __user *) arg;
+       CSMI_SAS_SATA_SIGNATURE_BUFFER   karg;
+       MPT_ADAPTER                     *ioc = NULL;
+       int                             iocnum;
+       int                             rc, jj;
+       ConfigExtendedPageHeader_t      hdr;
+       CONFIGPARMS                     cfg;
+       SasPhyPage0_t                   *sasPhyPg0;
+       dma_addr_t                      sasPhyPg0_dma;
+       int                             sasPhyPg0_data_sz;
+       SasDevicePage1_t                *sasDevicePg1;
+       dma_addr_t                      sasDevicePg1_dma;
+       int                             sasDevicePg1_data_sz;
+       u8                              phyId;
+       u64                             sas_address;
+
+       sasPhyPg0=NULL;
+       sasPhyPg0_data_sz=0;
+       sasDevicePg1=NULL;
+       sasDevicePg1_data_sz=0;
+
+       if (copy_from_user(&karg, uarg,
+            sizeof(CSMI_SAS_SATA_SIGNATURE_BUFFER))) {
+               printk(KERN_ERR "%s@%d::%s() - "
+                   "Unable to read in csmi_sas_sata_signature struct @ %p\n",
+                   __FILE__, __LINE__, __FUNCTION__, uarg);
+               return -EFAULT;
+       }
+
+       if (((iocnum = mpt_verify_adapter(karg.IoctlHeader.IOControllerNumber,
+           &ioc)) < 0) || (ioc == NULL)) {
+               printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n",
+                    __FILE__, __FUNCTION__, __LINE__, iocnum);
+               return -ENODEV;
+       }
+
+       if (!csmisas_is_this_sas_cntr(ioc)) {
+               printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n",
+                   __FILE__, __FUNCTION__, __LINE__, iocnum);
+               return -ENODEV;
+       }
+
+       dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__));
+       phyId = karg.Signature.bPhyIdentifier;
+       if (phyId >= ioc->num_ports) {
+               karg.IoctlHeader.ReturnCode = CSMI_SAS_PHY_DOES_NOT_EXIST;
+               dcsmisasprintk(ioc, printk(KERN_WARNING ": phyId >= ioc->num_ports\n"));
+               goto cim_sata_signature_exit;
+       }
+
+       /* Default to success.*/
+       karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS;
+
+       /* Issue a config request to get the devHandle of the attached device
+        */
+
+       /* Issue a config request to get phy information. */
+       hdr.PageVersion = MPI_SASPHY0_PAGEVERSION;
+       hdr.ExtPageLength = 0;
+       hdr.PageNumber = 0;
+       hdr.Reserved1 = 0;
+       hdr.Reserved2 = 0;
+       hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
+       hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
+
+       cfg.cfghdr.ehdr = &hdr;
+       cfg.physAddr = -1;
+       cfg.pageAddr = phyId;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+       cfg.dir = 0;    /* read */
+       cfg.timeout = MPT_IOCTL_DEFAULT_TIMEOUT;
+
+       if ((rc = mpt_config(ioc, &cfg)) != 0) {
+               /* Don't check if this failed.  Already in a
+                * failure case.
+                */
+               dcsmisasprintk(ioc, printk(KERN_ERR
+                   ": FAILED: MPI_SASPHY0_PAGEVERSION: HEADER\n"));
+               dcsmisasprintk(ioc, printk(KERN_ERR ": rc=%x\n",rc));
+               karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+               goto cim_sata_signature_exit;
+       }
+
+       if (hdr.ExtPageLength == 0) {
+               /* Don't check if this failed.  Already in a
+                * failure case.
+                */
+               dcsmisasprintk(ioc, printk(KERN_ERR ": hdr.ExtPageLength == 0\n"));
+               karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+               goto cim_sata_signature_exit;
+       }
+
+
+       sasPhyPg0_data_sz = hdr.ExtPageLength * 4;
+       rc = -ENOMEM;
+
+       sasPhyPg0 = (SasPhyPage0_t *) pci_alloc_consistent(ioc->pcidev,
+           sasPhyPg0_data_sz, &sasPhyPg0_dma);
+
+       if (! sasPhyPg0) {
+               dcsmisasprintk(ioc, printk(KERN_ERR ": pci_alloc_consistent: FAILED\n"));
+               karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+               goto cim_sata_signature_exit;
+       }
+
+       memset((u8 *)sasPhyPg0, 0, sasPhyPg0_data_sz);
+       cfg.physAddr = sasPhyPg0_dma;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+
+       if ((rc = mpt_config(ioc, &cfg)) != 0) {
+               /* Don't check if this failed.  Already in a
+                * failure case.
+                */
+               dcsmisasprintk(ioc, printk(KERN_ERR
+                   ": FAILED: MPI_SASPHY0_PAGEVERSION: PAGE\n"));
+               dcsmisasprintk(ioc, printk(KERN_ERR ": rc=%x\n",rc));
+               karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+               goto cim_sata_signature_exit;
+       }
+
+       /* Make sure a SATA device is attached. */
+       if ((le32_to_cpu(sasPhyPg0->AttachedDeviceInfo) &
+           MPI_SAS_DEVICE_INFO_SATA_DEVICE) == 0) {
+               dcsmisasprintk(ioc, printk(KERN_WARNING ": NOT A SATA DEVICE\n"));
+               karg.IoctlHeader.ReturnCode = CSMI_SAS_NO_SATA_DEVICE;
+               goto cim_sata_signature_exit;
+       }
+
+       /* Get device page 1 for FIS  signature. */
+       hdr.PageVersion = MPI_SASDEVICE1_PAGEVERSION;
+       hdr.ExtPageLength = 0;
+       hdr.PageNumber = 1 /* page number 1 */;
+       hdr.Reserved1 = 0;
+       hdr.Reserved2 = 0;
+       hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
+       hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE;
+
+       cfg.cfghdr.ehdr = &hdr;
+       cfg.physAddr = -1;
+
+       cfg.pageAddr = ((MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
+           MPI_SAS_DEVICE_PGAD_FORM_SHIFT) |
+           le16_to_cpu(sasPhyPg0->AttachedDevHandle));
+       cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+       cfg.dir = 0;    /* read */
+       cfg.timeout = MPT_IOCTL_DEFAULT_TIMEOUT;
+
+       if ((rc = mpt_config(ioc, &cfg)) != 0) {
+               dcsmisasprintk(ioc, printk(KERN_ERR
+                   ": FAILED: MPI_SASDEVICE1_PAGEVERSION: HEADER\n"));
+               dcsmisasprintk(ioc, printk(KERN_ERR ": rc=%x\n",rc));
+               karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+               goto cim_sata_signature_exit;
+       }
+
+       if (hdr.ExtPageLength == 0) {
+               dcsmisasprintk(ioc, printk(KERN_ERR ": hdr.ExtPageLength == 0\n"));
+               karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+               goto cim_sata_signature_exit;
+       }
+
+       sasDevicePg1_data_sz = hdr.ExtPageLength * 4;
+       rc = -ENOMEM;
+
+       sasDevicePg1 = (SasDevicePage1_t *) pci_alloc_consistent
+           (ioc->pcidev, sasDevicePg1_data_sz, &sasDevicePg1_dma);
+
+       if (! sasDevicePg1) {
+               dcsmisasprintk(ioc, printk(KERN_ERR ": pci_alloc_consistent: FAILED\n"));
+               karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+               goto cim_sata_signature_exit;
+       }
+
+       memset((u8 *)sasDevicePg1, 0, sasDevicePg1_data_sz);
+       cfg.physAddr = sasDevicePg1_dma;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+
+       if ((rc = mpt_config(ioc, &cfg)) != 0) {
+               dcsmisasprintk(ioc, printk(KERN_ERR
+                   ": FAILED: MPI_SASDEVICE1_PAGEVERSION: PAGE\n"));
+               dcsmisasprintk(ioc, printk(KERN_ERR ": rc=%x\n",rc));
+               karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+               goto cim_sata_signature_exit;
+       }
+
+/* EDM : dump Device Page 1 data*/
+       dcsmisasprintk(ioc, printk(KERN_DEBUG "---- SAS DEVICE PAGE 1 ---------\n"));
+       dcsmisasprintk(ioc, printk(KERN_DEBUG "Handle=0x%x\n",sasDevicePg1->DevHandle));
+       memcpy(&sas_address, &sasDevicePg1->SASAddress, sizeof(u64));
+       dcsmisasprintk(ioc, printk(KERN_DEBUG "SAS Address=0x%llX\n",
+           (unsigned long long)sas_address));
+       dcsmisasprintk(ioc, printk(KERN_DEBUG "\n"));
+       dcsmisasprintk(ioc, printk(KERN_DEBUG "Target ID=0x%x\n",sasDevicePg1->TargetID));
+       dcsmisasprintk(ioc, printk(KERN_DEBUG "Bus=0x%x\n",sasDevicePg1->Bus));
+       dcsmisasprintk(ioc, printk(KERN_DEBUG "Initial Reg Device FIS="));
+       for(jj=0;jj<20;jj++)
+               dcsmisasprintk(ioc, printk("%02x ",
+               ((u8 *)&sasDevicePg1->InitialRegDeviceFIS)[jj]));
+       dcsmisasprintk(ioc, printk(KERN_DEBUG "\n\n"));
+/* EDM : debug data */
+
+       memcpy(karg.Signature.bSignatureFIS,
+               sasDevicePg1->InitialRegDeviceFIS,20);
+
+ cim_sata_signature_exit:
+
+       if (sasPhyPg0)
+               pci_free_consistent(ioc->pcidev, sasPhyPg0_data_sz,
+                   (u8 *) sasPhyPg0, sasPhyPg0_dma);
+
+       if (sasDevicePg1)
+               pci_free_consistent(ioc->pcidev, sasDevicePg1_data_sz,
+                   (u8 *) sasDevicePg1, sasDevicePg1_dma);
+
+       /* Copy the data from kernel memory to user memory
+        */
+       if (copy_to_user(uarg, &karg,
+           sizeof(CSMI_SAS_SATA_SIGNATURE_BUFFER))) {
+               printk(KERN_ERR "%s@%d::%s() - "
+                   "Unable to write out csmi_sas_sata_signature @ %p\n",
+                   __FILE__, __LINE__, __FUNCTION__, uarg);
+               return -EFAULT;
+       }
+
+       dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__));
+       return 0;
+}
+
+/**
+ * Prototype Routine for the CSMI Sas Get SCSI Address command.
+ *
+ * Outputs:    None.
+ * Return:     0 if successful
+ *             -EFAULT if data unavailable
+ *             -ENODEV if no such device/adapter
+ **/
+static int
+csmisas_get_device_address(unsigned long arg)
+{
+       CSMI_SAS_GET_DEVICE_ADDRESS_BUFFER __user *uarg = (void __user *) arg;
+       CSMI_SAS_GET_DEVICE_ADDRESS_BUFFER       karg;
+       MPT_ADAPTER             *ioc = NULL;
+       int                     iocnum;
+       struct sas_device_info  *sas_info;
+       u64                     sas_address;
+
+       if (copy_from_user(&karg, uarg,
+           sizeof(CSMI_SAS_GET_DEVICE_ADDRESS_BUFFER))) {
+               printk(KERN_ERR "%s@%d::%s() - "
+          "Unable to read in csmi_sas_get_device_address_buffer struct @ %p\n",
+                   __FILE__, __LINE__, __FUNCTION__, uarg);
+               return -EFAULT;
+       }
+
+       if (((iocnum = mpt_verify_adapter(karg.IoctlHeader.IOControllerNumber,
+           &ioc)) < 0) || (ioc == NULL)) {
+               printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n",
+                   __FILE__, __FUNCTION__, __LINE__, iocnum);
+               return -ENODEV;
+       }
+
+       if (!csmisas_is_this_sas_cntr(ioc)) {
+               printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n",
+                   __FILE__, __FUNCTION__, __LINE__, iocnum);
+               return -ENODEV;
+       }
+
+       dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__));
+
+       karg.IoctlHeader.ReturnCode = CSMI_SAS_NO_DEVICE_ADDRESS;
+       memset(karg.bSASAddress, 0, sizeof(u64));
+       memset(karg.bSASLun, 0, sizeof(karg.bSASLun));
+
+       /* Search the list for the matching SAS address. */
+       sas_info = csmisas_get_device_component_by_os(ioc, karg.bPathId,
+           karg.bTargetId);
+       if (!sas_info || sas_info->is_cached || sas_info->is_logical_volume)
+               goto csmisas_get_device_address_exit;
+
+       sas_address = reverse_byte_order64(sas_info->sas_address);
+       memcpy(karg.bSASAddress, &sas_address, sizeof(u64));
+       karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS;
+
+ csmisas_get_device_address_exit:
+
+       /* Copy the data from kernel memory to user memory
+        */
+       if (copy_to_user(uarg, &karg,
+           sizeof(CSMI_SAS_GET_DEVICE_ADDRESS_BUFFER))) {
+               printk(KERN_ERR "%s@%d::%s() - "
+               "Unable to write out csmi_sas_get_device_address_buffer @ %p\n",
+                   __FILE__, __LINE__, __FUNCTION__, uarg);
+               return -EFAULT;
+       }
+
+       dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__));
+       return 0;
+}
+
+/**
+ * Prototype Routine for the CSMI Sas Get Link Errors command.
+ *
+ * Outputs:    None.
+ * Return:     0 if successful
+ *             -EFAULT if data unavailable
+ *             -ENODEV if no such device/adapter
+ **/
+static int
+csmisas_get_link_errors(unsigned long arg)
+{
+       CSMI_SAS_LINK_ERRORS_BUFFER __user *uarg = (void __user *) arg;
+       CSMI_SAS_LINK_ERRORS_BUFFER      karg;
+       MPT_ADAPTER                     *ioc = NULL;
+       MPT_FRAME_HDR                   *mf = NULL;
+       MPIHeader_t                     *mpi_hdr;
+       int                             iocnum;
+       int                             rc;
+       ConfigExtendedPageHeader_t      hdr;
+       CONFIGPARMS                     cfg;
+       SasPhyPage1_t                   *sasPhyPage1;
+       dma_addr_t                      sasPhyPage1_dma;
+       int                             sasPhyPage1_data_sz;
+       SasIoUnitControlRequest_t       *sasIoUnitCntrReq;
+       SasIoUnitControlReply_t         *sasIoUnitCntrReply;
+       u8                              phyId;
+       u16                             ioc_status;
+       u32                             MsgContext;
+
+       sasPhyPage1=NULL;
+       sasPhyPage1_data_sz=0;
+
+       if (copy_from_user(&karg, uarg,
+            sizeof(CSMI_SAS_LINK_ERRORS_BUFFER))) {
+               printk(KERN_ERR "%s@%d::%s() - "
+                   "Unable to read in csmisas_get_link_errors struct @ %p\n",
+                   __FILE__, __LINE__, __FUNCTION__, uarg);
+               return -EFAULT;
+       }
+
+       if (((iocnum = mpt_verify_adapter(karg.IoctlHeader.IOControllerNumber,
+           &ioc)) < 0) || (ioc == NULL)) {
+               printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n",
+                    __FILE__, __FUNCTION__, __LINE__, iocnum);
+               return -ENODEV;
+       }
+
+       if (!csmisas_is_this_sas_cntr(ioc)) {
+               printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n",
+                   __FILE__, __FUNCTION__, __LINE__, iocnum);
+               return -ENODEV;
+       }
+
+       dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__));
+       phyId = karg.Information.bPhyIdentifier;
+       if (phyId >= ioc->num_ports) {
+               karg.IoctlHeader.ReturnCode = CSMI_SAS_PHY_DOES_NOT_EXIST;
+               dcsmisasprintk(ioc, printk(KERN_WARNING ": phyId >= ioc->num_ports\n"));
+               goto cim_get_link_errors_exit;
+       }
+
+       /* Default to success.*/
+       karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS;
+
+       /* Issue a config request to get the devHandle of the attached device
+        */
+
+       /* Issue a config request to get phy information. */
+       hdr.PageVersion = MPI_SASPHY1_PAGEVERSION;
+       hdr.ExtPageLength = 0;
+       hdr.PageNumber = 1 /* page number 1*/;
+       hdr.Reserved1 = 0;
+       hdr.Reserved2 = 0;
+       hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
+       hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
+
+       cfg.cfghdr.ehdr = &hdr;
+       cfg.physAddr = -1;
+       cfg.pageAddr = phyId;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+       cfg.dir = 0;    /* read */
+       cfg.timeout = MPT_IOCTL_DEFAULT_TIMEOUT;
+
+       if ((rc = mpt_config(ioc, &cfg)) != 0) {
+               /* Don't check if this failed.  Already in a
+                * failure case.
+                */
+               dcsmisasprintk(ioc, printk(KERN_ERR
+                   ": FAILED: MPI_SASPHY1_PAGEVERSION: HEADER\n"));
+               dcsmisasprintk(ioc, printk(KERN_ERR ": rc=%x\n",rc));
+               karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+               goto cim_get_link_errors_exit;
+       }
+
+       if (hdr.ExtPageLength == 0) {
+               /* Don't check if this failed.  Already in a
+                * failure case.
+                */
+               dcsmisasprintk(ioc, printk(KERN_ERR ": hdr.ExtPageLength == 0\n"));
+               karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+               goto cim_get_link_errors_exit;
+       }
+
+
+       sasPhyPage1_data_sz = hdr.ExtPageLength * 4;
+       rc = -ENOMEM;
+
+       sasPhyPage1 = (SasPhyPage1_t *) pci_alloc_consistent(ioc->pcidev,
+           sasPhyPage1_data_sz, &sasPhyPage1_dma);
+
+       if (! sasPhyPage1) {
+               dcsmisasprintk(ioc, printk(KERN_ERR ": pci_alloc_consistent: FAILED\n"));
+               karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+               goto cim_get_link_errors_exit;
+       }
+
+       memset((u8 *)sasPhyPage1, 0, sasPhyPage1_data_sz);
+       cfg.physAddr = sasPhyPage1_dma;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+
+       if ((rc = mpt_config(ioc, &cfg)) != 0) {
+               /* Don't check if this failed.  Already in a
+                * failure case.
+                */
+               dcsmisasprintk(ioc, printk(KERN_ERR ": FAILED: MPI_SASPHY1_PAGEVERSION: PAGE\n"));
+               dcsmisasprintk(ioc, printk(KERN_ERR ": rc=%x\n",rc));
+               karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+               goto cim_get_link_errors_exit;
+       }
+
+/* EDM : dump PHY Page 1 data*/
+       dcsmisasprintk(ioc, printk(KERN_DEBUG "---- SAS PHY PAGE 1 ------------\n"));
+       dcsmisasprintk(ioc, printk(KERN_DEBUG "Invalid Dword Count=0x%x\n",
+           sasPhyPage1->InvalidDwordCount));
+       dcsmisasprintk(ioc, printk(KERN_DEBUG "Running Disparity Error Count=0x%x\n",
+           sasPhyPage1->RunningDisparityErrorCount));
+       dcsmisasprintk(ioc, printk(KERN_DEBUG "Loss Dword Synch Count=0x%x\n",
+           sasPhyPage1->LossDwordSynchCount));
+       dcsmisasprintk(ioc, printk(KERN_DEBUG "PHY Reset Problem Count=0x%x\n",
+           sasPhyPage1->PhyResetProblemCount));
+       dcsmisasprintk(ioc, printk(KERN_DEBUG "\n\n"));
+/* EDM : debug data */
+
+       karg.Information.uInvalidDwordCount =
+               le32_to_cpu(sasPhyPage1->InvalidDwordCount);
+       karg.Information.uRunningDisparityErrorCount =
+               le32_to_cpu(sasPhyPage1->RunningDisparityErrorCount);
+       karg.Information.uLossOfDwordSyncCount =
+               le32_to_cpu(sasPhyPage1->LossDwordSynchCount);
+       karg.Information.uPhyResetProblemCount =
+               le32_to_cpu(sasPhyPage1->PhyResetProblemCount);
+
+       if (karg.Information.bResetCounts ==
+           CSMI_SAS_LINK_ERROR_DONT_RESET_COUNTS ) {
+               goto cim_get_link_errors_exit;
+       }
+
+       /* Clear Error log
+        *
+        * Issue IOUNIT Control Reqeust Message
+        */
+
+       /* Get a MF for this command.
+        */
+       if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL) {
+               dcsmisasprintk(ioc, printk(KERN_ERR ": no msg frames!\n"));
+               karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+               goto cim_get_link_errors_exit;
+        }
+
+       mpi_hdr = (MPIHeader_t *) mf;
+       MsgContext = mpi_hdr->MsgContext;
+       sasIoUnitCntrReq = (SasIoUnitControlRequest_t *)mf;
+       memset(sasIoUnitCntrReq,0,sizeof(SasIoUnitControlRequest_t));
+       sasIoUnitCntrReq->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
+       sasIoUnitCntrReq->MsgContext = MsgContext;
+       sasIoUnitCntrReq->PhyNum = phyId;
+       sasIoUnitCntrReq->Operation = MPI_SAS_OP_PHY_CLEAR_ERROR_LOG;
+
+       if (csmisas_send_command_wait(ioc, mf, karg.IoctlHeader.Timeout) != 0) {
+               karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+               goto cim_get_link_errors_exit;
+       }
+
+       /* process the completed Reply Message Frame */
+       if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID) {
+
+               sasIoUnitCntrReply =
+                   (SasIoUnitControlReply_t *)ioc->ioctl_cmds.reply;
+               ioc_status = le16_to_cpu(sasIoUnitCntrReply->IOCStatus)
+                   & MPI_IOCSTATUS_MASK;
+
+               if (ioc_status != MPI_IOCSTATUS_SUCCESS) {
+                       dcsmisasprintk(ioc, printk(KERN_DEBUG ": SAS IO Unit Control: "));
+                       dcsmisasprintk(ioc, printk("IOCStatus=0x%X IOCLogInfo=0x%X\n",
+                           sasIoUnitCntrReply->IOCStatus,
+                           sasIoUnitCntrReply->IOCLogInfo));
+               }
+       }
+
+ cim_get_link_errors_exit:
+
+       if (sasPhyPage1)
+               pci_free_consistent(ioc->pcidev, sasPhyPage1_data_sz,
+                   (u8 *) sasPhyPage1, sasPhyPage1_dma);
+
+       /* Copy the data from kernel memory to user memory
+        */
+       if (copy_to_user(uarg, &karg,
+           sizeof(CSMI_SAS_LINK_ERRORS_BUFFER))) {
+               printk(KERN_ERR "%s@%d::%s() - "
+                   "Unable to write out csmisas_get_link_errors @ %p\n",
+                   __FILE__, __LINE__, __FUNCTION__, uarg);
+               return -EFAULT;
+       }
+
+       dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__));
+       return 0;
+
+}
+
+/**
+ * Prototype Routine for the CSMI SAS SMP Passthru command.
+ *
+ * Outputs:    None.
+ * Return:     0 if successful
+ *             -EFAULT if data unavailable
+ *             -ENODEV if no such device/adapter
+ **/
+static int
+csmisas_smp_passthru(unsigned long arg)
+{
+       CSMI_SAS_SMP_PASSTHRU_BUFFER __user *uarg = (void __user *) arg;
+       MPT_ADAPTER                     *ioc;
+       CSMI_SAS_SMP_PASSTHRU_BUFFER     *karg;
+       pSmpPassthroughRequest_t        smpReq;
+       pSmpPassthroughReply_t          smpReply;
+       MPT_FRAME_HDR                   *mf = NULL;
+       MPIHeader_t                     *mpi_hdr;
+       char                            *psge;
+       int                             iocnum, flagsLength;
+       void *                          request_data;
+       dma_addr_t                      request_data_dma;
+       u32                             request_data_sz;
+       void *                          response_data;
+       dma_addr_t                      response_data_dma;
+       u32                             response_data_sz;
+       u16                             ioc_status;
+       u64                             sas_address;
+       u32                             MsgContext;
+       int                             malloc_data_sz;
+       int                             memory_pages;
+
+       malloc_data_sz = sizeof(CSMI_SAS_SMP_PASSTHRU_BUFFER);
+       memory_pages = get_order(malloc_data_sz);
+       karg = (CSMI_SAS_SMP_PASSTHRU_BUFFER *)__get_free_pages(
+               GFP_KERNEL, memory_pages);
+       if (!karg){
+               printk(KERN_ERR "%s@%d::%s() - "
+                       "Unable to malloc CSMI_SAS_SMP_PASSTHRU_BUFFER "
+                       "malloc_data_sz=%d memory_pages=%d\n",
+                       __FILE__, __LINE__, __FUNCTION__,
+                       malloc_data_sz, memory_pages);
+               return -ENOMEM;
+       }
+
+       if (copy_from_user(karg, uarg, sizeof(CSMI_SAS_SMP_PASSTHRU_BUFFER))) {
+               printk(KERN_ERR "%s@%d::%s() - "
+                   "Unable to read in csmi_sas_smp_passthru struct @ %p\n",
+                   __FILE__, __LINE__, __FUNCTION__, uarg);
+               free_pages((unsigned long)karg, memory_pages);
+               return -EFAULT;
+       }
+
+       request_data = NULL;
+       response_data = NULL;
+       response_data_sz = sizeof(CSMI_SAS_SMP_RESPONSE);
+       request_data_sz  = karg->Parameters.uRequestLength;
+
+       if (((iocnum = mpt_verify_adapter(karg->IoctlHeader.IOControllerNumber,
+           &ioc)) < 0) || (ioc == NULL)) {
+               printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n",
+                   __FILE__, __FUNCTION__, __LINE__, iocnum);
+               free_pages((unsigned long)karg, memory_pages);
+               return -ENODEV;
+       }
+
+       if (ioc->ioc_reset_in_progress) {
+               printk(KERN_ERR "%s@%d::%s - "
+                   "Busy with IOC Reset \n",
+                   __FILE__, __LINE__,__FUNCTION__);
+               free_pages((unsigned long)karg, memory_pages);
+               return -EBUSY;
+       }
+
+       if (!csmisas_is_this_sas_cntr(ioc)) {
+               printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n",
+                   __FILE__, __FUNCTION__, __LINE__, iocnum);
+               free_pages((unsigned long)karg, memory_pages);
+               return -ENODEV;
+       }
+
+       dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__));
+
+       /* Default to success.*/
+       karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS;
+
+       /* Do some error checking on the request. */
+       if (karg->Parameters.bPortIdentifier == CSMI_SAS_IGNORE_PORT) {
+               karg->IoctlHeader.ReturnCode = CSMI_SAS_SELECT_PHY_OR_PORT;
+               goto cim_smp_passthru_exit;
+       }
+
+       if ((request_data_sz > 0xFFFF) || (!request_data_sz)) {
+               karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+               goto cim_smp_passthru_exit;
+       }
+
+       /* Get a free request frame and save the message context.
+        */
+       if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL) {
+               dcsmisasprintk(ioc, printk(KERN_ERR ": no msg frames!\n"));
+               karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+               goto cim_smp_passthru_exit;
+        }
+
+       mpi_hdr = (MPIHeader_t *) mf;
+       MsgContext = mpi_hdr->MsgContext;
+       smpReq = (pSmpPassthroughRequest_t ) mf;
+
+       memset(smpReq,0,ioc->req_sz);
+
+       memcpy(&sas_address, karg->Parameters.bDestinationSASAddress,
+           sizeof(u64));
+       sas_address = cpu_to_le64(reverse_byte_order64(sas_address));
+       memcpy(&smpReq->SASAddress, &sas_address, sizeof(u64));
+
+       /* Fill in smp request. */
+       smpReq->PhysicalPort = karg->Parameters.bPortIdentifier;
+       smpReq->Function = MPI_FUNCTION_SMP_PASSTHROUGH;
+       smpReq->RequestDataLength = cpu_to_le16(request_data_sz);
+       smpReq->ConnectionRate = karg->Parameters.bConnectionRate;
+       smpReq->MsgContext = MsgContext;
+       smpReq->Reserved2 = 0;
+       smpReq->Reserved3 = 0;
+
+       /*
+        * Prepare the necessary pointers to run
+        * through the SGL generation
+        */
+
+       psge = (char *)&smpReq->SGL;
+
+       /* setup the *Request* payload SGE */
+       flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
+               MPI_SGE_FLAGS_SYSTEM_ADDRESS |
+               MPI_SGE_FLAGS_32_BIT_ADDRESSING |
+               MPI_SGE_FLAGS_HOST_TO_IOC |
+               MPI_SGE_FLAGS_END_OF_BUFFER;
+
+       if (sizeof(dma_addr_t) == sizeof(u64)) {
+               flagsLength |= MPI_SGE_FLAGS_64_BIT_ADDRESSING;
+       }
+       flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT;
+       flagsLength |= request_data_sz;
+
+       request_data = pci_alloc_consistent(
+           ioc->pcidev, request_data_sz, &request_data_dma);
+
+       if (!request_data) {
+               dcsmisasprintk(ioc, printk(KERN_ERR ": pci_alloc_consistent: FAILED\n"));
+               karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+               mpt_free_msg_frame(ioc, mf);
+               goto cim_smp_passthru_exit;
+       }
+
+       ioc->add_sge(psge, flagsLength, request_data_dma);
+       psge += (sizeof(u32) + sizeof(dma_addr_t));
+
+       memcpy(request_data, &karg->Parameters.Request, request_data_sz);
+
+       /* setup the *Response* payload SGE */
+       response_data = pci_alloc_consistent(
+           ioc->pcidev, response_data_sz, &response_data_dma);
+
+       if (!response_data) {
+               dcsmisasprintk(ioc, printk(KERN_ERR ": pci_alloc_consistent: FAILED\n"));
+               karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+               mpt_free_msg_frame(ioc, mf);
+               goto cim_smp_passthru_exit;
+       }
+
+       flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
+               MPI_SGE_FLAGS_SYSTEM_ADDRESS |
+               MPI_SGE_FLAGS_32_BIT_ADDRESSING |
+               MPI_SGE_FLAGS_IOC_TO_HOST |
+               MPI_SGE_FLAGS_END_OF_BUFFER;
+
+       if (sizeof(dma_addr_t) == sizeof(u64)) {
+               flagsLength |= MPI_SGE_FLAGS_64_BIT_ADDRESSING;
+       }
+
+       flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT;
+       flagsLength |= response_data_sz;
+
+       ioc->add_sge(psge, flagsLength, response_data_dma);
+
+       if (csmisas_send_command_wait(ioc, mf, karg->IoctlHeader.Timeout) != 0) {
+               karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+               goto cim_smp_passthru_exit;
+       }
+
+       if ((ioc->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID) == 0) {
+               dcsmisasprintk(ioc, printk(KERN_DEBUG ": SMP Passthru: oh no, there is no reply!!"));
+               karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+               goto cim_smp_passthru_exit;
+       }
+
+       /* process the completed Reply Message Frame */
+       smpReply = (pSmpPassthroughReply_t )ioc->ioctl_cmds.reply;
+       ioc_status = le16_to_cpu(smpReply->IOCStatus) & MPI_IOCSTATUS_MASK;
+
+       if ((ioc_status != MPI_IOCSTATUS_SUCCESS) &&
+           (ioc_status != MPI_IOCSTATUS_SCSI_DATA_UNDERRUN)) {
+               karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+               dcsmisasprintk(ioc, printk(KERN_DEBUG ": SMP Passthru: "));
+               dcsmisasprintk(ioc, printk("IOCStatus=0x%X IOCLogInfo=0x%X SASStatus=0x%X\n",
+                   le16_to_cpu(smpReply->IOCStatus),
+                   le32_to_cpu(smpReply->IOCLogInfo),
+                   smpReply->SASStatus));
+               goto cim_smp_passthru_exit;
+       }
+
+       karg->Parameters.bConnectionStatus =
+           map_sas_status_to_csmi(smpReply->SASStatus);
+
+
+       if (le16_to_cpu(smpReply->ResponseDataLength)) {
+               karg->Parameters.uResponseBytes = le16_to_cpu(smpReply->ResponseDataLength);
+               memcpy(&karg->Parameters.Response,
+                   response_data, le16_to_cpu(smpReply->ResponseDataLength));
+       }
+
+ cim_smp_passthru_exit:
+
+       if (request_data)
+               pci_free_consistent(ioc->pcidev, request_data_sz,
+                   (u8 *)request_data, request_data_dma);
+
+       if (response_data)
+               pci_free_consistent(ioc->pcidev, response_data_sz,
+                   (u8 *)response_data, response_data_dma);
+
+
+       /* Copy the data from kernel memory to user memory
+        */
+       if (copy_to_user(uarg, karg,
+           sizeof(CSMI_SAS_SMP_PASSTHRU_BUFFER))) {
+               printk(KERN_ERR "%s@%d::%s() - "
+                       "Unable to write out csmi_sas_smp_passthru @ %p\n",
+                               __FILE__, __LINE__, __FUNCTION__, uarg);
+               free_pages((unsigned long)karg, memory_pages);
+               return -EFAULT;
+       }
+
+       free_pages((unsigned long)karg, memory_pages);
+       dcsmisasprintk(ioc, printk(KERN_DEBUG ": %s exit.\n",__FUNCTION__));
+       return 0;
+}
+
+/**
+ * Prototype Routine for the CSMI SAS SSP Passthru command.
+ *
+ * Outputs:    None.
+ * Return:     0 if successful
+ *             -EFAULT if data unavailable
+ *             -ENODEV if no such device/adapter
+ **/
+static int csmisas_ssp_passthru(unsigned long arg)
+{
+       CSMI_SAS_SSP_PASSTHRU_BUFFER __user *uarg = (void __user *) arg;
+       CSMI_SAS_SSP_PASSTHRU_BUFFER     karg_hdr, * karg;
+       MPT_ADAPTER                     *ioc = NULL;
+       pSCSIIORequest_t                pScsiRequest;
+       pSCSIIOReply_t                  pScsiReply;
+       MPT_FRAME_HDR                   *mf = NULL;
+       MPIHeader_t                     *mpi_hdr;
+       int                             iocnum,ii;
+       u64                             sas_address;
+       u16                             req_idx;
+       char                            *psge;
+       int                             flagsLength;
+       void *                          request_data;
+       dma_addr_t                      request_data_dma;
+       u32                             request_data_sz;
+       int                             malloc_data_sz;
+       int                             memory_pages;
+       u16                             ioc_status;
+       u8                              volume_id;
+       u8                              volume_bus;
+       u8                              is_hidden_raid_component;
+       u8                              channel;
+       u8                              id;
+       struct sas_device_info          *sas_info;
+       u8                              skey, asc, ascq;
+       u32                             MsgContext;
+
+       if (copy_from_user(&karg_hdr, uarg, sizeof(CSMI_SAS_SSP_PASSTHRU_BUFFER))) {
+               printk(KERN_ERR "%s@%d::%s() - "
+                   "Unable to read in csmi_sas_ssp_passthru struct @ %p\n",
+                   __FILE__, __LINE__, __FUNCTION__, uarg);
+               return -EFAULT;
+       }
+
+       request_data = NULL;
+       request_data_sz = karg_hdr.Parameters.uDataLength;
+       channel = 0;
+       id = 0;
+       volume_id = 0;
+       volume_bus = 0;
+       is_hidden_raid_component = 0;
+
+       malloc_data_sz = (request_data_sz +
+           offsetof(CSMI_SAS_SSP_PASSTHRU_BUFFER, bDataBuffer));
+       memory_pages = get_order(malloc_data_sz);
+       karg = (CSMI_SAS_SSP_PASSTHRU_BUFFER *)__get_free_pages(
+               GFP_KERNEL, memory_pages);
+       if (!karg){
+               printk(KERN_ERR "%s@%d::%s() - "
+                       "Unable to malloc SAS_SSP_PASSTHRU_BUFFER "
+                       "malloc_data_sz=%d memory_pages=%d\n",
+                       __FILE__, __LINE__, __FUNCTION__,
+                       malloc_data_sz, memory_pages);
+               return -ENOMEM;
+       }
+
+       memset(karg, 0, sizeof(*karg));
+
+       if (copy_from_user(karg, uarg, request_data_sz +
+           offsetof(CSMI_SAS_SSP_PASSTHRU_BUFFER,bDataBuffer))) {
+               printk(KERN_ERR "%s@%d::%s() - "
+                   "Unable to read in csmi_sas_ssp_passthru struct @ %p\n",
+                   __FILE__, __LINE__, __FUNCTION__, uarg);
+               free_pages((unsigned long)karg, memory_pages);
+               return -EFAULT;
+       }
+
+       /*
+        * some checks of the incoming frame
+        */
+       if ( offsetof(CSMI_SAS_SSP_PASSTHRU_BUFFER,bDataBuffer) +
+           request_data_sz - sizeof(IOCTL_HEADER) >
+           karg->IoctlHeader.Length ) {
+               karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_INVALID_PARAMETER;
+               dcsmisasprintk(ioc, printk(KERN_ERR
+                   "%s::%s()"
+                   " @%d - expected datalen incorrect!\n",
+                   __FILE__, __FUNCTION__, __LINE__));
+               goto cim_ssp_passthru_exit;
+       }
+
+       if (((iocnum = mpt_verify_adapter(karg->IoctlHeader.IOControllerNumber,
+           &ioc)) < 0) || (ioc == NULL)) {
+               karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_INVALID_PARAMETER;
+               printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n",
+                   __FILE__, __FUNCTION__, __LINE__, iocnum);
+               goto cim_ssp_passthru_exit;
+       }
+
+       if (ioc->ioc_reset_in_progress) {
+               printk(KERN_ERR "%s@%d::%s - "
+                   "Busy with IOC Reset \n",
+                   __FILE__, __LINE__,__FUNCTION__);
+               return -EBUSY;
+       }
+
+       if (!csmisas_is_this_sas_cntr(ioc)) {
+               karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_INVALID_PARAMETER;
+               printk(KERN_ERR "%s::%s()@%d - ioc%d not SAS controller!\n",
+                   __FILE__, __FUNCTION__, __LINE__, iocnum);
+               goto cim_ssp_passthru_exit;
+       }
+
+       dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__));
+
+       /* Default to success.
+        */
+       karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS;
+
+       /* Neither a phy nor a port has been selected.
+        */
+       if ((karg->Parameters.bPhyIdentifier == CSMI_SAS_USE_PORT_IDENTIFIER) &&
+               (karg->Parameters.bPortIdentifier == CSMI_SAS_IGNORE_PORT)) {
+               karg->IoctlHeader.ReturnCode = CSMI_SAS_SELECT_PHY_OR_PORT;
+               dcsmisasprintk(ioc, printk(KERN_ERR
+                   "%s::%s()"
+                   " @%d - incorrect bPhyIdentifier and bPortIdentifier!\n",
+                   __FILE__, __FUNCTION__, __LINE__));
+               goto cim_ssp_passthru_exit;
+       }
+
+       /* A phy has been selected. Verify that it's valid.
+        */
+       if (karg->Parameters.bPortIdentifier == CSMI_SAS_IGNORE_PORT) {
+
+               /* Is the phy in range? */
+               if (karg->Parameters.bPhyIdentifier >= ioc->num_ports) {
+                       dcsmisasprintk(ioc, printk(KERN_WARNING ": phyId >= ioc->num_ports (%d %d)\n",
+                           karg->Parameters.bPhyIdentifier,
+                           ioc->num_ports));
+                       karg->IoctlHeader.ReturnCode =
+                           CSMI_SAS_PHY_DOES_NOT_EXIST;
+                       goto cim_ssp_passthru_exit;
+               }
+       }
+
+       if(karg->Parameters.bAdditionalCDBLength) {
+       /* TODO - SCSI IO (32) Request Message support
+        */
+               dcsmisasprintk(ioc, printk(KERN_DEBUG ": greater than 16-byte cdb "
+                   "is not supported!\n"));
+                   karg->IoctlHeader.ReturnCode =
+                       CSMI_SAS_STATUS_INVALID_PARAMETER;
+               goto cim_ssp_passthru_exit;
+       }
+
+       /* we will use SAS address to resolve the scsi adddressing
+        */
+       memcpy(&sas_address, karg->Parameters.bDestinationSASAddress,
+           sizeof(u64));
+       sas_address = reverse_byte_order64(sas_address);
+
+       /* Search the list for the matching SAS address.
+        */
+       sas_info = csmisas_get_device_component_by_sas_addr(ioc, sas_address);
+       if (!sas_info || sas_info->is_cached) {
+               /*
+                *Invalid SAS address
+                */
+               karg->IoctlHeader.ReturnCode =
+                   CSMI_SAS_STATUS_INVALID_PARAMETER;
+               dcsmisasprintk(ioc, printk(KERN_ERR
+                   "%s::%s() @%d - couldn't find associated "
+                   "SASAddress=%llX!\n", __FILE__, __FUNCTION__, __LINE__,
+                   (unsigned long long)sas_address));
+               goto cim_ssp_passthru_exit;
+       }
+
+       id = sas_info->fw.id;
+       channel = sas_info->fw.channel;
+
+       if (csmisas_is_phys_disk(ioc, channel, id)) {
+               id = csmisas_raid_id_to_num(ioc, channel, id);
+               channel = 0;
+               is_hidden_raid_component = 1;
+       }
+
+       /* Get a free request frame and save the message context.
+        */
+       if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL) {
+               dcsmisasprintk(ioc, printk(KERN_ERR ": no msg frames!\n"));
+               karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+               goto cim_ssp_passthru_exit;
+        }
+
+       mpi_hdr = (MPIHeader_t *) mf;
+       MsgContext = mpi_hdr->MsgContext;
+       pScsiRequest = (pSCSIIORequest_t) mf;
+       req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
+
+       memset(pScsiRequest,0,sizeof(SCSIIORequest_t));
+
+       /* Fill in SCSI IO (16) request.
+        */
+
+       pScsiRequest->Function = (is_hidden_raid_component == 1) ?
+           MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH : MPI_FUNCTION_SCSI_IO_REQUEST;
+       pScsiRequest->TargetID = id;
+       pScsiRequest->Bus = channel;
+       memcpy(pScsiRequest->LUN, &karg->Parameters.bLun, 8);
+       pScsiRequest->CDBLength = karg->Parameters.bCDBLength;
+       pScsiRequest->DataLength = cpu_to_le32(request_data_sz);
+       pScsiRequest->MsgContext = MsgContext;
+       memcpy(pScsiRequest->CDB, karg->Parameters.bCDB,
+           pScsiRequest->CDBLength);
+
+       dcsmisasprintk(ioc, printk(KERN_DEBUG "\tchannel = %d id = %d ",
+           sas_info->fw.channel, sas_info->fw.id));
+       dcsmisasprintk(ioc, if(is_hidden_raid_component)
+           printk(KERN_DEBUG "num_id = %d ", id));
+       dcsmisasprintk(ioc, printk(KERN_DEBUG "\n"));
+       dcsmisasprintk(ioc, printk(KERN_DEBUG "\tcdb_len = %d request_len = %d\n",
+           pScsiRequest->CDBLength, request_data_sz));
+       dcsmisasprintk(ioc, printk(KERN_DEBUG "\t"));
+       dcsmisasprintk(ioc, for (ii = 0; ii < pScsiRequest->CDBLength; ++ii)
+           printk(" %02x", pScsiRequest->CDB[ii]));
+       dcsmisasprintk(ioc, printk(KERN_DEBUG "\n"));
+
+       /* direction
+        */
+       if (karg->Parameters.uFlags & CSMI_SAS_SSP_READ) {
+               pScsiRequest->Control = cpu_to_le32(MPI_SCSIIO_CONTROL_READ);
+       } else if (karg->Parameters.uFlags & CSMI_SAS_SSP_WRITE) {
+               pScsiRequest->Control = cpu_to_le32(MPI_SCSIIO_CONTROL_WRITE);
+       } else if ((karg->Parameters.uFlags & CSMI_SAS_SSP_UNSPECIFIED) &&
+           (!karg->Parameters.uDataLength)) {
+               /* no data transfer
+                */
+               pScsiRequest->Control = cpu_to_le32(MPI_SCSIIO_CONTROL_NODATATRANSFER);
+       } else {
+               /* no direction specified
+                */
+               pScsiRequest->Control = cpu_to_le32(MPI_SCSIIO_CONTROL_READ);
+               pScsiRequest->MsgFlags =
+                   MPI_SCSIIO_MSGFLGS_CMD_DETERMINES_DATA_DIR;
+       }
+
+       pScsiRequest->MsgFlags |= mpt_msg_flags();
+       /* task attributes
+        */
+       if((karg->Parameters.uFlags && 0xFF) == 0) {
+               pScsiRequest->Control |= cpu_to_le32(MPI_SCSIIO_CONTROL_SIMPLEQ);
+       } else if (karg->Parameters.uFlags &
+           CSMI_SAS_SSP_TASK_ATTRIBUTE_HEAD_OF_QUEUE) {
+               pScsiRequest->Control |= cpu_to_le32(MPI_SCSIIO_CONTROL_HEADOFQ);
+       } else if (karg->Parameters.uFlags &
+           CSMI_SAS_SSP_TASK_ATTRIBUTE_ORDERED) {
+               pScsiRequest->Control |= cpu_to_le32(MPI_SCSIIO_CONTROL_ORDEREDQ);
+       } else if (karg->Parameters.uFlags &
+           CSMI_SAS_SSP_TASK_ATTRIBUTE_ACA) {
+               pScsiRequest->Control |= cpu_to_le32(MPI_SCSIIO_CONTROL_ACAQ);
+       } else {
+               pScsiRequest->Control |= cpu_to_le32(MPI_SCSIIO_CONTROL_UNTAGGED);
+       }
+
+       /* setup sense
+        */
+       pScsiRequest->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
+       pScsiRequest->SenseBufferLowAddr = cpu_to_le32(ioc->sense_buf_low_dma +
+           (req_idx * MPT_SENSE_BUFFER_ALLOC));
+
+       /* setup databuffer sg, assuming we fit everything one contiguous buffer
+        */
+       psge = (char *)&pScsiRequest->SGL;
+
+       if (karg->Parameters.uFlags & CSMI_SAS_SSP_WRITE) {
+               flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
+       } else if (karg->Parameters.uFlags & CSMI_SAS_SSP_READ) {
+               flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
+       }else {
+               flagsLength = ( MPI_SGE_FLAGS_SIMPLE_ELEMENT |
+                               MPI_SGE_FLAGS_DIRECTION )
+                               << MPI_SGE_FLAGS_SHIFT;
+       }
+       flagsLength |= request_data_sz;
+
+       if ( request_data_sz > 0) {
+               request_data = pci_alloc_consistent(
+                   ioc->pcidev, request_data_sz, &request_data_dma);
+
+               if (request_data == NULL) {
+                       dcsmisasprintk(ioc, printk(KERN_ERR ": pci_alloc_consistent: FAILED "
+                           "request_data_sz=%d\n", request_data_sz));
+                       karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+                       mpt_free_msg_frame(ioc, mf);
+                       goto cim_ssp_passthru_exit;
+               }
+
+               ioc->add_sge(psge, flagsLength, request_data_dma);
+               if (karg->Parameters.uFlags & CSMI_SAS_SSP_WRITE)
+                       memcpy(request_data, karg->bDataBuffer, request_data_sz);
+       } else {
+               ioc->add_sge(psge, flagsLength, (dma_addr_t) -1);
+       }
+
+       if (csmisas_send_command_wait(ioc, mf, karg->IoctlHeader.Timeout) != 0) {
+               karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+               goto cim_ssp_passthru_exit;
+       }
+
+       memset(&karg->Status,0,sizeof(CSMI_SAS_SSP_PASSTHRU_STATUS));
+       karg->Status.bConnectionStatus = CSMI_SAS_OPEN_ACCEPT;
+       karg->Status.bDataPresent = CSMI_SAS_SSP_NO_DATA_PRESENT;
+       karg->Status.bStatus = GOOD;
+       karg->Status.bResponseLength[0] = 0;
+       karg->Status.bResponseLength[1] = 0;
+       karg->Status.uDataBytes = request_data_sz;
+
+       /* process the completed Reply Message Frame */
+       if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID) {
+
+               pScsiReply = (pSCSIIOReply_t ) ioc->ioctl_cmds.reply;
+               karg->Status.bStatus = pScsiReply->SCSIStatus;
+               karg->Status.uDataBytes = min(le32_to_cpu(pScsiReply->TransferCount),
+                   request_data_sz);
+               ioc_status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK;
+
+               if (pScsiReply->SCSIState ==
+                   MPI_SCSI_STATE_AUTOSENSE_VALID) {
+                       karg->Status.bConnectionStatus =
+                           CSMI_SAS_SSP_SENSE_DATA_PRESENT;
+                       karg->Status.bResponseLength[0] =
+                               (u8)le32_to_cpu(pScsiReply->SenseCount) & 0xFF;
+                       memcpy(karg->Status.bResponse,
+                           ioc->ioctl_cmds.sense, le32_to_cpu(pScsiReply->SenseCount));
+
+                       skey = ioc->ioctl_cmds.sense[2] & 0x0F;
+                       asc = ioc->ioctl_cmds.sense[12];
+                       ascq = ioc->ioctl_cmds.sense[13];
+
+                       dcsmisasprintk(ioc, printk(KERN_DEBUG "\t [sense_key,asc,ascq]: "
+                           "[0x%02x,0x%02x,0x%02x]\n",
+                           skey, asc, ascq));
+
+               } else if(pScsiReply->SCSIState ==
+                   MPI_SCSI_STATE_RESPONSE_INFO_VALID) {
+                       karg->Status.bDataPresent =
+                           CSMI_SAS_SSP_RESPONSE_DATA_PRESENT;
+                       karg->Status.bResponseLength[0] =
+                               sizeof(pScsiReply->ResponseInfo);
+                       for (ii=0;ii<sizeof(pScsiReply->ResponseInfo);ii++) {
+                               karg->Status.bResponse[ii] =
+                               ((u8*)&pScsiReply->ResponseInfo)[
+                                   (sizeof(pScsiReply->ResponseInfo)-1)-ii];
+                       }
+               } else if ((ioc_status != MPI_IOCSTATUS_SUCCESS) &&
+                   (ioc_status !=  MPI_IOCSTATUS_SCSI_RECOVERED_ERROR) &&
+                   (ioc_status != MPI_IOCSTATUS_SCSI_DATA_UNDERRUN)) {
+                       karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+                       dcsmisasprintk(ioc, printk(KERN_DEBUG ": SCSI IO : "));
+                       dcsmisasprintk(ioc, printk("IOCStatus=0x%X IOCLogInfo=0x%X\n",
+                           pScsiReply->IOCStatus,
+                           pScsiReply->IOCLogInfo));
+               }
+       }
+
+       if ((karg->Status.uDataBytes) && (request_data) &&
+           (karg->Parameters.uFlags & CSMI_SAS_SSP_READ)) {
+               if (copy_to_user((void __user *)uarg->bDataBuffer,
+                   request_data, karg->Status.uDataBytes)) {
+                       printk(KERN_ERR "%s@%d::%s - "
+                           "Unable to write data to user %p\n",
+                           __FILE__, __LINE__,__FUNCTION__,
+                           (void*)karg->bDataBuffer);
+                       karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+               }
+       }
+
+ cim_ssp_passthru_exit:
+
+
+       if (request_data)
+               pci_free_consistent(ioc->pcidev, request_data_sz,
+                   (u8 *)request_data, request_data_dma);
+
+       /* Copy the data from kernel memory to user memory
+        */
+       if (copy_to_user(uarg, karg,
+           offsetof(CSMI_SAS_SSP_PASSTHRU_BUFFER, bDataBuffer))) {
+               printk(KERN_ERR "%s@%d::%s() - "
+                       "Unable to write out csmi_sas_ssp_passthru @ %p\n",
+                               __FILE__, __LINE__, __FUNCTION__, uarg);
+               free_pages((unsigned long)karg, memory_pages);
+               return -EFAULT;
+       }
+
+       dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__));
+       free_pages((unsigned long)karg, memory_pages);
+       return 0;
+}
+
+/**
+ * Prototype Routine for the CSMI SAS STP Passthru command.
+ *
+ * Outputs:    None.
+ * Return:     0 if successful
+ *             -EFAULT if data unavailable
+ *             -ENODEV if no such device/adapter
+ **/
+static int
+csmisas_stp_passthru(unsigned long arg)
+{
+       CSMI_SAS_STP_PASSTHRU_BUFFER __user *uarg = (void __user *) arg;
+       CSMI_SAS_STP_PASSTHRU_BUFFER    karg_hdr, *karg;
+       MPT_ADAPTER                     *ioc = NULL;
+       pSataPassthroughRequest_t       pSataRequest;
+       pSataPassthroughReply_t         pSataReply;
+       MPT_FRAME_HDR                   *mf = NULL;
+       MPIHeader_t                     *mpi_hdr;
+       int                             iocnum;
+       u32                             data_sz;
+       u64                             sas_address;
+       u16                             req_idx;
+       char                            *psge;
+       int                             flagsLength;
+       void *                          request_data;
+       dma_addr_t                      request_data_dma;
+       u32                             request_data_sz;
+       int                             malloc_data_sz;
+       int                             memory_pages;
+       u8                              channel;
+       u8                              id;
+       u8                              volume_id;
+       u8                              volume_bus;
+       struct sas_device_info          *sas_info;
+       u16                             ioc_status;
+       u32                             MsgContext;
+
+       if (copy_from_user(&karg_hdr, uarg, sizeof(CSMI_SAS_STP_PASSTHRU_BUFFER))) {
+               printk(KERN_ERR "%s@%d::%s() - "
+                   "Unable to read struct @ %p\n",
+                   __FILE__, __LINE__, __FUNCTION__, uarg);
+               return -EFAULT;
+       }
+
+       request_data=NULL;
+       request_data_sz = karg_hdr.Parameters.uDataLength;
+       volume_id = 0;
+       volume_bus = 0;
+       channel = 0;
+       id = 0;
+
+       malloc_data_sz = (request_data_sz +
+           offsetof(CSMI_SAS_STP_PASSTHRU_BUFFER, bDataBuffer));
+       memory_pages = get_order(malloc_data_sz);
+       karg = (CSMI_SAS_STP_PASSTHRU_BUFFER *)__get_free_pages(
+               GFP_KERNEL, memory_pages);
+       if (!karg){
+               printk(KERN_ERR "%s@%d::%s() - "
+                       "Unable to malloc CSMI_SAS_STP_PASSTHRU_BUFFER "
+                       "malloc_data_sz=%d memory_pages=%d\n",
+                       __FILE__, __LINE__, __FUNCTION__, 
+                       malloc_data_sz, memory_pages);
+               return -ENOMEM;
+       }
+
+       memset(karg, 0, sizeof(*karg));
+
+       if (copy_from_user(karg, uarg, malloc_data_sz)) {
+               printk(KERN_ERR "%s@%d::%s() - "
+                   "Unable to read in csmi_sas_ssp_passthru struct @ %p\n",
+                   __FILE__, __LINE__, __FUNCTION__, uarg);
+               free_pages((unsigned long)karg, memory_pages);
+               return -EFAULT;
+       }
+
+       if (((iocnum = mpt_verify_adapter(karg->IoctlHeader.IOControllerNumber,
+           &ioc)) < 0) || (ioc == NULL)) {
+               printk(KERN_ERR "%s::%s @%d - ioc%d not found!\n",
+                   __FILE__, __FUNCTION__, __LINE__, iocnum);
+               free_pages((unsigned long)karg, memory_pages);
+               return -ENODEV;
+       }
+
+       if (ioc->ioc_reset_in_progress) {
+               printk(KERN_ERR "%s@%d::%s - "
+                   "Busy with IOC Reset \n",
+                   __FILE__, __LINE__,__FUNCTION__);
+               free_pages((unsigned long)karg, memory_pages);
+               return -EBUSY;
+       }
+
+       if (!csmisas_is_this_sas_cntr(ioc)) {
+               printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n",
+                   __FILE__, __FUNCTION__, __LINE__, iocnum);
+               free_pages((unsigned long)karg, memory_pages);
+               return -ENODEV;
+       }
+
+       dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__));
+
+       /* Default to success.
+        */
+       karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS;
+
+       /* Neither a phy nor a port has been selected.
+        */
+       if ((karg->Parameters.bPhyIdentifier == CSMI_SAS_USE_PORT_IDENTIFIER) &&
+               (karg->Parameters.bPortIdentifier == CSMI_SAS_IGNORE_PORT)) {
+               karg->IoctlHeader.ReturnCode = CSMI_SAS_SELECT_PHY_OR_PORT;
+               dcsmisasprintk(ioc, printk(KERN_ERR
+                   "%s::%s() @%d - incorrect bPhyIdentifier and bPortIdentifier!\n",
+                   __FILE__,__FUNCTION__, __LINE__));
+               goto cim_stp_passthru_exit;
+       }
+
+       /* A phy has been selected. Verify that it's valid.
+        */
+       if (karg->Parameters.bPortIdentifier == CSMI_SAS_IGNORE_PORT) {
+
+               /* Is the phy in range? */
+               if (karg->Parameters.bPhyIdentifier >= ioc->num_ports) {
+                       karg->IoctlHeader.ReturnCode =
+                           CSMI_SAS_PHY_DOES_NOT_EXIST;
+                       goto cim_stp_passthru_exit;
+               }
+       }
+
+       data_sz = sizeof(CSMI_SAS_STP_PASSTHRU_BUFFER) -
+           sizeof(IOCTL_HEADER) - sizeof(u8*) +
+           request_data_sz;
+
+       if ( data_sz > karg->IoctlHeader.Length ) {
+               karg->IoctlHeader.ReturnCode =
+                   CSMI_SAS_STATUS_INVALID_PARAMETER;
+               dcsmisasprintk(ioc, printk(KERN_ERR
+                   "%s::%s() @%d - expected datalen incorrect!\n",
+                   __FILE__, __FUNCTION__,__LINE__));
+               goto cim_stp_passthru_exit;
+       }
+
+
+       /* we will use SAS address to resolve the scsi adddressing
+        */
+       memcpy(&sas_address, karg->Parameters.bDestinationSASAddress,
+           sizeof(u64));
+       sas_address = reverse_byte_order64(sas_address);
+
+       /* Search the list for the matching SAS address.
+        */
+       sas_info = csmisas_get_device_component_by_sas_addr(ioc, sas_address);
+       if (!sas_info || sas_info->is_cached || sas_info->is_logical_volume) {
+               /*
+                *Invalid SAS address
+                */
+               karg->IoctlHeader.ReturnCode =
+                   CSMI_SAS_STATUS_INVALID_PARAMETER;
+               dcsmisasprintk(ioc, printk(KERN_ERR
+                   "%s::%s() @%d - couldn't find associated "
+                   "SASAddress=%llX!\n", __FILE__, __FUNCTION__, __LINE__,
+                   (unsigned long long)sas_address));
+               goto cim_stp_passthru_exit;
+       }
+
+       id = sas_info->fw.id;
+       channel = sas_info->fw.channel;
+
+       /* check that this is an STP or SATA target device
+        */
+       if ( !(sas_info->device_info & MPI_SAS_DEVICE_INFO_STP_TARGET ) &&
+            !(sas_info->device_info & MPI_SAS_DEVICE_INFO_SATA_DEVICE )) {
+               karg->IoctlHeader.ReturnCode =
+                   CSMI_SAS_STATUS_INVALID_PARAMETER;
+               goto cim_stp_passthru_exit;
+       }
+
+       /* Get a free request frame and save the message context.
+        */
+       if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL) {
+               dcsmisasprintk(ioc, printk(KERN_ERR ": no msg frames!\n"));
+               karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+               goto cim_stp_passthru_exit;
+        }
+
+       mpi_hdr = (MPIHeader_t *) mf;
+       MsgContext = mpi_hdr->MsgContext;
+       pSataRequest = (pSataPassthroughRequest_t) mf;
+       req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
+
+       memset(pSataRequest,0,sizeof(pSataPassthroughRequest_t));
+
+       pSataRequest->TargetID = id;
+       pSataRequest->Bus = channel;
+       pSataRequest->Function = MPI_FUNCTION_SATA_PASSTHROUGH;
+       pSataRequest->PassthroughFlags = cpu_to_le16(karg->Parameters.uFlags);
+       pSataRequest->ConnectionRate = karg->Parameters.bConnectionRate;
+       pSataRequest->MsgContext = MsgContext;
+       pSataRequest->DataLength = cpu_to_le32(request_data_sz);
+       pSataRequest->MsgFlags = 0;
+       memcpy( pSataRequest->CommandFIS,karg->Parameters.bCommandFIS, 20);
+
+       psge = (char *)&pSataRequest->SGL;
+       if (karg->Parameters.uFlags & CSMI_SAS_STP_WRITE) {
+               flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
+       } else if (karg->Parameters.uFlags & CSMI_SAS_STP_READ) {
+               flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
+       }else {
+               flagsLength = ( MPI_SGE_FLAGS_SIMPLE_ELEMENT |
+                               MPI_SGE_FLAGS_DIRECTION )
+                               << MPI_SGE_FLAGS_SHIFT;
+       }
+
+       flagsLength |= request_data_sz;
+       if (request_data_sz > 0) {
+               request_data = pci_alloc_consistent(
+                   ioc->pcidev, request_data_sz, &request_data_dma);
+
+               if (request_data == NULL) {
+                       dcsmisasprintk(ioc, printk(KERN_ERR ": pci_alloc_consistent: FAILED\n"));
+                       karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+                       mpt_free_msg_frame(ioc, mf);
+                       goto cim_stp_passthru_exit;
+               }
+
+               ioc->add_sge(psge, flagsLength, request_data_dma);
+               if (karg->Parameters.uFlags & CSMI_SAS_SSP_WRITE)
+                       memcpy(request_data, karg->bDataBuffer, request_data_sz);
+       } else {
+               ioc->add_sge(psge, flagsLength, (dma_addr_t) -1);
+       }
+
+       if (csmisas_send_command_wait(ioc, mf, karg->IoctlHeader.Timeout) != 0) {
+               karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+               goto cim_stp_passthru_exit;
+       }
+
+       memset(&karg->Status,0,sizeof(CSMI_SAS_STP_PASSTHRU_STATUS));
+
+       if ((ioc->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID) == 0) {
+               dcsmisasprintk(ioc, printk(KERN_DEBUG  ": STP Passthru: oh no, there is no reply!!"));
+               karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+               goto cim_stp_passthru_exit;
+       }
+
+       /* process the completed Reply Message Frame */
+       pSataReply = (pSataPassthroughReply_t ) ioc->ioctl_cmds.reply;
+       ioc_status = le16_to_cpu(pSataReply->IOCStatus) & MPI_IOCSTATUS_MASK;
+
+       if (ioc_status != MPI_IOCSTATUS_SUCCESS &&
+           ioc_status != MPI_IOCSTATUS_SCSI_DATA_UNDERRUN) {
+               karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+               dcsmisasprintk(ioc, printk(KERN_DEBUG ": STP Passthru: "));
+               dcsmisasprintk(ioc, printk("IOCStatus=0x%X IOCLogInfo=0x%X SASStatus=0x%X\n",
+                   le16_to_cpu(pSataReply->IOCStatus),
+                   le32_to_cpu(pSataReply->IOCLogInfo),
+                   pSataReply->SASStatus));
+       }
+
+       karg->Status.bConnectionStatus =
+           map_sas_status_to_csmi(pSataReply->SASStatus);
+
+       memcpy(karg->Status.bStatusFIS,pSataReply->StatusFIS, 20);
+
+       /*
+        * for now, just zero out uSCR array,
+        * then copy the one dword returned
+        * in the reply frame into uSCR[0]
+        */
+       memset( karg->Status.uSCR, 0, 64);
+       karg->Status.uSCR[0] = le32_to_cpu(pSataReply->StatusControlRegisters);
+
+       if((le32_to_cpu(pSataReply->TransferCount)) && (request_data) &&
+           (karg->Parameters.uFlags & CSMI_SAS_STP_READ)) {
+               karg->Status.uDataBytes =
+                   min(le32_to_cpu(pSataReply->TransferCount),request_data_sz);
+               if (copy_to_user((void __user *)uarg->bDataBuffer,
+                   request_data, karg->Status.uDataBytes)) {
+                       printk(KERN_ERR "%s::%s() @%d - "
+                           "Unable to write data to user %p\n",
+                           __FILE__, __FUNCTION__, __LINE__,
+                           (void*)karg->bDataBuffer);
+                       karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+               }
+       }
+
+ cim_stp_passthru_exit:
+
+       if (request_data)
+               pci_free_consistent(ioc->pcidev, request_data_sz,
+                   (u8 *)request_data, request_data_dma);
+
+       /* Copy th data from kernel memory to user memory
+        */
+       if (copy_to_user(uarg, karg,
+           offsetof(CSMI_SAS_STP_PASSTHRU_BUFFER, bDataBuffer))) {
+               printk(KERN_ERR "%s@%d::%s() - "
+                       "Unable to write out csmi_sas_ssp_passthru @ %p\n",
+                               __FILE__, __LINE__, __FUNCTION__, uarg);
+               free_pages((unsigned long)karg, memory_pages);
+               return -EFAULT;
+       }
+
+       free_pages((unsigned long)karg, memory_pages);
+       dcsmisasprintk(ioc, printk(KERN_DEBUG ": %s exit.\n",__FUNCTION__));
+       return 0;
+}
+
+/**
+ * Prototype Routine for the CSMI SAS Firmware Download command.
+ *
+ * Outputs:    None.
+ * Return:     0 if successful
+ *             -EFAULT if data unavailable
+ *             -ENODEV if no such device/adapter
+ **/
+static int
+csmisas_firmware_download(unsigned long arg)
+{
+       CSMI_SAS_FIRMWARE_DOWNLOAD_BUFFER __user *uarg = (void __user *) arg;
+       CSMI_SAS_FIRMWARE_DOWNLOAD_BUFFER        karg;
+       MPT_ADAPTER                     *ioc = NULL;
+       int                             iocnum;
+       pMpiFwHeader_t                  pFwHeader=NULL;
+
+       if (copy_from_user(&karg, uarg,
+               sizeof(CSMI_SAS_FIRMWARE_DOWNLOAD_BUFFER))) {
+               printk(KERN_ERR "%s@%d::%s() - "
+                   "Unable to read in csmi_sas_firmware_download struct @ %p\n",
+                   __FILE__, __LINE__, __FUNCTION__, uarg);
+               return -EFAULT;
+       }
+
+       if (((iocnum = mpt_verify_adapter(karg.IoctlHeader.IOControllerNumber,
+           &ioc)) < 0) || (ioc == NULL)) {
+               printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n",
+                   __FILE__, __FUNCTION__, __LINE__, iocnum);
+               return -ENODEV;
+       }
+
+       if (!csmisas_is_this_sas_cntr(ioc)) {
+               printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n",
+                   __FILE__, __FUNCTION__, __LINE__, iocnum);
+               return -ENODEV;
+       }
+
+       dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__));
+
+       /* Default to success.*/
+       karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS;
+       karg.Information.usStatus = CSMI_SAS_FWD_SUCCESS;
+       karg.Information.usSeverity = CSMI_SAS_FWD_INFORMATION;
+
+       /* some checks of the incoming frame */
+       if ((karg.Information.uBufferLength +
+           sizeof(CSMI_SAS_FIRMWARE_DOWNLOAD)) >
+           karg.IoctlHeader.Length) {
+               karg.IoctlHeader.ReturnCode =
+                   CSMI_SAS_STATUS_INVALID_PARAMETER;
+               karg.Information.usStatus = CSMI_SAS_FWD_FAILED;
+               goto cim_firmware_download_exit;
+       }
+
+       if ( karg.Information.uDownloadFlags &
+           (CSMI_SAS_FWD_SOFT_RESET | CSMI_SAS_FWD_VALIDATE)) {
+               karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+               karg.Information.usStatus = CSMI_SAS_FWD_REJECT;
+               karg.Information.usSeverity = CSMI_SAS_FWD_ERROR;
+               goto cim_firmware_download_exit;
+       }
+
+       /* now we need to alloc memory so we can pull in the
+        * fw image attached to end of incoming packet.
+        */
+       pFwHeader = kmalloc(karg.Information.uBufferLength, GFP_KERNEL);
+       if (!pFwHeader){
+               karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+               karg.Information.usStatus = CSMI_SAS_FWD_REJECT;
+               karg.Information.usSeverity = CSMI_SAS_FWD_ERROR;
+               goto cim_firmware_download_exit;
+       }
+       memset(pFwHeader, 0, sizeof(*pFwHeader));
+
+       if (copy_from_user(pFwHeader, uarg->bDataBuffer,
+               karg.Information.uBufferLength)) {
+               printk(KERN_ERR "%s@%d::%s() - "
+                   "Unable to read in pFwHeader @ %p\n",
+                   __FILE__, __LINE__, __FUNCTION__, uarg);
+               return -EFAULT;
+       }
+
+       if ( !((pFwHeader->Signature0 == MPI_FW_HEADER_SIGNATURE_0) &&
+           (pFwHeader->Signature1 == MPI_FW_HEADER_SIGNATURE_1) &&
+           (pFwHeader->Signature2 == MPI_FW_HEADER_SIGNATURE_2))) {
+               // the signature check failed
+               karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+               karg.Information.usStatus = CSMI_SAS_FWD_REJECT;
+               karg.Information.usSeverity = CSMI_SAS_FWD_ERROR;
+               goto cim_firmware_download_exit;
+       }
+
+       if ( mptctl_do_fw_download(karg.IoctlHeader.IOControllerNumber,
+           uarg->bDataBuffer, karg.Information.uBufferLength)
+           != 0) {
+               karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+               karg.Information.usStatus = CSMI_SAS_FWD_FAILED;
+               karg.Information.usSeverity = CSMI_SAS_FWD_FATAL;
+               goto cim_firmware_download_exit;
+       }
+
+       if((karg.Information.uDownloadFlags & CSMI_SAS_FWD_SOFT_RESET) ||
+           (karg.Information.uDownloadFlags & CSMI_SAS_FWD_HARD_RESET)) {
+               if (mpt_HardResetHandler(ioc, CAN_SLEEP) != 0) {
+                       karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+                       karg.Information.usStatus = CSMI_SAS_FWD_FAILED;
+                       karg.Information.usSeverity = CSMI_SAS_FWD_FATAL;
+               }
+       }
+
+ cim_firmware_download_exit:
+
+       if(pFwHeader)
+               kfree(pFwHeader);
+
+       /* Copy the data from kernel memory to user memory
+        */
+       if (copy_to_user(uarg, &karg,
+                               sizeof(CSMI_SAS_FIRMWARE_DOWNLOAD_BUFFER))) {
+               printk(KERN_ERR "%s@%d::%s() - "
+                       "Unable to write out csmi_sas_firmware_download @ %p\n",
+                               __FILE__, __LINE__, __FUNCTION__, uarg);
+               return -EFAULT;
+       }
+
+       dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__));
+       return 0;
+}
+
+/**
+ * Prototype Routine for the CSMI SAS Get RAID Info command.
+ *
+ * Outputs:    None.
+ * Return:     0 if successful
+ *             -EFAULT if data unavailable
+ *             -ENODEV if no such device/adapter
+ **/
+static int
+csmisas_get_raid_info(unsigned long arg)
+{
+       CSMI_SAS_RAID_INFO_BUFFER __user *uarg =  (void __user *) arg;
+       CSMI_SAS_RAID_INFO_BUFFER        karg;
+       MPT_ADAPTER                     *ioc = NULL;
+       int                             iocnum;
+       u32                             raidFlags;
+       u8                              maxRaidTypes;
+       u8                              maxDrivesPerSet;
+
+       if (copy_from_user(&karg, uarg, sizeof(CSMI_SAS_RAID_INFO_BUFFER))) {
+               printk(KERN_ERR "%s@%d::%s() - "
+                   "Unable to read in csmi_sas_get_raid_info struct @ %p\n",
+                   __FILE__, __LINE__, __FUNCTION__, uarg);
+               return -EFAULT;
+       }
+
+       if (((iocnum = mpt_verify_adapter(karg.IoctlHeader.IOControllerNumber,
+           &ioc)) < 0) || (ioc == NULL)) {
+               printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n",
+                   __FILE__, __FUNCTION__, __LINE__, iocnum);
+               return -ENODEV;
+       }
+
+       if (!csmisas_is_this_sas_cntr(ioc)) {
+               printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n",
+                   __FILE__, __FUNCTION__, __LINE__, iocnum);
+               return -ENODEV;
+       }
+
+       dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__));
+
+       karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+       if (!ioc->raid_data.pIocPg2)
+               goto csmisas_get_raid_info_out;
+       karg.Information.uNumRaidSets =
+           ioc->raid_data.pIocPg2->NumActiveVolumes;
+       karg.Information.uMaxRaidSets = ioc->raid_data.pIocPg2->MaxVolumes;
+       if( ioc->raid_data.pIocPg6 ) {
+               // get absolute maximum for all RAID sets
+               maxDrivesPerSet = ioc->raid_data.pIocPg6->MaxDrivesIS;
+               maxDrivesPerSet = max(ioc->raid_data.pIocPg6->MaxDrivesIM,
+                   maxDrivesPerSet);
+               maxDrivesPerSet = max(ioc->raid_data.pIocPg6->MaxDrivesIME,
+                   maxDrivesPerSet);
+               karg.Information.uMaxDrivesPerSet = maxDrivesPerSet;
+       }
+       else
+               karg.Information.uMaxDrivesPerSet = 8;
+       // For bMaxRaidSets, count bits set in bits 0-6 of CapabilitiesFlags
+       raidFlags = ioc->raid_data.pIocPg2->CapabilitiesFlags & 0x0000007F;
+       for( maxRaidTypes=0; raidFlags; maxRaidTypes++ )
+               raidFlags &= raidFlags - 1;
+       karg.Information.bMaxRaidTypes = maxRaidTypes;
+       // ulMinRaidSetBlocks hard coded to 1MB until available from config page
+       karg.Information.ulMinRaidSetBlocks.uLowPart = 2048;
+       karg.Information.ulMinRaidSetBlocks.uHighPart = 0;
+       karg.Information.ulMaxRaidSetBlocks.uLowPart = 0xffffffff;
+       if( ioc->raid_data.pIocPg2->CapabilitiesFlags &
+           MPI_IOCPAGE2_CAP_FLAGS_RAID_64_BIT_ADDRESSING )
+               karg.Information.ulMaxRaidSetBlocks.uHighPart = 0xffffffff;
+       else
+               karg.Information.ulMaxRaidSetBlocks.uHighPart = 0;
+       karg.Information.uMaxPhysicalDrives =
+           ioc->raid_data.pIocPg2->MaxPhysDisks;
+       karg.Information.uMaxExtents = 1;
+       karg.Information.uMaxModules = 0;
+       karg.Information.uMaxTransformationMemory = 0;
+       karg.Information.uChangeCount = ioc->csmi_change_count;
+       karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS;
+
+csmisas_get_raid_info_out:
+
+       /* Copy the data from kernel memory to user memory
+        */
+       if (copy_to_user(uarg, &karg,
+                               sizeof(CSMI_SAS_RAID_INFO_BUFFER))) {
+               printk(KERN_ERR "%s@%d::%s() - "
+                       "Unable to write out csmi_sas_get_raid_info @ %p\n",
+                               __FILE__, __LINE__, __FUNCTION__, uarg);
+               return -EFAULT;
+       }
+
+       dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__));
+       return 0;
+}
+
+/**
+ *     csmisas_do_raid - Format and Issue a RAID volume request message.
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @action: What do be done.
+ *     @PhysDiskNum: Logical target id.
+ *     @VolumeBus: Target locations bus.
+ *     @VolumeId: Volume id
+ *
+ *     Returns: < 0 on a fatal error
+ *             0 on success
+ *
+ *     Remark: Wait to return until reply processed by the ISR.
+ **/
+static int
+csmisas_do_raid(MPT_ADAPTER *ioc, u8 action, u8 PhysDiskNum, u8 VolumeBus, u8 VolumeId, pMpiRaidActionReply_t reply)
+{
+       MpiRaidActionRequest_t  *pReq;
+       MpiRaidActionReply_t    *pReply;
+       MPT_FRAME_HDR           *mf;
+
+       /* Get and Populate a free Frame
+        */
+       if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL) {
+               dcsmisasprintk(ioc, printk(KERN_ERR ": no msg frames!\n"));
+               return -EAGAIN;
+       }
+       pReq = (MpiRaidActionRequest_t *)mf;
+       pReq->Action = action;
+       pReq->Reserved1 = 0;
+       pReq->ChainOffset = 0;
+       pReq->Function = MPI_FUNCTION_RAID_ACTION;
+       pReq->VolumeID = VolumeId;
+       pReq->VolumeBus = VolumeBus;
+       pReq->PhysDiskNum = PhysDiskNum;
+       pReq->MsgFlags = 0;
+       pReq->Reserved2 = 0;
+       pReq->ActionDataWord = 0; /* Reserved for this action */
+       //pReq->ActionDataSGE = 0;
+
+       ioc->add_sge((char *)&pReq->ActionDataSGE,
+               MPT_SGE_FLAGS_SSIMPLE_READ | 0, (dma_addr_t) -1);
+
+       if (csmisas_send_command_wait(ioc, mf, MPT_IOCTL_DEFAULT_TIMEOUT) != 0)
+               return -ENODATA;
+
+       if ((ioc->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID) &&
+           (reply != NULL)){
+               pReply = (MpiRaidActionReply_t *)&(ioc->ioctl_cmds.reply);
+               memcpy(reply, pReply,
+                       min(ioc->reply_sz,
+                       4*pReply->MsgLength));
+       }
+
+       return 0;
+}
+
+/**
+ * csmisas_raid_inq
+ * @ioc = per host instance
+ * @opcode = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH or
+ *          MPI_FUNCTION_SCSI_IO_REQUEST
+ * @id = target id
+ * @bus = target bus
+ * @inq_vpd = inquiry data, returned
+ * @inq_vpd_sz = maximum size of inquiry data
+ *
+ * Return = 0(sucess), non-zero(failure)
+ **/
+static int
+csmisas_raid_inq(MPT_ADAPTER *ioc, u8 opcode, u8 bus, u8 id, u8 inq_vpd_page,
+    u8 * inq_vpd, u32 inq_vpd_sz)
+{
+       MPT_FRAME_HDR           *mf = NULL;
+       MPIHeader_t             *mpi_hdr;
+       pSCSIIORequest_t        pScsiRequest;
+       u16                     req_idx;
+       char                    *psge;
+       u8                      inq_vpd_cdb[6];
+       u8                      *request_data=NULL;
+       dma_addr_t              request_data_dma;
+       u32                     request_data_sz;
+       int                     rc = 0;
+       u32                     MsgContext;
+
+       request_data_sz = inq_vpd_sz;
+
+       /* fill-in cdb */
+       memset(inq_vpd_cdb, 0, sizeof(inq_vpd_cdb));
+       inq_vpd_cdb[0] = 0x12;
+       if (inq_vpd_page) {
+               inq_vpd_cdb[1] = 0x01; /* evpd bit */
+               inq_vpd_cdb[2] = inq_vpd_page;
+       }
+       inq_vpd_cdb[3] = (u8)(request_data_sz >> 8);
+       inq_vpd_cdb[4] = (u8)request_data_sz;
+
+       /* Get a free request frame and save the message context.
+        */
+       if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL) {
+               dcsmisasprintk(ioc, printk(KERN_ERR ": no msg frames!\n"));
+               goto csmisas_raid_inq_exit;
+       }
+
+       mpi_hdr = (MPIHeader_t *) mf;
+       MsgContext = mpi_hdr->MsgContext;
+       pScsiRequest = (pSCSIIORequest_t) mf;
+       req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
+
+       memset(pScsiRequest,0,sizeof(SCSIIORequest_t));
+       pScsiRequest->Function = opcode;
+       pScsiRequest->TargetID = id;
+       pScsiRequest->Bus = bus;
+       pScsiRequest->CDBLength = 6;
+       pScsiRequest->DataLength = cpu_to_le32(request_data_sz);
+       pScsiRequest->MsgContext = MsgContext;
+       memcpy(pScsiRequest->CDB,inq_vpd_cdb,pScsiRequest->CDBLength);
+       pScsiRequest->Control = cpu_to_le32(MPI_SCSIIO_CONTROL_READ);
+       pScsiRequest->Control |= cpu_to_le32(MPI_SCSIIO_CONTROL_SIMPLEQ);
+       pScsiRequest->MsgFlags = mpt_msg_flags();
+
+       /* setup sense
+        */
+       pScsiRequest->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
+       pScsiRequest->SenseBufferLowAddr = cpu_to_le32(ioc->sense_buf_low_dma +
+           (req_idx * MPT_SENSE_BUFFER_ALLOC));
+
+       request_data = pci_alloc_consistent(
+           ioc->pcidev, request_data_sz, &request_data_dma);
+
+       if (request_data == NULL) {
+               mpt_free_msg_frame(ioc, mf);
+               rc=-1;
+               goto csmisas_raid_inq_exit;
+       }
+
+       memset(request_data,0,request_data_sz);
+       psge = (char *)&pScsiRequest->SGL;
+       ioc->add_sge(psge, (MPT_SGE_FLAGS_SSIMPLE_READ | 0xFC) ,
+           request_data_dma);
+
+       if (csmisas_send_command_wait(ioc, mf, MPT_IOCTL_DEFAULT_TIMEOUT) != 0) {
+               rc=-1;
+               goto csmisas_raid_inq_exit;
+       }
+
+       /* copy the request_data */
+       memcpy(inq_vpd, request_data, request_data_sz);
+
+ csmisas_raid_inq_exit:
+
+       if (request_data)
+               pci_free_consistent(ioc->pcidev, request_data_sz,
+                   request_data, request_data_dma);
+
+       return rc;
+}
+
+/**
+ * Prototype Routine for the CSMI SAS Get RAID Config command.
+ *
+ * Outputs:    None.
+ * Return:     0 if successful
+ *             -EFAULT if data unavailable
+ *             -ENODEV if no such device/adapter
+ **/
+static int
+csmisas_get_raid_config(unsigned long arg)
+{
+       CSMI_SAS_RAID_CONFIG_BUFFER __user *uarg = (void __user *) arg;
+       CSMI_SAS_RAID_CONFIG_BUFFER      karg,*pKarg=NULL;
+       CONFIGPARMS                     cfg;
+       ConfigPageHeader_t              header;
+       MPT_ADAPTER                     *ioc = NULL;
+       int                             iocnum;
+       u8                              volumeID, VolumeBus;
+       u8                              physDiskNum, physDiskNumMax;
+       int                             volumepage0sz = 0;
+       int                             physdiskpage0sz = 0, ioc_page5_sz = 0;
+       dma_addr_t                      volume0_dma, physdisk0_dma;
+       dma_addr_t                      ioc_page5_dma = 0;
+       pRaidVolumePage0_t              pVolume0 = NULL;
+       pRaidPhysDiskPage0_t            pPhysDisk0 = NULL;
+       pMpiRaidActionReply_t           pRaidActionReply = NULL;
+       u32                             device_info = 0;
+       pIOCPage5_t                     pIocPage5 = NULL;
+       int                             i, idx, csmi_sas_raid_config_buffer_sz;
+       int                             memory_pages;
+       int                             copy_buffer_sz = 0;
+       u64                             totalMaxLBA, tmpTotalMaxLBA;
+       u64                             sas_address;
+       struct sas_device_info          *sas_info;
+
+       if (copy_from_user(&karg, uarg, sizeof(IOCTL_HEADER))) {
+               printk(KERN_ERR "%s@%d::%s() - "
+                   "Unable to read in csmisas_get_raid_config struct @ %p\n",
+                   __FILE__, __LINE__, __FUNCTION__, uarg);
+               return -EFAULT;
+       }
+
+       csmi_sas_raid_config_buffer_sz = karg.IoctlHeader.Length;
+       memory_pages = get_order(csmi_sas_raid_config_buffer_sz);
+       pKarg = (CSMI_SAS_RAID_CONFIG_BUFFER *)__get_free_pages(
+               GFP_KERNEL, memory_pages);
+       if (!pKarg){
+               printk(KERN_ERR "%s@%d::%s() - "
+                   "Unable to malloc RAID_CONFIG_BUFFER "
+                       "csmi_sas_raid_config_buffer_sz=%d memory_pages=%d\n",
+                       __FILE__, __LINE__, __FUNCTION__, 
+                       csmi_sas_raid_config_buffer_sz, memory_pages);
+               return -ENOMEM;
+       }
+       memset(pKarg, 0, sizeof(*pKarg));
+
+       if (copy_from_user(pKarg, uarg, csmi_sas_raid_config_buffer_sz)) {
+               printk(KERN_ERR "%s@%d::%s() - "
+                   "Unable to read in csmisas_get_raid_config struct @ %p\n",
+                   __FILE__, __LINE__, __FUNCTION__, uarg);
+               free_pages((unsigned long)pKarg, memory_pages);
+               return -EFAULT;
+       }
+
+       if (((iocnum = mpt_verify_adapter(pKarg->IoctlHeader.IOControllerNumber,
+           &ioc)) < 0) || (ioc == NULL)) {
+               printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n",
+                   __FILE__, __FUNCTION__, __LINE__, iocnum);
+               free_pages((unsigned long)pKarg, memory_pages);
+               return -ENODEV;
+       }
+
+       if (!csmisas_is_this_sas_cntr(ioc)) {
+               printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n",
+                   __FILE__, __FUNCTION__, __LINE__, iocnum);
+               free_pages((unsigned long)pKarg, memory_pages);
+               return -ENODEV;
+       }
+
+       dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__));
+
+       if (pKarg->Configuration.uChangeCount != 0 &&
+               pKarg->Configuration.uChangeCount != ioc->csmi_change_count ) {
+               pKarg->IoctlHeader.ReturnCode =
+                   CSMI_SAS_STATUS_INVALID_PARAMETER;
+               pKarg->Configuration.uFailureCode =
+                   CSMI_SAS_FAIL_CODE_CHANGE_COUNT_INVALID;
+               goto cim_get_raid_config_exit;
+       }
+
+       if (!ioc->raid_data.pIocPg2) {
+               karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+               goto cim_get_raid_config_exit;
+       }
+
+       /*
+        * Check to see if the input uRaidSetIndex is
+        * greater than the number of RAID sets
+        */
+       if (pKarg->Configuration.uRaidSetIndex >=
+           ioc->raid_data.pIocPg2->NumActiveVolumes) {
+               pKarg->IoctlHeader.ReturnCode = CSMI_SAS_RAID_SET_OUT_OF_RANGE;
+               goto cim_get_raid_config_exit;
+       }
+
+       /*
+        * get RAID Volume Page 0
+        */
+       volumeID = ioc->raid_data.pIocPg2->RaidVolume[pKarg->Configuration.uRaidSetIndex].VolumeID;
+       VolumeBus = ioc->raid_data.pIocPg2->RaidVolume[pKarg->Configuration.uRaidSetIndex].VolumeBus;
+
+       header.PageVersion = 0;
+       header.PageLength = 0;
+       header.PageNumber = 0;
+       header.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
+       cfg.cfghdr.hdr = &header;
+       cfg.physAddr = -1;
+       cfg.pageAddr = (VolumeBus << 8) + volumeID;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+       cfg.dir = 0;
+       cfg.timeout = MPT_IOCTL_DEFAULT_TIMEOUT;
+       if (mpt_config(ioc, &cfg) != 0) {
+               pKarg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+               goto cim_get_raid_config_exit;
+       }
+
+       if (header.PageLength == 0) {
+               pKarg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+               goto cim_get_raid_config_exit;
+       }
+
+       volumepage0sz = header.PageLength * 4;
+       pVolume0 = pci_alloc_consistent(ioc->pcidev, volumepage0sz,
+           &volume0_dma);
+       if (!pVolume0) {
+               pKarg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+               goto cim_get_raid_config_exit;
+       }
+
+       cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+       cfg.physAddr = volume0_dma;
+       if (mpt_config(ioc, &cfg) != 0) {
+               pKarg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+               goto cim_get_raid_config_exit;
+       }
+
+       totalMaxLBA = (u64)le32_to_cpu(pVolume0->MaxLBA) |
+           ((u64)le32_to_cpu(pVolume0->MaxLBAHigh)) << 32;
+       tmpTotalMaxLBA = totalMaxLBA + 1;
+       do_div(tmpTotalMaxLBA, 2048);
+       pKarg->Configuration.bDriveCount = 0;
+       pKarg->Configuration.uCapacity = tmpTotalMaxLBA;
+       pKarg->Configuration.uStripeSize =
+               le32_to_cpu(pVolume0->StripeSize)/2;
+
+       switch(pVolume0->VolumeType) {
+       case MPI_RAID_VOL_TYPE_IS:
+               pKarg->Configuration.bRaidType = CSMI_SAS_RAID_TYPE_0;
+               break;
+       case MPI_RAID_VOL_TYPE_IME:
+               pKarg->Configuration.bRaidType = CSMI_SAS_RAID_TYPE_10;
+               break;
+       case MPI_RAID_VOL_TYPE_IM:
+               pKarg->Configuration.bRaidType = CSMI_SAS_RAID_TYPE_1;
+               break;
+       default:
+               pKarg->Configuration.bRaidType = CSMI_SAS_RAID_TYPE_OTHER;
+               break;
+       }
+
+       switch (pVolume0->VolumeStatus.State) {
+       case MPI_RAIDVOL0_STATUS_STATE_OPTIMAL:
+               pKarg->Configuration.bStatus = CSMI_SAS_RAID_SET_STATUS_OK;
+               break;
+       case MPI_RAIDVOL0_STATUS_STATE_DEGRADED:
+               /* Volume is degraded, check if Resyncing or Inactive */
+               pKarg->Configuration.bStatus = CSMI_SAS_RAID_SET_STATUS_DEGRADED;
+               break;
+       case MPI_RAIDVOL0_STATUS_STATE_FAILED:
+               pKarg->Configuration.bStatus = CSMI_SAS_RAID_SET_STATUS_FAILED;
+               break;
+       }
+
+       /* check flags */
+       if (pVolume0->VolumeStatus.Flags &
+           MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE)
+               pKarg->Configuration.bStatus = CSMI_SAS_RAID_SET_STATUS_OFFLINE;
+       else if (pVolume0->VolumeStatus.Flags &
+           MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS)
+               pKarg->Configuration.bStatus = CSMI_SAS_RAID_SET_STATUS_REBUILDING;
+
+       pKarg->Configuration.bInformation = 0;  /* default */
+       if(pVolume0->VolumeStatus.Flags &
+           MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS ) {
+
+               uint64_t        * ptrUint64;
+               uint64_t        totalBlocks64, blocksRemaining64;
+               uint32_t        totalBlocks32, blocksRemaining32;
+
+               /* get percentage complete */
+               pRaidActionReply = kmalloc( sizeof(MPI_RAID_VOL_INDICATOR) +
+                   offsetof(MSG_RAID_ACTION_REPLY,ActionData),
+                   GFP_KERNEL);
+
+               if (!pRaidActionReply){
+                       printk(KERN_ERR "%s@%d::%s() - "
+                           "Unable to malloc @ %p\n",
+                           __FILE__, __LINE__, __FUNCTION__,pKarg);
+                       goto cim_get_raid_config_exit;
+               }
+               memset(pRaidActionReply, 0, sizeof(*pRaidActionReply));
+
+               csmisas_do_raid(ioc,
+                   MPI_RAID_ACTION_INDICATOR_STRUCT,
+                   0, VolumeBus, volumeID, pRaidActionReply);
+
+               ptrUint64       = (uint64_t *)&pRaidActionReply->ActionData;
+               totalBlocks64     = *ptrUint64;
+               ptrUint64++;
+               blocksRemaining64 = *ptrUint64;
+               while(totalBlocks64 > 0xFFFFFFFFUL){
+                       totalBlocks64 = totalBlocks64 >> 1;
+                       blocksRemaining64 = blocksRemaining64 >> 1;
+               }
+               totalBlocks32 = (uint32_t)totalBlocks64;
+               blocksRemaining32 = (uint32_t)blocksRemaining64;
+
+               if(totalBlocks32)
+                       pKarg->Configuration.bInformation =
+                           (totalBlocks32 - blocksRemaining32) /
+                           (totalBlocks32 / 100);
+
+               kfree(pRaidActionReply);
+       }
+
+       /* fill-in more information depending on data type */
+       if (pKarg->Configuration.bDataType ==
+           CSMI_SAS_RAID_DATA_ADDITIONAL_DATA) {
+               pKarg->Configuration.Data->bLabel[0] = '\0';
+               pKarg->Configuration.Data->bRaidSetLun[1] = 0;
+               pKarg->Configuration.Data->bWriteProtection =
+                       CSMI_SAS_RAID_SET_WRITE_PROTECT_UNKNOWN;
+               pKarg->Configuration.Data->bCacheSetting =
+                       CSMI_SAS_RAID_SET_CACHE_UNKNOWN;
+               pKarg->Configuration.Data->bCacheRatio = 0;
+               pKarg->Configuration.Data->usBlockSize = 512;
+               pKarg->Configuration.Data->ulRaidSetExtentOffset.uLowPart = 0;
+               pKarg->Configuration.Data->ulRaidSetExtentOffset.uHighPart = 0;
+               pKarg->Configuration.Data->ulRaidSetBlocks.uLowPart =
+                   le32_to_cpu(pVolume0->MaxLBA);
+               pKarg->Configuration.Data->ulRaidSetBlocks.uHighPart =
+                   le32_to_cpu(pVolume0->MaxLBAHigh);
+               if (pVolume0->VolumeType == MPI_RAID_VOL_TYPE_IS ||
+                   pVolume0->VolumeType == MPI_RAID_VOL_TYPE_IME ) {
+                       pKarg->Configuration.Data->uStripeSizeInBlocks =
+                           le32_to_cpu(pVolume0->StripeSize);
+               } else {
+                       pKarg->Configuration.Data->uStripeSizeInBlocks = 0;
+               }
+               pKarg->Configuration.Data->uSectorsPerTrack = 128;
+               for (i=0; i<16; i++) {
+                       // unsupported
+                       pKarg->Configuration.Data->bApplicationScratchPad[i] =
+                           0xFF;
+               }
+               pKarg->Configuration.Data->uNumberOfHeads = 16;
+
+               tmpTotalMaxLBA = totalMaxLBA;
+               do_div(tmpTotalMaxLBA,
+                   (pKarg->Configuration.Data->uNumberOfHeads *
+                    pKarg->Configuration.Data->uSectorsPerTrack));
+               pKarg->Configuration.Data->uNumberOfTracks = tmpTotalMaxLBA;
+       } else if ( pKarg->Configuration.bDataType ==
+           CSMI_SAS_RAID_DATA_DEVICE_ID ) {
+               /* Send inquiry to get VPD Page 0x83 */
+               u32 vpd_page_sz;
+               vpd_page_sz = csmi_sas_raid_config_buffer_sz -
+                   offsetof(CSMI_SAS_RAID_CONFIG,DeviceId);
+               if (csmisas_raid_inq(ioc, MPI_FUNCTION_SCSI_IO_REQUEST,
+                       VolumeBus, volumeID, 0x83,
+                       (u8*)&pKarg->Configuration.DeviceId->bDeviceIdentificationVPDPage,
+                       vpd_page_sz) != 0) {
+                       pKarg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+                       goto cim_get_raid_config_exit;
+               }
+       } else {
+               /* suppress drive information */
+               if (pKarg->Configuration.bDriveCount ==
+                       CSMI_SAS_RAID_DRIVE_COUNT_SUPRESSED) {
+                       pKarg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS;
+                       goto cim_get_raid_config_exit;
+               }
+       }
+
+       /* get hotspare info, used later in this function */
+       if (pVolume0->VolumeSettings.HotSparePool) {
+               /* Read and save IOC Page 5
+                */
+               header.PageVersion = 0;
+               header.PageLength = 0;
+               header.PageNumber = 5;
+               header.PageType = MPI_CONFIG_PAGETYPE_IOC;
+               cfg.cfghdr.hdr = &header;
+               cfg.physAddr = -1;
+               cfg.pageAddr = 0;
+               cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+               cfg.dir = 0;
+               cfg.timeout = MPT_IOCTL_DEFAULT_TIMEOUT;
+               if ((mpt_config(ioc, &cfg) == 0) && (header.PageLength)) {
+                       ioc_page5_sz = header.PageLength * 4;
+                       pIocPage5 = pci_alloc_consistent(ioc->pcidev,
+                           ioc_page5_sz,
+                           &ioc_page5_dma);
+                       memset(pIocPage5,0,ioc_page5_sz);
+                       if (ioc_page5_dma) {
+                               cfg.physAddr = ioc_page5_dma;
+                               cfg.action =
+                                   MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+                               mpt_config(ioc, &cfg);
+                       }
+               }
+       }
+
+       /*
+        * get RAID Physical Disk Page 0
+        */
+       header.PageVersion = 0;
+       header.PageLength = 0;
+       header.PageNumber = 0;
+       header.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
+       cfg.cfghdr.hdr = &header;
+       cfg.physAddr = -1;
+       cfg.pageAddr = 0;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+       cfg.dir = 0;
+       cfg.timeout = MPT_IOCTL_DEFAULT_TIMEOUT;
+       if (mpt_config(ioc, &cfg) != 0) {
+               pKarg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+               goto cim_get_raid_config_exit;
+       }
+
+       if (header.PageLength == 0) {
+               pKarg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+               goto cim_get_raid_config_exit;
+       }
+
+       physdiskpage0sz = header.PageLength * 4;
+       pPhysDisk0 = pci_alloc_consistent(ioc->pcidev, physdiskpage0sz,
+           &physdisk0_dma);
+       if (!pPhysDisk0) {
+               pKarg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+               goto cim_get_raid_config_exit;
+       }
+       cfg.physAddr = physdisk0_dma;
+
+       physDiskNumMax = (csmi_sas_raid_config_buffer_sz -
+           offsetof(CSMI_SAS_RAID_CONFIG,Drives))
+           / sizeof(CSMI_SAS_RAID_DRIVES);
+
+       tmpTotalMaxLBA = totalMaxLBA;
+       if (pVolume0->VolumeType == MPI_RAID_VOL_TYPE_IS) {
+               do_div(tmpTotalMaxLBA, pVolume0->NumPhysDisks);
+               dcsmisasprintk(ioc, printk(KERN_DEBUG "IS Volume tmpTotalMaxLBA=%llX\n",
+               (unsigned long long)tmpTotalMaxLBA));
+       }
+       else if (pVolume0->VolumeType == MPI_RAID_VOL_TYPE_IME) {
+               do_div(tmpTotalMaxLBA, pVolume0->NumPhysDisks * 2);
+               dcsmisasprintk(ioc, printk(KERN_DEBUG "IME Volume tmpTotalMaxLBA=%llX\n",
+               (unsigned long long)tmpTotalMaxLBA));
+       } else {
+               dcsmisasprintk(ioc, printk(KERN_DEBUG "IM Volume tmpTotalMaxLBA=%llX\n",
+               (unsigned long long)tmpTotalMaxLBA));
+       }
+
+       for (i=0; i< min(pVolume0->NumPhysDisks, physDiskNumMax); i++) {
+
+               physDiskNum = pVolume0->PhysDisk[i].PhysDiskNum;
+               cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+               cfg.pageAddr = physDiskNum;
+               if (mpt_config(ioc, &cfg) != 0){
+                       pKarg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+                       goto cim_get_raid_config_exit;
+               }
+
+               pKarg->Configuration.bDriveCount++;
+               if (pKarg->Configuration.bDataType != CSMI_SAS_RAID_DATA_DRIVES)
+                       continue;
+
+               /* Search the list for the matching SAS address. */
+               sas_info = csmisas_get_device_component_by_fw(ioc, pPhysDisk0->PhysDiskBus,
+                   pPhysDisk0->PhysDiskID);
+               if (sas_info) {
+                       sas_address = reverse_byte_order64(sas_info->sas_address);
+                       memcpy(pKarg->Configuration.Drives[i].bSASAddress,
+                          &sas_address,sizeof(u64));
+                       if (!device_info)
+                               device_info = sas_info->device_info;
+               }
+
+               memcpy(pKarg->Configuration.Drives[i].bModel,
+                   pPhysDisk0->InquiryData.VendorID,
+                   offsetof(RAID_PHYS_DISK0_INQUIRY_DATA,ProductRevLevel));
+               memcpy(pKarg->Configuration.Drives[i].bFirmware,
+                       pPhysDisk0->InquiryData.ProductRevLevel,
+                       sizeof(pPhysDisk0->InquiryData.ProductRevLevel));
+               if (csmisas_is_sata(pPhysDisk0)) {
+                       memcpy(&pKarg->Configuration.Drives[i].bSerialNumber,
+                               &pPhysDisk0->ExtDiskIdentifier[4],
+                               4);
+                       memcpy(&pKarg->Configuration.Drives[i].bSerialNumber[4],
+                               &pPhysDisk0->DiskIdentifier,
+                               sizeof(pPhysDisk0->DiskIdentifier));
+               } else {
+                       memcpy(pKarg->Configuration.Drives[i].bSerialNumber,
+                               pPhysDisk0->DiskIdentifier,
+                               sizeof(pPhysDisk0->DiskIdentifier));
+               }
+
+               pKarg->Configuration.Drives[i].bDriveUsage =
+                   (pPhysDisk0->PhysDiskStatus.Flags &
+                   MPI_PHYSDISK0_STATUS_FLAG_INACTIVE_VOLUME) ?
+                   CSMI_SAS_DRIVE_CONFIG_NOT_USED :
+                   CSMI_SAS_DRIVE_CONFIG_MEMBER;
+
+               pKarg->Configuration.Drives[i].bDriveStatus =
+                   CSMI_SAS_DRIVE_STATUS_OK;
+               if (pPhysDisk0->PhysDiskStatus.State ==
+                   MPI_PHYSDISK0_STATUS_OFFLINE_REQUESTED) {
+                       pKarg->Configuration.Drives[i].bDriveStatus =
+                           CSMI_SAS_DRIVE_STATUS_OFFLINE;
+               } else if(pPhysDisk0->PhysDiskStatus.State) {
+                       pKarg->Configuration.Drives[i].bDriveStatus =
+                           CSMI_SAS_DRIVE_STATUS_FAILED;
+                       if(pKarg->Configuration.bStatus ==
+                           CSMI_SAS_RAID_SET_STATUS_DEGRADED)
+                               pKarg->Configuration.bInformation = i;
+               } else if((pVolume0->VolumeStatus.Flags &
+                   MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS) &&
+                   (pPhysDisk0->PhysDiskStatus.Flags &
+                   MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC))
+                       pKarg->Configuration.Drives[i].bDriveStatus =
+                           CSMI_SAS_DRIVE_STATUS_REBUILDING;
+               else if(pPhysDisk0->ErrorData.SmartCount ||
+                   (pPhysDisk0->PhysDiskStatus.Flags &
+                   MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC))
+                       pKarg->Configuration.Drives[i].bDriveStatus =
+                       CSMI_SAS_DRIVE_STATUS_DEGRADED;
+
+               memset(pKarg->Configuration.Drives[i].bSASLun,
+                   0, sizeof(pKarg->Configuration.Drives[i].bSASLun));
+               if (csmisas_is_sata(pPhysDisk0)) {
+                       pKarg->Configuration.Drives[i].bDriveType =
+                       CSMI_SAS_DRIVE_TYPE_SATA;
+               } else { /* drive in a volume can only be SAS/SATA */
+                       pKarg->Configuration.Drives[i].bDriveType =
+                               CSMI_SAS_DRIVE_TYPE_SINGLE_PORT_SAS;
+                       if (mpt_raid_phys_disk_get_num_paths(ioc,
+                           pVolume0->PhysDisk[i].PhysDiskNum) > 1)
+                                       pKarg->Configuration.Drives[i].bDriveType =
+                                           CSMI_SAS_DRIVE_TYPE_DUAL_PORT_SAS;
+               }
+
+               pKarg->Configuration.Drives[i].usBlockSize = 512;
+                       pKarg->Configuration.Drives[i].uDriveIndex =
+                           pPhysDisk0->PhysDiskNum;
+               pKarg->Configuration.Drives[i].ulTotalUserBlocks.uLowPart =
+                   (u32)tmpTotalMaxLBA;
+               pKarg->Configuration.Drives[i].ulTotalUserBlocks.uHighPart =
+                   (u32)(tmpTotalMaxLBA >> 32);
+       }
+
+       /* adding hot spare info at the end */
+       if ((pVolume0->VolumeSettings.HotSparePool) && (pIocPage5) &&
+           (pVolume0->VolumeType != MPI_RAID_VOL_TYPE_IS)) {
+               for (idx = 0, i = pVolume0->NumPhysDisks ;
+                   idx < pIocPage5->NumHotSpares ; idx++) {
+                       if (i >= physDiskNumMax)
+                               break;
+                       if ((pVolume0->VolumeSettings.HotSparePool &
+                           pIocPage5->HotSpare[idx].HotSparePool) == 0)
+                               continue;
+                       if(pIocPage5->HotSpare[idx].Flags !=
+                           MPI_IOC_PAGE_5_HOT_SPARE_ACTIVE)
+                           continue;
+                       physDiskNum = pIocPage5->HotSpare[idx].PhysDiskNum;
+                       cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+                       cfg.pageAddr = physDiskNum;
+                       if (mpt_config(ioc, &cfg) != 0)
+                               continue;
+
+                       /* don't mix SSP hot spare
+                        * in SATA volume
+                        */
+                       if (!csmisas_is_sata(pPhysDisk0) &&
+                           (device_info &
+                           MPI_SAS_DEVICE_INFO_SATA_DEVICE))
+                               continue;
+
+                       /* don't mix SATA hot spare
+                        * in SSP volume
+                        */
+                       if (csmisas_is_sata(pPhysDisk0) &&
+                           (device_info &
+                           MPI_SAS_DEVICE_INFO_SSP_TARGET))
+                               continue;
+
+                       /* capacity check for IM volumes*/
+                       if ((pVolume0->VolumeType ==
+                           MPI_RAID_VOL_TYPE_IM) &&
+                           (totalMaxLBA +
+                           (64*2*1024) /* metadata = 64MB*/ >
+                           le32_to_cpu(pPhysDisk0->MaxLBA)))
+                               continue;
+
+                       tmpTotalMaxLBA = totalMaxLBA;
+                       do_div(tmpTotalMaxLBA, pVolume0->NumPhysDisks);
+                       /* capacity check for IME volumes*/
+                       if ((pVolume0->VolumeType ==
+                           MPI_RAID_VOL_TYPE_IME) &&
+                           (((totalMaxLBA +
+                           pVolume0->NumPhysDisks) * 2) +
+                           (64*2*1024 ) /*metadata = 64MB*/ >
+                           le32_to_cpu(pPhysDisk0->MaxLBA)))
+                               continue;
+
+                       pKarg->Configuration.bDriveCount++;
+                       if (pKarg->Configuration.bDataType !=
+                           CSMI_SAS_RAID_DATA_DRIVES) {
+                               i++;
+                               continue;
+                       }
+
+                       /* Search the list for the matching SAS address. */
+                       sas_info = csmisas_get_device_component_by_fw(ioc,
+                           pPhysDisk0->PhysDiskBus, pPhysDisk0->PhysDiskID);
+                       if (sas_info) {
+                               sas_address = reverse_byte_order64(sas_info->sas_address);
+                               memcpy(pKarg->Configuration.Drives[i].bSASAddress,
+                                  &sas_address,sizeof(u64));
+                       }
+
+                       memcpy(pKarg->Configuration.Drives[i].bModel,
+                           pPhysDisk0->InquiryData.VendorID,
+                           offsetof(RAID_PHYS_DISK0_INQUIRY_DATA,ProductRevLevel));
+                       memcpy(pKarg->Configuration.Drives[i].bFirmware,
+                               pPhysDisk0->InquiryData.ProductRevLevel,
+                               sizeof(pPhysDisk0->InquiryData.ProductRevLevel));
+                       if (csmisas_is_sata(pPhysDisk0)) {
+                               memcpy(&pKarg->Configuration.Drives[i].bSerialNumber,
+                                       &pPhysDisk0->ExtDiskIdentifier[4],
+                                       4);
+                               memcpy(&pKarg->Configuration.Drives[i].bSerialNumber[4],
+                                       &pPhysDisk0->DiskIdentifier,
+                                       sizeof(pPhysDisk0->DiskIdentifier));
+                       } else {
+                               memcpy(pKarg->Configuration.Drives[i].bSerialNumber,
+                                       pPhysDisk0->DiskIdentifier,
+                                       sizeof(pPhysDisk0->DiskIdentifier));
+                       }
+                       pKarg->Configuration.Drives[i].bDriveStatus =
+                           CSMI_SAS_DRIVE_STATUS_OK;
+                       if(pPhysDisk0->PhysDiskStatus.State)
+                               pKarg->Configuration.Drives[i].bDriveStatus =
+                                   CSMI_SAS_DRIVE_STATUS_FAILED;
+                       else if(pPhysDisk0->ErrorData.SmartCount)
+                               pKarg->Configuration.Drives[i].bDriveStatus =
+                                   CSMI_SAS_DRIVE_STATUS_DEGRADED;
+                       pKarg->Configuration.Drives[i].bDriveUsage =
+                           CSMI_SAS_DRIVE_CONFIG_SPARE;
+                       pKarg->Configuration.Drives[i].usBlockSize = 512;
+                       pKarg->Configuration.Drives[i].uDriveIndex =
+                           pPhysDisk0->PhysDiskNum;
+                       if (csmisas_is_sata(pPhysDisk0)) {
+                               pKarg->Configuration.Drives[i].bDriveType =
+                               CSMI_SAS_DRIVE_TYPE_SATA;
+                       } else { /* drive in a volume can only be SAS/SATA */
+                               pKarg->Configuration.Drives[i].bDriveType =
+                                       CSMI_SAS_DRIVE_TYPE_SINGLE_PORT_SAS;
+                               if (mpt_raid_phys_disk_get_num_paths(ioc,
+                                   pVolume0->PhysDisk[i].PhysDiskNum) > 1)
+                                       pKarg->Configuration.Drives[i].bDriveType =
+                                           CSMI_SAS_DRIVE_TYPE_DUAL_PORT_SAS;
+                       }
+                       i++;
+               }
+       }
+
+       // Only return data on the first 240 drives
+       if( pKarg->Configuration.bDriveCount > 0xF0 )
+               pKarg->Configuration.bDriveCount =
+                   CSMI_SAS_RAID_DRIVE_COUNT_TOO_BIG;
+
+       pKarg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS;
+
+ cim_get_raid_config_exit:
+
+       if (pVolume0 != NULL)
+               pci_free_consistent(ioc->pcidev, volumepage0sz, pVolume0,
+                   volume0_dma);
+
+       if(pPhysDisk0 != NULL)
+               pci_free_consistent(ioc->pcidev, physdiskpage0sz, pPhysDisk0,
+                   physdisk0_dma);
+
+       if(pIocPage5 != NULL)
+               pci_free_consistent(ioc->pcidev, ioc_page5_sz, pIocPage5,
+                   ioc_page5_dma);
+
+       /* Copy the data from kernel memory to user memory
+        */
+
+       /* find the buffer size to copy depending on how much is filled-in */
+       switch (pKarg->Configuration.bDataType) {
+       case CSMI_SAS_RAID_DATA_ADDITIONAL_DATA:
+               copy_buffer_sz = sizeof(IOCTL_HEADER) +
+                   offsetof(CSMI_SAS_RAID_CONFIG,Data) +
+                   sizeof(CSMI_SAS_RAID_SET_ADDITIONAL_DATA);
+               break;
+       case CSMI_SAS_RAID_DATA_DRIVES:
+               if (pKarg->Configuration.bDriveCount ==
+                   CSMI_SAS_RAID_DRIVE_COUNT_SUPRESSED)
+                       copy_buffer_sz = sizeof(IOCTL_HEADER) +
+                           offsetof(CSMI_SAS_RAID_CONFIG,Drives);
+               else
+                       copy_buffer_sz = sizeof(IOCTL_HEADER) +
+                           offsetof(CSMI_SAS_RAID_CONFIG,Drives) +
+                           (pKarg->Configuration.bDriveCount *
+                           sizeof(CSMI_SAS_RAID_DRIVES));
+               break;
+       case CSMI_SAS_RAID_DATA_DEVICE_ID:
+               copy_buffer_sz = csmi_sas_raid_config_buffer_sz;
+               break;
+       }
+
+       if (copy_to_user(uarg, pKarg, copy_buffer_sz)) {
+               printk(KERN_ERR "%s@%d::%s() - "
+                      "Unable to write out csmi_sas_get_raid_config @ %p\n",
+                          __FILE__, __LINE__, __FUNCTION__, uarg);
+               free_pages((unsigned long)pKarg, memory_pages);
+               return -EFAULT;
+       }
+
+       dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__));
+       free_pages((unsigned long)pKarg, memory_pages);
+       return 0;
+}
+
+/**
+ * Prototype Routine for the CSMI SAS Get RAID Features command.
+ *
+ * Outputs:    None.
+ * Return:     0 if successful
+ *             -EFAULT if data unavailable
+ *             -ENODEV if no such device/adapter
+ **/
+static int
+csmisas_get_raid_features(unsigned long arg)
+{
+       CSMI_SAS_RAID_FEATURES_BUFFER __user *uarg = (void __user *) arg;
+       CSMI_SAS_RAID_FEATURES_BUFFER karg, *pKarg=NULL;
+       int csmi_sas_raid_features_buffer_sz, iocnum;
+       int                             memory_pages;
+       MPT_ADAPTER             *ioc = NULL;
+
+       if (copy_from_user(&karg, uarg, sizeof(IOCTL_HEADER))) {
+               printk(KERN_ERR "%s@%d::%s() - "
+                   "Unable to read in csmi_sas_get_raid_features struct @ %p\n",
+                   __FILE__, __LINE__, __FUNCTION__, uarg);
+               return -EFAULT;
+       }
+
+       csmi_sas_raid_features_buffer_sz = karg.IoctlHeader.Length;
+       memory_pages = get_order(csmi_sas_raid_features_buffer_sz);
+       pKarg = (CSMI_SAS_RAID_FEATURES_BUFFER *)__get_free_pages(
+               GFP_KERNEL, memory_pages);
+       if (!pKarg){
+               printk(KERN_ERR "%s@%d::%s() - "
+                   "Unable to malloc RAID_FEATURES_BUFFER "
+                       "csmi_sas_raid_features_buffer_sz=%d memory_pages=%d\n",
+                       __FILE__, __LINE__, __FUNCTION__, 
+                       csmi_sas_raid_features_buffer_sz, memory_pages);
+               return -ENOMEM;
+       }
+       memset(pKarg, 0, sizeof(*pKarg));
+
+       if (copy_from_user(pKarg, uarg, csmi_sas_raid_features_buffer_sz)) {
+               printk(KERN_ERR "%s@%d::%s() - "
+                   "Unable to read in csmi_sas_get_raid_features struct @ %p\n",
+                   __FILE__, __LINE__, __FUNCTION__, uarg);
+               free_pages((unsigned long)pKarg, memory_pages);
+               return -EFAULT;
+       }
+
+       if (((iocnum = mpt_verify_adapter(pKarg->IoctlHeader.IOControllerNumber,
+           &ioc)) < 0) || (ioc == NULL)) {
+               printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n",
+                   __FILE__, __FUNCTION__, __LINE__, iocnum);
+               free_pages((unsigned long)pKarg, memory_pages);
+               return -ENODEV;
+       }
+
+       if (!csmisas_is_this_sas_cntr(ioc)) {
+               printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n",
+                   __FILE__, __FUNCTION__, __LINE__, iocnum);
+               free_pages((unsigned long)pKarg, memory_pages);
+               return -ENODEV;
+       }
+
+       dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__));
+
+       if (pKarg->Information.uChangeCount != 0 &&
+           pKarg->Information.uChangeCount != ioc->csmi_change_count ) {
+               pKarg->IoctlHeader.ReturnCode =
+                   CSMI_SAS_STATUS_INVALID_PARAMETER;
+               pKarg->Information.uFailureCode =
+                   CSMI_SAS_FAIL_CODE_CHANGE_COUNT_INVALID;
+               goto cim_get_raid_features_exit;
+       }
+
+       pKarg->Information.uFeatures = CSMI_SAS_RAID_FEATURE_REBUILD |
+           CSMI_SAS_RAID_FEATURE_SURFACE_SCAN |
+           CSMI_SAS_RAID_FEATURE_SPARES_SHARED;
+       pKarg->Information.bDefaultTransformPriority =
+           CSMI_SAS_PRIORITY_UNKNOWN;
+       pKarg->Information.bTransformPriority = CSMI_SAS_PRIORITY_UNKNOWN;
+       pKarg->Information.bDefaultRebuildPriority = CSMI_SAS_PRIORITY_UNKNOWN;
+       pKarg->Information.bRebuildPriority =
+           pKarg->Information.bDefaultRebuildPriority;
+       pKarg->Information.bDefaultSurfaceScanPriority =
+           CSMI_SAS_PRIORITY_UNKNOWN;
+       pKarg->Information.bSurfaceScanPriority = CSMI_SAS_PRIORITY_UNKNOWN;
+       pKarg->Information.uRaidSetTransformationRules = 0;
+
+        /* IS */
+       pKarg->Information.RaidType[0].bRaidType = CSMI_SAS_RAID_TYPE_0;
+       pKarg->Information.RaidType[0].uSupportedStripeSizeMap = 0x80;
+
+       /* IM */
+       pKarg->Information.RaidType[1].bRaidType = CSMI_SAS_RAID_TYPE_1;
+       pKarg->Information.RaidType[1].uSupportedStripeSizeMap = 0;
+
+       /* IME */
+       pKarg->Information.RaidType[2].bRaidType = CSMI_SAS_RAID_TYPE_1E;
+       pKarg->Information.RaidType[2].uSupportedStripeSizeMap = 0x80;
+
+       pKarg->Information.RaidType[3].bRaidType = CSMI_SAS_RAID_TYPE_END;
+       pKarg->Information.bCacheRatiosSupported[0] =
+           CSMI_SAS_RAID_CACHE_RATIO_END;
+
+ cim_get_raid_features_exit:
+
+       /*
+        * Copy the data from kernel memory to user memory
+        */
+       if (copy_to_user(uarg, pKarg,
+           sizeof(CSMI_SAS_RAID_FEATURES_BUFFER))) {
+               printk(KERN_ERR "%s@%d::%s() - "
+               "Unable to write out csmi_sas_get_raid_features @ %p\n",
+               __FILE__, __LINE__, __FUNCTION__, uarg);
+               free_pages((unsigned long)pKarg, memory_pages);
+               return -EFAULT;
+       }
+
+       dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__));
+       free_pages((unsigned long)pKarg, memory_pages);
+       return 0;
+}
+
+/**
+ * Prototype Routine for the CSMI SAS Set RAID Control command.
+ *
+ * Outputs:    None.
+ * Return:     0 if successful
+ *             -EFAULT if data unavailable
+ *             -ENODEV if no such device/adapter
+ **/
+static int
+csmisas_set_raid_control(unsigned long arg)
+{
+       CSMI_SAS_RAID_CONTROL_BUFFER __user *uarg = (void __user *) arg;
+       CSMI_SAS_RAID_CONTROL_BUFFER karg, *pKarg=NULL;
+       int csmi_sas_raid_control_buffer_sz, iocnum;
+       int                             memory_pages;
+       MPT_ADAPTER     *ioc = NULL;
+
+       if (copy_from_user(&karg, uarg, sizeof(IOCTL_HEADER))) {
+               printk(KERN_ERR "%s@%d::%s() - "
+                   "Unable to read in csmi_sas_set_raid_control struct @ %p\n",
+                   __FILE__, __LINE__, __FUNCTION__, uarg);
+               return -EFAULT;
+       }
+
+       csmi_sas_raid_control_buffer_sz = karg.IoctlHeader.Length;
+       memory_pages = get_order(csmi_sas_raid_control_buffer_sz);
+       pKarg = (CSMI_SAS_RAID_CONTROL_BUFFER *)__get_free_pages(
+               GFP_KERNEL, memory_pages);
+       if (!pKarg){
+               printk(KERN_ERR "%s@%d::%s() - "
+                   "Unable to malloc RAID_CONTROL_BUFFER "
+                       "csmi_sas_raid_control_buffer_sz=%d memory_pages=%d\n",
+                       __FILE__, __LINE__, __FUNCTION__, 
+                       csmi_sas_raid_control_buffer_sz, memory_pages);
+               return -ENOMEM;
+       }
+       memset(pKarg, 0, sizeof(*pKarg));
+
+       if (copy_from_user(pKarg, uarg, csmi_sas_raid_control_buffer_sz)) {
+               printk(KERN_ERR "%s@%d::%s() - "
+                   "Unable to read in csmi_sas_set_raid_control struct @ %p\n",
+                   __FILE__, __LINE__, __FUNCTION__, uarg);
+               free_pages((unsigned long)pKarg, memory_pages);
+               return -EFAULT;
+       }
+
+       if (((iocnum = mpt_verify_adapter(pKarg->IoctlHeader.IOControllerNumber,
+           &ioc)) < 0) || (ioc == NULL)) {
+               printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n",
+                   __FILE__, __FUNCTION__, __LINE__, iocnum);
+               free_pages((unsigned long)pKarg, memory_pages);
+               return -ENODEV;
+       }
+
+       if (!csmisas_is_this_sas_cntr(ioc)) {
+               printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n",
+                   __FILE__, __FUNCTION__, __LINE__, iocnum);
+               free_pages((unsigned long)pKarg, memory_pages);
+               return -ENODEV;
+       }
+
+       dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__));
+
+       if (pKarg->Information.uChangeCount != 0 &&
+               pKarg->Information.uChangeCount != ioc->csmi_change_count ) {
+               pKarg->IoctlHeader.ReturnCode =
+                   CSMI_SAS_STATUS_INVALID_PARAMETER;
+               pKarg->Information.uFailureCode =
+                   CSMI_SAS_FAIL_CODE_CHANGE_COUNT_INVALID;
+               goto cim_set_raid_control_exit;
+       }
+
+       if (pKarg->Information.bTransformPriority !=
+           CSMI_SAS_PRIORITY_UNCHANGED) {
+               pKarg->IoctlHeader.ReturnCode =
+                   CSMI_SAS_STATUS_INVALID_PARAMETER;
+               pKarg->Information.uFailureCode =
+                   CSMI_SAS_FAIL_CODE_TRANSFORM_PRIORITY_INVALID;
+               goto cim_set_raid_control_exit;
+       }
+
+       if (pKarg->Information.bRebuildPriority !=
+           CSMI_SAS_PRIORITY_AUTO &&
+               pKarg->Information.bRebuildPriority !=
+               CSMI_SAS_PRIORITY_UNCHANGED) {
+               pKarg->IoctlHeader.ReturnCode =
+                   CSMI_SAS_STATUS_INVALID_PARAMETER;
+               pKarg->Information.uFailureCode =
+                   CSMI_SAS_FAIL_CODE_REBUILD_PRIORITY_INVALID;
+               goto cim_set_raid_control_exit;
+       }
+
+       if (pKarg->Information.bCacheRatioFlag ==
+           CSMI_SAS_RAID_CACHE_RATIO_DISABLE) {
+               pKarg->IoctlHeader.ReturnCode =
+                   CSMI_SAS_STATUS_INVALID_PARAMETER;
+               pKarg->Information.uFailureCode =
+                   CSMI_SAS_FAIL_CODE_CACHE_RATIO_INVALID;
+               goto cim_set_raid_control_exit;
+       }
+
+       if( !strcmp(pKarg->Information.bClearConfiguration,
+               CSMI_SAS_RAID_CLEAR_CONFIGURATION_SIGNATURE) ) {
+               pKarg->IoctlHeader.ReturnCode =
+                       CSMI_SAS_STATUS_INVALID_PARAMETER;
+               pKarg->Information.uFailureCode =
+                       CSMI_SAS_FAIL_CODE_CLEAR_CONFIGURATION_INVALID;
+               goto cim_set_raid_control_exit;
+       }
+
+       pKarg->Information.bFailureDescription[0] = '\0';
+
+ cim_set_raid_control_exit:
+
+       /*
+        * Copy the data from kernel memory to user memory
+        */
+       if (copy_to_user(uarg, pKarg,
+               sizeof(CSMI_SAS_RAID_CONTROL_BUFFER))) {
+               printk(KERN_ERR "%s@%d::%s() - "
+               "Unable to write out csmi_sas_set_raid_control @ %p\n",
+               __FILE__, __LINE__, __FUNCTION__, uarg);
+               free_pages((unsigned long)pKarg, memory_pages);
+               return -EFAULT;
+       }
+
+       dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__));
+       free_pages((unsigned long)pKarg, memory_pages);
+       return 0;
+}
+
+/**
+ * Prototype Routine for the CSMI SAS Get Raid Element.
+ *
+ * Outputs:    None.
+ * Return:     0 if successful
+ *             -EFAULT if data unavailable
+ *             -ENODEV if no such device/adapter
+ **/
+static int
+csmisas_get_raid_element(unsigned long arg)
+{
+       CSMI_SAS_RAID_ELEMENT_BUFFER __user *uarg = (void __user *) arg;
+       CSMI_SAS_RAID_ELEMENT_BUFFER     karg;
+       MPT_ADAPTER                     *ioc = NULL;
+       int                             iocnum;
+
+       if (copy_from_user(&karg, uarg, sizeof(CSMI_SAS_RAID_ELEMENT_BUFFER))) {
+               printk(KERN_ERR "%s@%d::%s() - "
+                   "Unable to read in csmisas_get_raid_element struct @ %p\n",
+                   __FILE__, __LINE__, __FUNCTION__, uarg);
+               return -EFAULT;
+       }
+
+       if (((iocnum = mpt_verify_adapter(karg.IoctlHeader.IOControllerNumber,
+           &ioc)) < 0) || (ioc == NULL)) {
+               printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n",
+                   __FILE__, __FUNCTION__, __LINE__, iocnum);
+               return -ENODEV;
+       }
+
+       if (!csmisas_is_this_sas_cntr(ioc)) {
+               printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n",
+                   __FILE__, __FUNCTION__, __LINE__, iocnum);
+               return -ENODEV;
+       }
+
+       dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__));
+
+/* TODO - implement IOCTL here */
+       karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_BAD_CNTL_CODE;
+       dcsmisasprintk(ioc, printk(KERN_DEBUG ": not implemented\n"));
+
+// csmisas_get_raid_element_exit:
+
+       /* Copy the data from kernel memory to user memory
+        */
+       if (copy_to_user(uarg, &karg,
+                               sizeof(CSMI_SAS_RAID_ELEMENT_BUFFER))) {
+               printk(KERN_ERR "%s@%d::%s() - "
+                       "Unable to write out csmisas_get_raid_element @ %p\n",
+                               __FILE__, __LINE__, __FUNCTION__, uarg);
+               return -EFAULT;
+       }
+
+       dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__));
+       return 0;
+
+}
+
+/**
+ * Prototype Routine for the CSMI SAS Set Raid Operation
+ *
+ * Outputs:    None.
+ * Return:     0 if successful
+ *             -EFAULT if data unavailable
+ *             -ENODEV if no such device/adapter
+ **/
+static int
+csmisas_set_raid_operation(unsigned long arg)
+{
+       CSMI_SAS_RAID_SET_OPERATION_BUFFER __user *uarg = (void __user *) arg;
+       CSMI_SAS_RAID_SET_OPERATION_BUFFER       karg;
+       MPT_ADAPTER                     *ioc = NULL;
+       int                             iocnum;
+
+       if (copy_from_user(&karg, uarg, sizeof(CSMI_SAS_RAID_SET_OPERATION_BUFFER))) {
+               printk(KERN_ERR "%s@%d::%s() - "
+                   "Unable to read in csmi_set_raid_operation struct @ %p\n",
+                   __FILE__, __LINE__, __FUNCTION__, uarg);
+               return -EFAULT;
+       }
+
+       if (((iocnum = mpt_verify_adapter(karg.IoctlHeader.IOControllerNumber,
+           &ioc)) < 0) || (ioc == NULL)) {
+               printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n",
+                   __FILE__, __FUNCTION__, __LINE__, iocnum);
+               return -ENODEV;
+       }
+
+       if (!csmisas_is_this_sas_cntr(ioc)) {
+               printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n",
+                   __FILE__, __FUNCTION__, __LINE__, iocnum);
+               return -ENODEV;
+       }
+
+       dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__));
+
+/* TODO - implement IOCTL here */
+       karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_BAD_CNTL_CODE;
+       dcsmisasprintk(ioc, printk(KERN_DEBUG ": not implemented\n"));
+
+// cim_set_raid_operation:
+
+       /* Copy the data from kernel memory to user memory
+        */
+       if (copy_to_user(uarg, &karg,
+                               sizeof(CSMI_SAS_RAID_SET_OPERATION_BUFFER))) {
+               printk(KERN_ERR "%s@%d::%s() - "
+                       "Unable to write out csmi_set_raid_operation @ %p\n",
+                               __FILE__, __LINE__, __FUNCTION__, uarg);
+               return -EFAULT;
+       }
+
+       dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__));
+       return 0;
+
+}
+
+
+/**
+ * Prototype Routine for the CSMI SAS Task Managment Config command.
+ *
+ * Outputs:    None.
+ * Return:     0 if successful
+ *             -EFAULT if data unavailable
+ *             -ENODEV if no such device/adapter
+ **/
+static int
+csmisas_task_managment(unsigned long arg)
+{
+       CSMI_SAS_SSP_TASK_IU_BUFFER __user *uarg = (void __user *) arg;
+       CSMI_SAS_SSP_TASK_IU_BUFFER      karg;
+       pSCSITaskMgmt_t                 pScsiTm;
+       pSCSITaskMgmtReply_t            pScsiTmReply;
+       MPT_ADAPTER                     *ioc = NULL;
+       MPT_SCSI_HOST                   *hd;
+       MPT_FRAME_HDR                   *mf = NULL;
+       MPIHeader_t                     *mpi_hdr;
+       int                             iocnum;
+       u8                              taskType;
+       u8                              channel;
+       u8                              id;
+       u8                              queueTag;
+       u32                             TaskMsgContext = 0;
+       int                             i;
+       u8                              found_qtag;
+       struct sas_device_info          *sas_info;
+       u16                             ioc_status;
+       u32                             MsgContext;
+
+       if (copy_from_user(&karg, uarg, sizeof(CSMI_SAS_SSP_TASK_IU_BUFFER))) {
+               printk(KERN_ERR "%s@%d::%s() - "
+                   "Unable to read in csmi_sas_task_managment struct @ %p\n",
+                   __FILE__, __LINE__, __FUNCTION__, uarg);
+               return -EFAULT;
+       }
+
+       if (((iocnum = mpt_verify_adapter(karg.IoctlHeader.IOControllerNumber,
+           &ioc)) < 0) || (ioc == NULL)) {
+               printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n",
+                   __FILE__, __FUNCTION__, __LINE__, iocnum);
+               return -ENODEV;
+       }
+
+       if (!csmisas_is_this_sas_cntr(ioc)) {
+               printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n",
+                   __FILE__, __FUNCTION__, __LINE__, iocnum);
+               return -ENODEV;
+       }
+
+       dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__));
+
+       karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_INVALID_PARAMETER;
+
+       sas_info = csmisas_get_device_component_by_os(ioc,
+           karg.Parameters.bPathId, karg.Parameters.bTargetId);
+       if (!sas_info || sas_info->is_cached || sas_info->is_logical_volume)
+               goto cim_get_task_managment_exit;
+
+       channel = sas_info->fw.channel;
+       id = sas_info->fw.id;
+       queueTag = (u8)karg.Parameters.uQueueTag & 0xFF;
+       hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
+
+       /* try to catch an error
+        */
+       if ((karg.Parameters.uFlags & CSMI_SAS_TASK_IU) &&
+           (karg.Parameters.uFlags & CSMI_SAS_HARD_RESET_SEQUENCE))
+               goto cim_get_task_managment_exit;
+
+       if (karg.Parameters.uFlags & CSMI_SAS_TASK_IU) {
+               switch (karg.Parameters.bTaskManagementFunction) {
+
+               case CSMI_SAS_SSP_ABORT_TASK:
+                       taskType = MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK;
+                       break;
+               case CSMI_SAS_SSP_ABORT_TASK_SET:
+                       taskType = MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET;
+                       break;
+               case CSMI_SAS_SSP_CLEAR_TASK_SET:
+                       taskType = MPI_SCSITASKMGMT_TASKTYPE_CLEAR_TASK_SET;
+                       break;
+               case CSMI_SAS_SSP_LOGICAL_UNIT_RESET:
+                       taskType = MPI_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET;
+                       break;
+               case CSMI_SAS_SSP_CLEAR_ACA:
+               case CSMI_SAS_SSP_QUERY_TASK:
+               default:
+                       goto cim_get_task_managment_exit;
+               }
+       } else if (karg.Parameters.uFlags & CSMI_SAS_HARD_RESET_SEQUENCE)
+               taskType = MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
+       else
+               goto cim_get_task_managment_exit;
+
+       switch (karg.Parameters.uInformation) {
+               case CSMI_SAS_SSP_TEST:
+                       dcsmisasprintk(ioc, printk(KERN_DEBUG "TM request for test purposes\n"));
+                       break;
+               case CSMI_SAS_SSP_EXCEEDED:
+                       dcsmisasprintk(ioc, printk(KERN_DEBUG "TM request due to timeout\n"));
+                       break;
+               case CSMI_SAS_SSP_DEMAND:
+                       dcsmisasprintk(ioc, printk(KERN_DEBUG "TM request demanded by app\n"));
+                       break;
+               case CSMI_SAS_SSP_TRIGGER:
+                       dcsmisasprintk(ioc, printk(KERN_DEBUG "TM request sent to trigger event\n"));
+                       break;
+       }
+
+       switch (taskType) {
+
+       case MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK:
+       /*
+        * look up qtag in the ScsiLookup[] table
+        */
+               for (i = 0, found_qtag = 0; i < hd->ioc->req_depth; i++) {
+                       if ((ioc->ScsiLookup[i]) &&
+                           (ioc->ScsiLookup[i]->tag == queueTag)) {
+                               mf = MPT_INDEX_2_MFPTR(hd->ioc, i);
+                               TaskMsgContext =
+                                   mf->u.frame.hwhdr.msgctxu.MsgContext;
+                               found_qtag=1;
+                               break;
+                       }
+               }
+
+               if(!found_qtag)
+                       goto cim_get_task_managment_exit;
+
+       case MPI_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET:
+       case MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET:
+       case MPI_SCSITASKMGMT_TASKTYPE_CLEAR_TASK_SET:
+       /* for now, this should work
+        */
+       case MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET:
+
+               /* Single threading ....
+                */
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,15))
+               mutex_lock(&ioc->taskmgmt_cmds.mutex);
+               if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) {
+                       mutex_unlock(&ioc->taskmgmt_cmds.mutex);
+                       karg.IoctlHeader.ReturnCode =
+                           CSMI_SAS_STATUS_FAILED;
+                       goto cim_get_task_managment_exit;
+               }
+#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0))
+               if (mptctl_set_tm_flags(hd) != 0) {
+                       karg.IoctlHeader.ReturnCode =
+                           CSMI_SAS_STATUS_FAILED;
+                       goto cim_get_task_managment_exit;
+               }
+#endif
+               /* Send request
+                */
+               if ((mf = mpt_get_msg_frame(mptctl_taskmgmt_id, ioc)) == NULL) {
+                       dcsmisasprintk(ioc, printk(KERN_ERR ": no msg frames!\n"));
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,15))
+                       mutex_unlock(&ioc->taskmgmt_cmds.mutex);
+                       mpt_clear_taskmgmt_in_progress_flag(ioc);
+#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0))
+                       mptctl_free_tm_flags(ioc);
+#endif
+                       karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+                       goto cim_get_task_managment_exit;
+               }
+
+               mpi_hdr = (MPIHeader_t *) mf;
+               MsgContext = mpi_hdr->MsgContext;
+               pScsiTm = (pSCSITaskMgmt_t ) mf;
+
+               memset(pScsiTm,0,sizeof(SCSITaskMgmt_t));
+               pScsiTm->TaskType = taskType;
+               pScsiTm->Bus = channel;
+               pScsiTm->TargetID = id;
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,15))
+               int_to_scsilun(karg.Parameters.bLun,
+                   (struct scsi_lun *)pScsiTm->LUN);
+#else
+               pScsiTm->LUN[1] = karg.Parameters.bLun;
+#endif
+               pScsiTm->MsgContext = MsgContext;
+               pScsiTm->TaskMsgContext = TaskMsgContext;
+               pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
+
+               if (csmisas_send_handshake_wait(ioc, mf,
+                   karg.IoctlHeader.Timeout) != 0)  {
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,15))
+                       mutex_unlock(&ioc->taskmgmt_cmds.mutex);
+#endif
+                       karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+                       goto cim_get_task_managment_exit;
+               }
+
+               if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID) {
+
+                       pScsiTmReply =
+                           (pSCSITaskMgmtReply_t ) ioc->ioctl_cmds.reply;
+
+                       ioc_status = le16_to_cpu(pScsiTmReply->IOCStatus)
+                           & MPI_IOCSTATUS_MASK;
+
+                       memset(&karg.Status,0,
+                           sizeof(CSMI_SAS_SSP_PASSTHRU_STATUS));
+
+                       if(ioc_status == MPI_IOCSTATUS_SUCCESS) {
+                               karg.IoctlHeader.ReturnCode =
+                                   CSMI_SAS_STATUS_SUCCESS;
+                               karg.Status.bSSPStatus =
+                                   CSMI_SAS_SSP_STATUS_COMPLETED;
+                       }else if(ioc_status == MPI_IOCSTATUS_INSUFFICIENT_RESOURCES) {
+                               karg.IoctlHeader.ReturnCode =
+                                   CSMI_SAS_STATUS_SUCCESS;
+                               karg.Status.bSSPStatus =
+                                   CSMI_SAS_SSP_STATUS_RETRY;
+                       }else {
+                               karg.IoctlHeader.ReturnCode =
+                                   CSMI_SAS_STATUS_FAILED;
+                               karg.Status.bSSPStatus =
+                                   CSMI_SAS_SSP_STATUS_FATAL_ERROR;
+                       }
+               } else
+                       karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+
+               break;
+
+       default:
+               karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_INVALID_PARAMETER;
+               break;
+       }
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,15))
+       mutex_unlock(&ioc->taskmgmt_cmds.mutex);
+#endif
+
+ cim_get_task_managment_exit:
+
+       /* Copy the data from kernel memory to user memory
+        */
+       if (copy_to_user(uarg, &karg,
+                               sizeof(CSMI_SAS_SSP_TASK_IU_BUFFER))) {
+               printk(KERN_ERR "%s@%d::%s() - "
+                       "Unable to write out csmi_sas_task_managment @ %p\n",
+                               __FILE__, __LINE__, __FUNCTION__, uarg);
+               return -EFAULT;
+       }
+
+       dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__));
+       return 0;
+}
+
+/**
+ *     map_sas_status_to_csmi - Conversion  for Connection Status
+ *     @mpi_sas_status: Sas status returned by the firmware
+ *
+ *     Returns converted connection status
+ *
+ **/
+static u8
+map_sas_status_to_csmi(u8 mpi_sas_status)
+{
+       u8  csmi_connect_status;
+
+       switch (mpi_sas_status) {
+
+       case MPI_SASSTATUS_SUCCESS:
+               csmi_connect_status = CSMI_SAS_OPEN_ACCEPT;
+               break;
+
+       case MPI_SASSTATUS_UTC_BAD_DEST:
+               csmi_connect_status = CSMI_SAS_OPEN_REJECT_BAD_DESTINATION;
+               break;
+
+       case MPI_SASSTATUS_UTC_CONNECT_RATE_NOT_SUPPORTED:
+               csmi_connect_status = CSMI_SAS_OPEN_REJECT_RATE_NOT_SUPPORTED;
+               break;
+
+       case MPI_SASSTATUS_UTC_PROTOCOL_NOT_SUPPORTED:
+               csmi_connect_status =
+                   CSMI_SAS_OPEN_REJECT_PROTOCOL_NOT_SUPPORTED;
+               break;
+
+       case MPI_SASSTATUS_UTC_STP_RESOURCES_BUSY:
+               csmi_connect_status = CSMI_SAS_OPEN_REJECT_STP_RESOURCES_BUSY;
+               break;
+
+       case MPI_SASSTATUS_UTC_WRONG_DESTINATION:
+               csmi_connect_status = CSMI_SAS_OPEN_REJECT_WRONG_DESTINATION;
+               break;
+
+       case MPI_SASSTATUS_SDSF_NAK_RECEIVED:
+               csmi_connect_status = CSMI_SAS_OPEN_REJECT_RETRY;
+               break;
+
+       case MPI_SASSTATUS_SDSF_CONNECTION_FAILED:
+               csmi_connect_status = CSMI_SAS_OPEN_REJECT_PATHWAY_BLOCKED;
+               break;
+
+       case MPI_SASSTATUS_INITIATOR_RESPONSE_TIMEOUT:
+               csmi_connect_status =  CSMI_SAS_OPEN_REJECT_NO_DESTINATION;
+               break;
+
+       case MPI_SASSTATUS_UNKNOWN_ERROR:
+       case MPI_SASSTATUS_INVALID_FRAME:
+       case MPI_SASSTATUS_UTC_BREAK_RECEIVED:
+       case MPI_SASSTATUS_UTC_PORT_LAYER_REQUEST:
+       case MPI_SASSTATUS_SHORT_INFORMATION_UNIT:
+       case MPI_SASSTATUS_LONG_INFORMATION_UNIT:
+       case MPI_SASSTATUS_XFER_RDY_INCORRECT_WRITE_DATA:
+       case MPI_SASSTATUS_XFER_RDY_REQUEST_OFFSET_ERROR:
+       case MPI_SASSTATUS_XFER_RDY_NOT_EXPECTED:
+       case MPI_SASSTATUS_DATA_INCORRECT_DATA_LENGTH:
+       case MPI_SASSTATUS_DATA_TOO_MUCH_READ_DATA:
+       case MPI_SASSTATUS_DATA_OFFSET_ERROR:
+               csmi_connect_status = CSMI_SAS_OPEN_REJECT_RESERVE_STOP;
+               break;
+
+       default:
+               csmi_connect_status = CSMI_SAS_OPEN_REJECT_RESERVE_STOP;
+               break;
+       }
+
+       return csmi_connect_status;
+}
+
+/**
+ *                      csmisas_phy_reset
+ *     Issues a phy link reset or phy hard reset
+ *
+ *     @ioc - Pointer to MPT_ADAPTER structure
+ *     @PhyNum - phy number
+ *     @opcode - {MPI_SAS_OP_PHY_LINK_RESET,MPI_SAS_OP_PHY_HARD_RESET}
+ *
+ *     Returns: 0 for success, non-zero error
+ **/
+static int
+csmisas_phy_reset(MPT_ADAPTER *ioc, u8 PhyNum, u8 opcode)
+{
+       SasIoUnitControlRequest_t       *sasIoUnitCntrReq;
+       SasIoUnitControlReply_t         *sasIoUnitCntrReply;
+       MPT_FRAME_HDR                   *mf = NULL;
+       MPIHeader_t                     *mpi_hdr;
+       u16                             ioc_status;
+       u32                             MsgContext;
+
+       if ((opcode != MPI_SAS_OP_PHY_LINK_RESET) &&
+           (opcode != MPI_SAS_OP_PHY_HARD_RESET))
+           return -1;
+
+       /* Get a MF for this command.
+        */
+       if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL) {
+               dcsmisasprintk(ioc, printk(KERN_ERR ": no msg frames!\n"));
+               return -1;
+        }
+
+       mpi_hdr = (MPIHeader_t *) mf;
+       MsgContext =  mpi_hdr->MsgContext;
+       sasIoUnitCntrReq = (SasIoUnitControlRequest_t *)mf;
+       memset(sasIoUnitCntrReq,0,sizeof(SasIoUnitControlRequest_t));
+       sasIoUnitCntrReq->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
+       sasIoUnitCntrReq->MsgContext = MsgContext;
+       sasIoUnitCntrReq->Operation = opcode;
+       sasIoUnitCntrReq->PhyNum = PhyNum;
+
+       if (csmisas_send_command_wait(ioc, mf, MPT_IOCTL_DEFAULT_TIMEOUT) != 0)
+               return -1;
+
+       if ((ioc->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID) == 0)
+               return -1;
+
+       /* process the completed Reply Message Frame */
+       sasIoUnitCntrReply = (SasIoUnitControlReply_t *)ioc->ioctl_cmds.reply;
+       ioc_status = le16_to_cpu(sasIoUnitCntrReply->IOCStatus)
+           & MPI_IOCSTATUS_MASK;
+       if (ioc_status != MPI_IOCSTATUS_SUCCESS) {
+               printk(KERN_DEBUG "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
+                   __FUNCTION__,
+                   sasIoUnitCntrReply->IOCStatus,
+                   sasIoUnitCntrReply->IOCLogInfo);
+               return -1;
+       }
+       return 0;
+}
+
+/** Prototype Routine for the CSMI SAS Phy Control command.
+ *
+ * Outputs:    None.
+ * Return:     0 if successful
+ *             -EFAULT if data unavailable
+ *             -ENODEV if no such device/adapter
+ **/
+static int
+csmisas_phy_control(unsigned long arg)
+{
+       CSMI_SAS_PHY_CONTROL_BUFFER __user *uarg = (void __user *) arg;
+       IOCTL_HEADER                    ioctl_header;
+       PCSMI_SAS_PHY_CONTROL_BUFFER    karg;
+       SasIOUnitPage0_t                *sasIoUnitPg0=NULL;
+       dma_addr_t                      sasIoUnitPg0_dma;
+       int                             sasIoUnitPg0_data_sz=0;
+       SasIOUnitPage1_t                *sasIoUnitPg1=NULL;
+       dma_addr_t                      sasIoUnitPg1_dma;
+       int                             sasIoUnitPg1_data_sz=0;
+       ConfigExtendedPageHeader_t      hdr;
+       CONFIGPARMS                     cfg;
+       MPT_ADAPTER                     *ioc = NULL;
+       int                             iocnum;
+       int                             csmi_sas_phy_control_buffer_sz;
+       int                             memory_pages;
+
+       if (copy_from_user(&ioctl_header, uarg, sizeof(IOCTL_HEADER))) {
+               printk(KERN_ERR "%s@%d::%s() - "
+                   "Unable to read in IOCTL_HEADER"
+                   "struct @ %p\n", __FILE__, __LINE__, __FUNCTION__, uarg);
+               return -EFAULT;
+       }
+
+       csmi_sas_phy_control_buffer_sz = ioctl_header.Length;
+       memory_pages = get_order(csmi_sas_phy_control_buffer_sz);
+       karg = (PCSMI_SAS_PHY_CONTROL_BUFFER)__get_free_pages(
+               GFP_KERNEL, memory_pages);
+       if (!karg){
+               printk(KERN_ERR "%s@%d::%s() - "
+                   "Unable to malloc SAS_PHY_CONTROL_BUFFER "
+                       "csmi_sas_phy_control_buffer_sz=%d memory_pages=%d\n",
+                       __FILE__, __LINE__, __FUNCTION__, 
+                       csmi_sas_phy_control_buffer_sz, memory_pages);
+               return -ENOMEM;
+       }
+       memset(karg, 0, sizeof(*karg));
+
+       if (copy_from_user(karg, uarg, csmi_sas_phy_control_buffer_sz)) {
+               printk(KERN_ERR "%s@%d::%s() - "
+                   "Unable to read in csmi_sas_phy_control_buffer "
+                   "struct @ %p\n", __FILE__, __LINE__, __FUNCTION__, uarg);
+               free_pages((unsigned long)karg, memory_pages);
+               return -EFAULT;
+       }
+
+       if (((iocnum = mpt_verify_adapter(ioctl_header.IOControllerNumber,
+           &ioc)) < 0) || (ioc == NULL)) {
+               printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n",
+                   __FILE__, __FUNCTION__, __LINE__, iocnum);
+               free_pages((unsigned long)karg, memory_pages);
+               return -ENODEV;
+       }
+
+       if (!csmisas_is_this_sas_cntr(ioc)) {
+               printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n",
+                   __FILE__, __FUNCTION__, __LINE__, iocnum);
+               free_pages((unsigned long)karg, memory_pages);
+               return -ENODEV;
+       }
+
+       dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__));
+
+       if (karg->bPhyIdentifier >= ioc->num_ports) {
+               karg->IoctlHeader.ReturnCode =
+                  CSMI_SAS_STATUS_INVALID_PARAMETER;
+               goto cim_sas_phy_control_exit;
+       }
+
+       /*
+        *  Retreive SAS IOUNIT PAGE 0
+        */
+
+       hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION;
+       hdr.ExtPageLength = 0;
+       hdr.PageNumber = 0;
+       hdr.Reserved1 = 0;
+       hdr.Reserved2 = 0;
+       hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
+       hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
+
+       cfg.cfghdr.ehdr = &hdr;
+       cfg.physAddr = -1;
+       cfg.pageAddr = 0;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+       cfg.dir = 0;    /* read */
+       cfg.timeout = MPT_IOCTL_DEFAULT_TIMEOUT;
+
+       if (mpt_config(ioc, &cfg) != 0) {
+               dcsmisasprintk(ioc, printk(KERN_ERR
+                   ": FAILED: READ MPI_SASIOUNITPAGE0: HEADER\n"));
+               karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+               goto cim_sas_phy_control_exit;
+       }
+
+       if (hdr.ExtPageLength == 0) {
+               dcsmisasprintk(ioc, printk(KERN_ERR ": hdr.ExtPageLength == 0\n"));
+               karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+               goto cim_sas_phy_control_exit;
+       }
+
+       sasIoUnitPg0_data_sz = hdr.ExtPageLength * 4;
+       sasIoUnitPg0 = (SasIOUnitPage0_t *) pci_alloc_consistent(ioc->pcidev,
+           sasIoUnitPg0_data_sz, &sasIoUnitPg0_dma);
+
+       if (!sasIoUnitPg0) {
+               dcsmisasprintk(ioc, printk(KERN_ERR ": pci_alloc_consistent: FAILED\n"));
+               karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+               goto cim_sas_phy_control_exit;
+       }
+
+       memset((u8 *)sasIoUnitPg0, 0, sasIoUnitPg0_data_sz);
+       cfg.physAddr = sasIoUnitPg0_dma;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+
+       if (mpt_config(ioc, &cfg) != 0) {
+               dcsmisasprintk(ioc, printk(KERN_ERR
+                   ": FAILED: READ MPI_SASIOUNITPAGE0: CURRENT\n"));
+               karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+               goto cim_sas_phy_control_exit;
+       }
+
+       /*
+        *  Retreive SAS IOUNIT PAGE 1
+        */
+
+       hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION;
+       hdr.ExtPageLength = 0;
+       hdr.PageNumber = 1;
+       hdr.Reserved1 = 0;
+       hdr.Reserved2 = 0;
+       hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
+       hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
+
+       cfg.cfghdr.ehdr = &hdr;
+       cfg.physAddr = -1;
+       cfg.pageAddr = 0;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+       cfg.dir = 0;    /* read */
+       cfg.timeout = MPT_IOCTL_DEFAULT_TIMEOUT;
+
+       if (mpt_config(ioc, &cfg) != 0) {
+               dcsmisasprintk(ioc, printk(KERN_ERR
+                   ": FAILED: READ MPI_SASIOUNITPAGE1: HEADER\n"));
+               karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+               goto cim_sas_phy_control_exit;
+       }
+
+       if (hdr.ExtPageLength == 0) {
+               dcsmisasprintk(ioc, printk(KERN_ERR ": hdr.ExtPageLength == 0\n"));
+               karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+               goto cim_sas_phy_control_exit;
+       }
+
+       sasIoUnitPg1_data_sz = hdr.ExtPageLength * 4;
+       sasIoUnitPg1 = (SasIOUnitPage1_t *) pci_alloc_consistent(ioc->pcidev,
+           sasIoUnitPg1_data_sz, &sasIoUnitPg1_dma);
+
+       if (!sasIoUnitPg1) {
+               dcsmisasprintk(ioc, printk(KERN_ERR ": pci_alloc_consistent: FAILED\n"));
+               karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+               goto cim_sas_phy_control_exit;
+       }
+
+       memset((u8 *)sasIoUnitPg1, 0, sasIoUnitPg1_data_sz);
+       cfg.physAddr = sasIoUnitPg1_dma;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+
+       if (mpt_config(ioc, &cfg) != 0) {
+               dcsmisasprintk(ioc, printk(KERN_ERR
+                   ": FAILED:  READ MPI_SASIOUNITPAGE1: CURRENT\n"));
+               karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+               goto cim_sas_phy_control_exit;
+       }
+
+       switch (karg->uFunction) {
+
+       case CSMI_SAS_PC_LINK_RESET:
+       case CSMI_SAS_PC_HARD_RESET:
+       {
+               u8 opcode = (karg->uFunction==CSMI_SAS_PC_LINK_RESET) ?
+                   MPI_SAS_OP_PHY_LINK_RESET : MPI_SAS_OP_PHY_HARD_RESET;
+
+               if((karg->uLinkFlags & CSMI_SAS_PHY_ACTIVATE_CONTROL) &&
+                   (karg->usLengthOfControl >= sizeof(CSMI_SAS_PHY_CONTROL)) &&
+                   (karg->bNumberOfControls > 0)){
+                       if(karg->Control[0].bRate ==
+                          CSMI_SAS_LINK_RATE_1_5_GBPS) {
+                               sasIoUnitPg1->PhyData[karg->bPhyIdentifier].MaxMinLinkRate =
+                               MPI_SAS_IOUNIT1_MAX_RATE_1_5 |
+                               MPI_SAS_IOUNIT1_MIN_RATE_1_5;
+                       }
+                       else if(karg->Control[0].bRate ==
+                          CSMI_SAS_LINK_RATE_3_0_GBPS) {
+                               sasIoUnitPg1->PhyData[karg->bPhyIdentifier].MaxMinLinkRate =
+                               MPI_SAS_IOUNIT1_MAX_RATE_3_0 |
+                               MPI_SAS_IOUNIT1_MIN_RATE_3_0;
+                       }
+                       sasIoUnitPg1->PhyData[karg->bPhyIdentifier].PhyFlags &=
+                           ~MPI_SAS_IOUNIT1_PHY_FLAGS_PHY_DISABLE;
+                       cfg.dir = 1;
+                       cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM;
+                       if (mpt_config(ioc, &cfg) != 0) {
+                               dcsmisasprintk(ioc, printk(KERN_ERR
+                           ": FAILED: WRITE MPI_SASIOUNITPAGE1 NVRAM\n"));
+                               karg->IoctlHeader.ReturnCode =
+                                  CSMI_SAS_STATUS_FAILED;
+                               goto cim_sas_phy_control_exit;
+                       }
+                       cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
+                       if (mpt_config(ioc, &cfg) != 0) {
+                               dcsmisasprintk(ioc, printk(KERN_ERR
+                        ": FAILED: WRITE MPI_SASIOUNITPAGE1 CURRENT\n"));
+                               karg->IoctlHeader.ReturnCode =
+                                  CSMI_SAS_STATUS_FAILED;
+                               goto cim_sas_phy_control_exit;
+                       }
+               }
+               if (csmisas_phy_reset(ioc,
+                   karg->bPhyIdentifier, opcode) != 0) {
+                       dcsmisasprintk(ioc, printk(KERN_ERR
+                           ": FAILED: csmisas_phy_reset\n"));
+                       karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+                       goto cim_sas_phy_control_exit;
+               }
+               break;
+
+       }
+       case CSMI_SAS_PC_PHY_DISABLE:
+               if(karg->usLengthOfControl || karg->bNumberOfControls) {
+                       karg->IoctlHeader.ReturnCode =
+                           CSMI_SAS_STATUS_INVALID_PARAMETER;
+                       break;
+               }
+               sasIoUnitPg1->PhyData[karg->bPhyIdentifier].PhyFlags |=
+                   MPI_SAS_IOUNIT1_PHY_FLAGS_PHY_DISABLE;
+               cfg.dir = 1;
+               cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM;
+               if (mpt_config(ioc, &cfg) != 0) {
+                       dcsmisasprintk(ioc, printk(KERN_ERR
+                           ": FAILED: WRITE MPI_SASIOUNITPAGE1 NVRAM\n"));
+                       karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+                       goto cim_sas_phy_control_exit;
+               }
+               cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
+               if (mpt_config(ioc, &cfg) != 0) {
+                       dcsmisasprintk(ioc, printk(KERN_ERR
+                           ": FAILED: WRITE MPI_SASIOUNITPAGE1 CURRENT\n"));
+                       karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+                       goto cim_sas_phy_control_exit;
+               }
+               if (csmisas_phy_reset(ioc,
+                   karg->bPhyIdentifier, MPI_SAS_OP_PHY_HARD_RESET) != 0) {
+                       dcsmisasprintk(ioc, printk(KERN_ERR
+                           ": FAILED: csmisas_phy_reset\n"));
+                       karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+                       goto cim_sas_phy_control_exit;
+               }
+               break;
+
+       case CSMI_SAS_PC_GET_PHY_SETTINGS:
+               if(karg->usLengthOfControl || karg->bNumberOfControls) {
+                       karg->IoctlHeader.ReturnCode =
+                           CSMI_SAS_STATUS_INVALID_PARAMETER;
+                       break;
+               }
+               if(csmi_sas_phy_control_buffer_sz <
+                   offsetof(CSMI_SAS_PHY_CONTROL_BUFFER,Control) +
+                   (4* sizeof(CSMI_SAS_PHY_CONTROL))) {
+                       karg->IoctlHeader.ReturnCode =
+                           CSMI_SAS_STATUS_INVALID_PARAMETER;
+                       break;
+               }
+               karg->usLengthOfControl = sizeof(CSMI_SAS_PHY_CONTROL);
+               karg->bNumberOfControls = 4;
+               karg->Control[0].bType = CSMI_SAS_SAS;
+               karg->Control[0].bRate = CSMI_SAS_LINK_RATE_1_5_GBPS;
+               karg->Control[1].bType = CSMI_SAS_SAS;
+               karg->Control[1].bRate = CSMI_SAS_LINK_RATE_3_0_GBPS;
+               karg->Control[2].bType = CSMI_SAS_SATA;
+               karg->Control[2].bRate = CSMI_SAS_LINK_RATE_1_5_GBPS;
+               karg->Control[3].bType = CSMI_SAS_SATA;
+               karg->Control[3].bRate = CSMI_SAS_LINK_RATE_3_0_GBPS;
+               karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS;
+               break;
+       default:
+               break;
+       }
+
+ cim_sas_phy_control_exit:
+
+       if (sasIoUnitPg0)
+               pci_free_consistent(ioc->pcidev, sasIoUnitPg0_data_sz,
+                   (u8 *) sasIoUnitPg0, sasIoUnitPg0_dma);
+
+       if (sasIoUnitPg1)
+               pci_free_consistent(ioc->pcidev, sasIoUnitPg1_data_sz,
+                   (u8 *) sasIoUnitPg1, sasIoUnitPg1_dma);
+
+       /* Copy the data from kernel memory to user memory
+        */
+       if (copy_to_user(uarg, karg,csmi_sas_phy_control_buffer_sz)) {
+               printk(KERN_ERR "%s@%d::%s() - "
+                   "Unable to write out csmi_sas_phy_control_buffer @ %p\n",
+                   __FILE__, __LINE__, __FUNCTION__, uarg);
+               free_pages((unsigned long)karg, memory_pages);
+               return -EFAULT;
+       }
+
+       dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__));
+       free_pages((unsigned long)karg, memory_pages);
+       return 0;
+}
+
+/**
+ *     csmisas_get_manuf_pg_7 - Fetch Manufacturing config Page7.
+ * @ioc: Pointer to MPT_ADAPTER structure
+ * @mfgpage7_buffer: pointer to ManufacturingPage7_t that returns config
+ *                    page data
+ * @mfg_size - max size of buffer
+ *
+ *     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
+csmisas_get_manuf_pg_7(MPT_ADAPTER *ioc, ManufacturingPage7_t *mfgpage7_buffer, int mfg_size)
+{
+       ConfigPageHeader_t hdr;
+       CONFIGPARMS     cfg;
+       ManufacturingPage7_t *mfgPage7 = NULL;
+       dma_addr_t      mfgPage7_dma;
+       int             data_sz = 0;
+       int             rc;
+
+       /* Get Manufacturing Page 7 header */
+       hdr.PageVersion = MPI_MANUFACTURING0_PAGEVERSION;
+       hdr.PageLength = 0;
+       hdr.PageNumber = 7;
+       hdr.PageType = MPI_CONFIG_PAGETYPE_MANUFACTURING;
+       cfg.cfghdr.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)
+               goto csmisas_get_manuf_pg_7_exit;
+
+       if (hdr.PageLength == 0) {
+               rc = -EFAULT;
+               goto csmisas_get_manuf_pg_7_exit;
+       }
+
+       data_sz = hdr.PageLength * 4;
+       mfgPage7 = pci_alloc_consistent(ioc->pcidev, data_sz, &mfgPage7_dma);
+       if (!mfgPage7) {
+               rc = -ENOMEM;
+               goto csmisas_get_manuf_pg_7_exit;
+       }
+
+       memset((u8 *)mfgPage7, 0, data_sz);
+       cfg.physAddr = mfgPage7_dma;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+
+       if ((rc = mpt_config(ioc, &cfg)) != 0)
+               goto csmisas_get_manuf_pg_7_exit;
+
+       /* copy buffer back to user */
+       memcpy(mfgpage7_buffer, mfgPage7, min(data_sz, mfg_size));
+
+ csmisas_get_manuf_pg_7_exit:
+
+       if (mfgPage7)
+               pci_free_consistent(ioc->pcidev, data_sz, (u8 *)mfgPage7,
+                   mfgPage7_dma);
+
+       return rc;
+}
+
+/**
+ * Prototype Routine for the CSMI SAS Get Connector info command.
+ *
+ * Outputs:    None.
+ * Return:     0 if successful
+ *             -EFAULT if data unavailable
+ *             -ENODEV if no such device/adapter
+ **/
+static int
+csmisas_get_connector_info(unsigned long arg)
+{
+       CSMI_SAS_CONNECTOR_INFO_BUFFER __user *uarg = (void __user *) arg;
+       CSMI_SAS_CONNECTOR_INFO_BUFFER   karg;
+       MPT_ADAPTER                     *ioc = NULL;
+       ManufacturingPage7_t            *mfgPg7 = NULL;
+       int                             mfgPg7_sz;
+       int                             iocnum;
+       int                             i;
+
+       if (copy_from_user(&karg, uarg,
+               sizeof(CSMI_SAS_CONNECTOR_INFO_BUFFER))) {
+               printk(KERN_ERR "%s@%d::%s() - "
+                  "Unable to read in csmi_sas_connector_info_buffer"
+                  " struct @ %p\n",
+                  __FILE__, __LINE__, __FUNCTION__, uarg);
+               return -EFAULT;
+       }
+
+       if (((iocnum = mpt_verify_adapter(karg.IoctlHeader.IOControllerNumber,
+           &ioc)) < 0) || (ioc == NULL)) {
+               printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n",
+                   __FILE__, __FUNCTION__, __LINE__, iocnum);
+               return -ENODEV;
+       }
+
+       if (!csmisas_is_this_sas_cntr(ioc)) {
+               printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n",
+                   __FILE__, __FUNCTION__, __LINE__, iocnum);
+               return -ENODEV;
+       }
+
+       dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__));
+
+       karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS;
+
+       /* `32` is the sizeof MPI_MANPAGE7_CONNECTOR_INFO */
+       for (i = 0; i < 32; i++) {
+               karg.Reference[i].uPinout = CSMI_SAS_CON_UNKNOWN;
+               strcpy(karg.Reference[i].bConnector,"");
+               karg.Reference[i].bLocation = CSMI_SAS_CON_UNKNOWN;
+       }
+
+       mfgPg7_sz = offsetof(CONFIG_PAGE_MANUFACTURING_7,ConnectorInfo) +
+           (ioc->num_ports * sizeof(MPI_MANPAGE7_CONNECTOR_INFO));
+       mfgPg7 = kmalloc(mfgPg7_sz, GFP_KERNEL);
+       if (!mfgPg7){
+               printk(KERN_ERR "%s@%d::%s() - "
+                   "Unable to malloc @ %p\n",
+                   __FILE__, __LINE__, __FUNCTION__, mfgPg7);
+               return -EFAULT;
+       }
+       memset(mfgPg7, 0, mfgPg7_sz);
+
+       if (!csmisas_get_manuf_pg_7(ioc, mfgPg7, mfgPg7_sz)) {
+               for (i = 0; i < ioc->num_ports; i++) {
+                       karg.Reference[i].uPinout =
+                           le32_to_cpu(mfgPg7->ConnectorInfo[i].Pinout);
+                       /*endian conversion , this is u8 * 16 ?? */
+                       strncpy(karg.Reference[i].bConnector,
+                           mfgPg7->ConnectorInfo[i].Connector, 16);
+                       karg.Reference[i].bLocation =
+                           mfgPg7->ConnectorInfo[i].Location;
+               }
+       }
+
+       kfree(mfgPg7);
+
+       /* Copy the data from kernel memory to user memory
+        */
+       if (copy_to_user(uarg, &karg,
+               sizeof(CSMI_SAS_CONNECTOR_INFO_BUFFER))) {
+               printk(KERN_ERR "%s@%d::%s() - "
+               "Unable to write out csmi_sas_connector_info_buffer @"
+              "%p\n",
+               __FILE__, __LINE__, __FUNCTION__, uarg);
+               return -EFAULT;
+       }
+
+       dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__));
+       return 0;
+}
+
+/**
+ *                 csmisas_fill_location_data
+ *
+ * Outputs:    None.
+ * Return:     0 if successful
+ **/
+static int
+csmisas_fill_location_data(MPT_ADAPTER *ioc, u8 bus, u8 id, u8 opcode,
+       CSMI_SAS_LOCATION_IDENTIFIER * location_ident)
+{
+
+       ConfigExtendedPageHeader_t      hdr;
+       CONFIGPARMS                     cfg;
+       int                             rc;
+       SasDevicePage0_t                *sasDevicePg0=NULL;
+       SasEnclosurePage0_t             *sasEnclosurePg0=NULL;
+       dma_addr_t                      sasDevicePg0_dma,sasEnclosurePg0_dma;
+       int                             sasDevicePg0_data_sz=0;
+       int                             sasEnclosurePg0_data_sz=0;
+       u64                             sas_address;
+
+       dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__));
+       memset (location_ident, 0, sizeof(*location_ident));
+
+       /* SAS Device Page 0 */
+       hdr.PageVersion = MPI_SASDEVICE0_PAGEVERSION;
+       hdr.ExtPageLength = 0;
+       hdr.PageNumber = 0;
+       hdr.Reserved1 = 0;
+       hdr.Reserved2 = 0;
+       hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
+       hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE;
+
+       cfg.cfghdr.ehdr = &hdr;
+       cfg.physAddr = -1;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+       cfg.dir = 0;    /* read */
+       cfg.timeout = MPT_IOCTL_DEFAULT_TIMEOUT;
+
+       if ((rc = mpt_config(ioc, &cfg)) != 0) {
+               rc=-1;
+               goto fill_location_data_exit;
+       }
+
+       if (hdr.ExtPageLength == 0) {
+               rc=-1;
+               goto fill_location_data_exit;
+       }
+
+       sasDevicePg0_data_sz = hdr.ExtPageLength * 4;
+       sasDevicePg0 = (SasDevicePage0_t *) pci_alloc_consistent(
+           ioc->pcidev, sasDevicePg0_data_sz, &sasDevicePg0_dma);
+       if (!sasDevicePg0) {
+               rc=-1;
+               goto fill_location_data_exit;
+       }
+
+       memset((u8 *)sasDevicePg0, 0, sasDevicePg0_data_sz);
+       cfg.physAddr = sasDevicePg0_dma;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+       cfg.pageAddr = (bus << 8) + id
+           + (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
+               MPI_SAS_DEVICE_PGAD_FORM_SHIFT);
+
+       if ((rc = mpt_config(ioc, &cfg)) != 0) {
+               rc=-1;
+               goto fill_location_data_exit;
+       }
+
+       location_ident->bLocationFlags |= CSMI_SAS_LOCATE_SAS_ADDRESS_VALID;
+       memcpy(&sas_address, &sasDevicePg0->SASAddress, sizeof(u64));
+       sas_address = reverse_byte_order64(sas_address);
+       memcpy(location_ident->bSASAddress, &sas_address, sizeof(u64));
+
+       location_ident->bLocationFlags |= CSMI_SAS_LOCATE_SAS_LUN_VALID;
+       memset(location_ident->bSASLun, 0, sizeof(location_ident->bSASLun));
+
+       /* SAS Enclosure Page 0 */
+       hdr.PageVersion = MPI_SASENCLOSURE0_PAGEVERSION;
+       hdr.ExtPageLength = 0;
+       hdr.PageNumber = 0;
+       hdr.Reserved1 = 0;
+       hdr.Reserved2 = 0;
+       hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
+       hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_ENCLOSURE;
+
+       cfg.cfghdr.ehdr = &hdr;
+       cfg.physAddr = -1;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+       cfg.dir = 0;    /* read */
+       cfg.timeout = MPT_IOCTL_DEFAULT_TIMEOUT;
+
+       if ((rc = mpt_config(ioc, &cfg)) != 0) {
+               rc=0;
+               goto fill_location_data_exit;
+       }
+
+       if (hdr.ExtPageLength == 0) {
+               rc=0;
+               goto fill_location_data_exit;
+       }
+
+       sasEnclosurePg0_data_sz = hdr.ExtPageLength * 4;
+       sasEnclosurePg0 = (SasEnclosurePage0_t *) pci_alloc_consistent(
+           ioc->pcidev, sasEnclosurePg0_data_sz, &sasEnclosurePg0_dma);
+       if (!sasEnclosurePg0) {
+               rc=0;
+               goto fill_location_data_exit;
+       }
+       cfg.physAddr = sasEnclosurePg0_dma;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+       cfg.pageAddr = sasDevicePg0->EnclosureHandle
+           + (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE << MPI_SAS_ENCLOS_PGAD_FORM_SHIFT);
+
+       if ((rc = mpt_config(ioc, &cfg)) != 0) {
+               rc=0;
+               goto fill_location_data_exit;
+       }
+
+       location_ident->bLocationFlags |= CSMI_SAS_LOCATE_ENCLOSURE_IDENTIFIER_VALID;
+       memcpy(&sas_address, &sasEnclosurePg0->EnclosureLogicalID, sizeof(u64));
+       sas_address = reverse_byte_order64(sas_address);
+       if (sas_address)
+               memcpy(location_ident->bEnclosureIdentifier, &sas_address, sizeof(u64));
+       else
+               strcpy(location_ident->bEnclosureIdentifier,"Internal");
+
+// bBayPrefix - not supported
+
+// TODO - We need to look at sasEnclosurePg0-.Flags , to determine
+//     whether SEP BUS/TargetID is valid.  Ifs its a SES device, then
+//     issue internal inquiry to (bus/id) to gather the Enclosure name.
+//     If the device is SMP, then issue SMP_MANUFACTURING to get enclosure name
+//     If its direct attached, there is no enclosure name
+       location_ident->bLocationFlags |= CSMI_SAS_LOCATE_ENCLOSURE_NAME_VALID;
+       strcpy(location_ident->bEnclosureName,"Not Supported");
+
+       location_ident->bLocationFlags |= CSMI_SAS_LOCATE_LOCATION_STATE_VALID;
+       location_ident->bLocationState = CSMI_SAS_LOCATE_UNKNOWN;
+
+       location_ident->bLocationFlags |= CSMI_SAS_LOCATE_BAY_IDENTIFIER_VALID;
+       location_ident->bBayIdentifier = le16_to_cpu(sasDevicePg0->Slot);
+
+
+// TODO - illuminating LEDs,
+// karg->bIdentify = CSMI_SAS_LOCATE_FORCE_OFF, CSMI_SAS_LOCATE_FORCE_ON
+// We can enable/disable LEDs by SCSI Enclosure Processor MPI request message
+// printk("Flags=0x%x\n",sasEnclosurePg0->Flags);
+
+/* check sasEnclosurePg0->Flags -
+ * to validate whether we need to send the SEPRequest
+ * bit:5 should be set
+ * bit:3-0 any bit should be set.  If zero, then SEPRequest will fail
+*/
+
+/* MPI_FUNCTION_SCSI_ENCLOSURE_PROCESSOR
+ * Look in mpi_init.h
+ * SEPRequest_t = structure
+ *
+ * SEPRequest_t->Action should be set to MPI_SEP_REQ_ACTION_WRITE_STATUS
+ *
+ * SEPRequest_t->Flags should be set to
+ * MPI_SEP_REQ_FLAGS_ENCLOSURE_SLOT_ADDRESS, to pass along enclosure/slot ids
+ *
+ * SEPRequest_t->SlotStatus |= MPI_SEP_REQ_SLOTSTATUS_IDENTIFY_REQUEST - this
+ * will illuminate the LEDs
+ */
+
+fill_location_data_exit:
+
+       if (sasDevicePg0 != NULL)
+               pci_free_consistent(ioc->pcidev, sasDevicePg0_data_sz,
+                   sasDevicePg0, sasDevicePg0_dma);
+
+       if (sasEnclosurePg0 != NULL)
+               pci_free_consistent(ioc->pcidev, sasEnclosurePg0_data_sz,
+                   sasEnclosurePg0, sasEnclosurePg0_dma);
+
+       dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__));
+       return rc;
+}
+
+static int
+csmisas_fill_location_data_raid(MPT_ADAPTER *ioc, PCSMI_SAS_GET_LOCATION_BUFFER karg, u8 VolumeBus,
+       u8 volumeID)
+{
+       pRaidVolumePage0_t              pVolume0 = NULL;
+       pRaidPhysDiskPage0_t            pPhysDisk0 = NULL;
+       CONFIGPARMS                     cfg;
+       ConfigPageHeader_t              header;
+       u8                              physDiskNumMax;
+       int                             volumepage0sz = 0, physdiskpage0sz = 0;
+       dma_addr_t                      volume0_dma, physdisk0_dma;
+       int                             csmi_sas_get_location_sz;
+       int                             rc = 0, i, idx;
+       int                             num_hotpares;
+       u64                             totalMaxLBA, tmpTotalMaxLBA;
+       IOCPage5_t                      *iocPage5 = NULL;
+       u32                             device_info = 0;
+       struct sas_device_info          *sas_info;
+
+       int                             sz;
+
+       csmi_sas_get_location_sz = karg->IoctlHeader.Length;
+       physDiskNumMax = (csmi_sas_get_location_sz -
+           offsetof(CSMI_SAS_GET_LOCATION_BUFFER,Location))
+           / sizeof(CSMI_SAS_LOCATION_IDENTIFIER);
+       karg->bNumberOfLocationIdentifiers=0;
+
+       /*
+        * get RAID Volume Page 0
+        */
+
+       header.PageVersion = 0;
+       header.PageLength = 0;
+       header.PageNumber = 0;
+       header.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
+       cfg.cfghdr.hdr = &header;
+       cfg.physAddr = -1;
+       cfg.pageAddr = (VolumeBus << 8) + volumeID;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+       cfg.dir = 0;
+       cfg.timeout = MPT_IOCTL_DEFAULT_TIMEOUT;
+       if (mpt_config(ioc, &cfg) != 0) {
+               rc = -1;
+               goto sas_fill_location_data_raid_exit;
+       }
+
+       if (header.PageLength == 0) {
+               rc = -1;
+               goto sas_fill_location_data_raid_exit;
+       }
+
+       volumepage0sz = header.PageLength * 4;
+       pVolume0 = pci_alloc_consistent(ioc->pcidev, volumepage0sz,
+           &volume0_dma);
+       if (!pVolume0) {
+               rc = -1;
+               goto sas_fill_location_data_raid_exit;
+       }
+
+       cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+       cfg.physAddr = volume0_dma;
+       if (mpt_config(ioc, &cfg) != 0){
+               rc = -1;
+               goto sas_fill_location_data_raid_exit;
+       }
+
+       totalMaxLBA = (u64)le32_to_cpu(pVolume0->MaxLBA) |
+           ((u64)le32_to_cpu(pVolume0->MaxLBAHigh)) << 32;
+
+       /*
+        * get RAID Physical Disk Page 0
+        */
+       header.PageVersion = 0;
+       header.PageLength = 0;
+       header.PageNumber = 0;
+       header.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
+       cfg.cfghdr.hdr = &header;
+       cfg.physAddr = -1;
+       cfg.pageAddr = 0;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+       cfg.dir = 0;
+       cfg.timeout = MPT_IOCTL_DEFAULT_TIMEOUT;
+       if (mpt_config(ioc, &cfg) != 0) {
+               rc = -1;
+               goto sas_fill_location_data_raid_exit;
+       }
+
+       if (header.PageLength == 0) {
+               rc = -1;
+               goto sas_fill_location_data_raid_exit;
+       }
+
+       physdiskpage0sz = header.PageLength * 4;
+       pPhysDisk0 = pci_alloc_consistent(ioc->pcidev, physdiskpage0sz,
+           &physdisk0_dma);
+       if (!pPhysDisk0) {
+               rc = -1;
+               goto sas_fill_location_data_raid_exit;
+       }
+       cfg.physAddr = physdisk0_dma;
+
+       for (i=0; i < min(pVolume0->NumPhysDisks, physDiskNumMax); i++) {
+
+               /* obtain a refresh of pPhysDisk0 */
+               cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+               cfg.pageAddr = pVolume0->PhysDisk[i].PhysDiskNum;
+               if (mpt_config(ioc, &cfg) != 0){
+                       rc = -1;
+                       goto sas_fill_location_data_raid_exit;
+               }
+
+               if((csmisas_fill_location_data(ioc, pPhysDisk0->PhysDiskBus,
+                   pPhysDisk0->PhysDiskID, karg->bIdentify,
+                   &karg->Location[karg->bNumberOfLocationIdentifiers])) == 0)
+                       karg->bNumberOfLocationIdentifiers++;
+
+               if (device_info)
+                       continue;
+               sas_info = csmisas_get_device_component_by_fw(ioc,
+                   pPhysDisk0->PhysDiskBus, pPhysDisk0->PhysDiskID);
+               if (!sas_info || sas_info->is_cached)
+                       continue;
+               device_info = sas_info->device_info;
+       }
+
+       if (pVolume0->VolumeType == MPI_RAID_VOL_TYPE_IS)
+               goto sas_fill_location_data_raid_exit;
+
+       /*
+        * hot spare support
+        *
+        */
+
+       num_hotpares = csmisas_get_number_hotspares(ioc);
+
+       if (num_hotpares) {
+
+               sz = offsetof(IOCPage5_t, HotSpare) +
+                   num_hotpares * sizeof(IOC_5_HOT_SPARE);
+               iocPage5 = kmalloc(sz, GFP_KERNEL);
+
+               if (!iocPage5)
+                       goto sas_fill_location_data_raid_exit;
+               memset(iocPage5, 0, sizeof(*iocPage5));
+
+               if (csmisas_get_ioc_pg5(ioc, iocPage5, sz) != 0)
+                       goto sas_fill_location_data_raid_exit;
+
+               for(i = 0, idx = pVolume0->NumPhysDisks ; i < num_hotpares;
+                   i++, idx++) {
+
+                       if (idx >= physDiskNumMax)
+                               break;
+
+                       /* obtain a refresh of pPhysDisk0 */
+                       cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+                       cfg.pageAddr = iocPage5->HotSpare[i].PhysDiskNum;
+                       if (mpt_config(ioc, &cfg) != 0)
+                               goto sas_fill_location_data_raid_exit;
+
+                       /* Search the list for the matching SAS address. */
+                       sas_info = csmisas_get_device_component_by_fw(ioc,
+                           pPhysDisk0->PhysDiskBus, pPhysDisk0->PhysDiskID);
+
+                       if (!sas_info || sas_info->is_cached)
+                               continue;
+
+                       /* don't mix SSP hot spare
+                        * in SATA volume
+                        */
+                       if (!csmisas_is_sata(pPhysDisk0) &&
+                           (device_info &
+                           MPI_SAS_DEVICE_INFO_SATA_DEVICE))
+                               continue;
+
+                       /* don't mix SATA hot spare
+                        * in SSP volume
+                        */
+                       if (csmisas_is_sata(pPhysDisk0) &&
+                           (device_info &
+                           MPI_SAS_DEVICE_INFO_SSP_TARGET))
+                               continue;
+
+                       /* capacity check for IM volumes*/
+                       if ((pVolume0->VolumeType ==
+                           MPI_RAID_VOL_TYPE_IM) &&
+                           (totalMaxLBA +
+                           (64*2*1024) /* metadata = 64MB*/ >
+                           le32_to_cpu(pPhysDisk0->MaxLBA)))
+                               continue;
+
+                       tmpTotalMaxLBA = totalMaxLBA;
+                       do_div(tmpTotalMaxLBA, pVolume0->NumPhysDisks);
+                       /* capacity check for IME volumes*/
+                       if ((pVolume0->VolumeType ==
+                               MPI_RAID_VOL_TYPE_IME) &&
+                           ((tmpTotalMaxLBA * 2) +
+                            (64*2*1024 ) /*metadata = 64MB*/ >
+                           le32_to_cpu(pPhysDisk0->MaxLBA)))
+                               continue;
+
+                       if((csmisas_fill_location_data(ioc,
+                           pPhysDisk0->PhysDiskBus, pPhysDisk0->PhysDiskID,
+                           karg->bIdentify,
+                           &karg->Location[karg->bNumberOfLocationIdentifiers])) == 0)
+                               karg->bNumberOfLocationIdentifiers++;
+               }
+       }
+
+
+ sas_fill_location_data_raid_exit:
+
+       kfree(iocPage5);
+
+       if (pVolume0)
+               pci_free_consistent(ioc->pcidev, volumepage0sz, pVolume0,
+                   volume0_dma);
+
+       if(pPhysDisk0)
+               pci_free_consistent(ioc->pcidev, physdiskpage0sz, pPhysDisk0,
+                   physdisk0_dma);
+
+       return rc;
+}
+
+/**
+ * Prototype Routine for the CSMI SAS Get location command.
+ *
+ * Outputs:    None.
+ * Return:     0 if successful
+ *             -EFAULT if data unavailable
+ *             -ENODEV if no such device/adapter
+ */
+static int
+csmisas_get_location(unsigned long arg)
+{
+       CSMI_SAS_GET_LOCATION_BUFFER __user *uarg = (void __user *) arg;
+       PCSMI_SAS_GET_LOCATION_BUFFER   karg;
+       IOCTL_HEADER                    ioctl_header;
+       MPT_ADAPTER                     *ioc = NULL;
+       int                             iocnum,i;
+       int                             csmi_sas_get_location_sz;
+       int                             memory_pages;
+       struct sas_device_info          *sas_info;
+
+       if (copy_from_user(&ioctl_header, uarg, sizeof(IOCTL_HEADER))) {
+               printk(KERN_ERR "%s@%d::%s() - "
+                   "Unable to read in IOCTL_HEADER"
+                   "struct @ %p\n", __FILE__, __LINE__, __FUNCTION__, uarg);
+               return -EFAULT;
+       }
+
+       csmi_sas_get_location_sz = ioctl_header.Length;
+       memory_pages = get_order(csmi_sas_get_location_sz);
+       karg = (PCSMI_SAS_GET_LOCATION_BUFFER)__get_free_pages(
+               GFP_KERNEL, memory_pages);
+       if (!karg){
+               printk(KERN_ERR "%s@%d::%s() - "
+                       "Unable to malloc GET_LOCATION_BUFFER "
+                       "csmi_sas_get_location_sz=%d memory_pages=%d\n",
+                       __FILE__, __LINE__, __FUNCTION__, 
+                       csmi_sas_get_location_sz, memory_pages);
+               return -ENOMEM;
+       }
+       memset(karg, 0, sizeof(*karg));
+
+       if (copy_from_user(karg, uarg, csmi_sas_get_location_sz)) {
+               printk(KERN_ERR "%s@%d::%s() - "
+                   "Unable to read in csmi_sas_phy_control_buffer "
+                   "struct @ %p\n", __FILE__, __LINE__, __FUNCTION__, uarg);
+               free_pages((unsigned long)karg, memory_pages);
+               return -EFAULT;
+       }
+
+       if (((iocnum = mpt_verify_adapter(karg->IoctlHeader.IOControllerNumber,
+           &ioc)) < 0) || (ioc == NULL)) {
+               printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n",
+                   __FILE__, __FUNCTION__, __LINE__, iocnum);
+               free_pages((unsigned long)karg, memory_pages);
+               return -ENODEV;
+       }
+
+       if (!csmisas_is_this_sas_cntr(ioc)) {
+               printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n",
+                   __FILE__, __FUNCTION__, __LINE__, iocnum);
+               free_pages((unsigned long)karg, memory_pages);
+               return -ENODEV;
+       }
+
+       dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__));
+
+       karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_INVALID_PARAMETER;
+       if(karg->bLengthOfLocationIdentifier !=
+           sizeof(CSMI_SAS_LOCATION_IDENTIFIER))
+               goto cim_sas_get_location_exit;
+
+       sas_info = csmisas_get_device_component_by_os(ioc, karg->bPathId,
+           karg->bTargetId);
+       if (!sas_info)
+               goto cim_sas_get_location_exit;
+
+       /* RAID SUPPORT */
+       if (ioc->raid_data.pIocPg2 && sas_info->is_logical_volume) {
+               for (i=0; i<ioc->raid_data.pIocPg2->NumActiveVolumes; i++){
+                       if (sas_info->fw.id ==
+                           ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID &&
+                           sas_info->fw.channel ==
+                           ioc->raid_data.pIocPg2->RaidVolume[i].VolumeBus) {
+                               if(csmisas_fill_location_data_raid(ioc, karg,
+                                   ioc->raid_data.pIocPg2->RaidVolume[i].VolumeBus,
+                                   ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID) == 0)
+                                       karg->IoctlHeader.ReturnCode =
+                                           CSMI_SAS_STATUS_SUCCESS;
+                               else
+                                       karg->IoctlHeader.ReturnCode =
+                                           CSMI_SAS_STATUS_FAILED;
+                               goto cim_sas_get_location_exit;
+                       }
+               }
+       }
+
+       /* NON-RAID SUPPORT */
+       if (sas_info->is_cached || sas_info->is_logical_volume)
+               goto cim_sas_get_location_exit;
+
+       /* make sure there's enough room to populate the Location[] struct */
+       if ((csmi_sas_get_location_sz -
+           offsetof(CSMI_SAS_GET_LOCATION_BUFFER,Location)) <
+           sizeof(CSMI_SAS_LOCATION_IDENTIFIER))
+               goto cim_sas_get_location_exit;
+
+       karg->bNumberOfLocationIdentifiers=1;
+       karg->Location[0].bLocationFlags=0;
+       if((csmisas_fill_location_data(ioc, sas_info->fw.channel,
+           sas_info->fw.id, karg->bIdentify, &karg->Location[0])) == 0)
+               karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS;
+       else
+               karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED;
+
+ cim_sas_get_location_exit:
+
+       /* Copy the data from kernel memory to user memory
+        */
+       if (copy_to_user(uarg, karg, csmi_sas_get_location_sz)) {
+               printk(KERN_ERR "%s@%d::%s() - "
+                   "Unable to write out csmi_sas_get_location_buffer "
+                   "@ %p\n",__FILE__, __LINE__, __FUNCTION__, uarg);
+               free_pages((unsigned long)karg, memory_pages);
+               return -EFAULT;
+       }
+
+       dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__));
+       free_pages((unsigned long)karg, memory_pages);
+       return 0;
+}
diff --git a/drivers/message/fusion/csmi/csmisas.h b/drivers/message/fusion/csmi/csmisas.h
new file mode 100644 (file)
index 0000000..7e9dffb
--- /dev/null
@@ -0,0 +1,1854 @@
+/**************************************************************************
+
+Module Name:
+
+   CSMISAS.H
+
+
+Abstract:
+
+   This file contains constants and data structure definitions used by drivers
+   that support the Common Storage Management Interface specification for
+   SAS or SATA in either the Windows or Linux.
+
+   This should be considered as a reference implementation only.  Changes may
+   be necessary to accommodate a specific build environment or target OS.
+
+Revision History:
+
+   001  SEF   8/12/03  Initial release.
+   002  SEF   8/20/03  Cleanup to match documentation.
+   003  SEF   9/12/03  Additional cleanup, created combined header
+   004  SEF   9/23/03  Changed base types to match linux defaults
+                       Added RAID signature
+                       Added bControllerFlags to CSMI_SAS_CNTLR_CONFIG
+                       Changed CSMI_SAS_BEGIN_PACK to 8 for common structures
+                       Fixed other typos identified in first compilation test
+   005  SEF  10/03/03  Additions to match first version of CSMI document
+   006  SEF  10/14/03  Fixed typedef struct _CSMI_SAS_SMP_PASSTHRU_BUFFER
+                       Added defines for bConnectionRate
+   007  SEF  10/15/03  Added Firmware Download Control Code and support
+                       Added CSMI revision support
+   008  SEF  10/30/03  No functional change, just updated version to track
+                       spec changes
+   009  SEF  12/09/03  No functional change, just updated version to track
+                       spec changes
+   010  SEF   3/11/04  Fixed typedef struct CSMI_SAS_RAID_DRIVES to include the
+                       bFirmware member that is defined in the spec, but
+                       was missing in this file,
+                       added CC_CSMI_SAS_TASK_MANAGEMENT
+   011  SEF   4/02/04  No functional change, added comment line before
+                       CC_CSMI_SAS_TASK_MANAGEMENT
+   012  SEF   4/16/04  Added IOControllerNumber to linux header,
+                       Modified linux control codes to have upper word of
+                       0xCC77.... to indicate CSMI version 77
+                       Added bSignalClass to CC_CSMI_SET_PHY_INFO
+                       Added CC_CSMI_SAS_PHY_CONTROL support
+   013  SEF   5/14/04  Added CC_CSMI_SAS_GET_CONNECTOR_INFO support
+   014  SEF   5/24/04  No functional change, just updated version to track spec
+                       changes
+   015  SEF   6/16/04  changed bPinout to uPinout to reflect proper size,
+                       changed width of bLocation defines to reflect size
+   016  SEF   6/17/04  changed bLengthOfControls in CSMI_SAS_PHY_CONTROL
+                       to be proper size
+   017  SEF   9/17/04  added CSMI_SAS_SATA_PORT_SELECTOR,
+                       CSMI_SAS_LINK_VIRTUAL, CSMI_SAS_CON_NOT_PRESENT, and
+                       CSMI_SAS_CON_NOT_CONNECTED
+   018  SEF   9/20/04  added CSMI_SAS_PHY_USER_PATTERN,
+                       changed definition of CSMI_SAS_PHY_FIXED_PATTERN to not
+                       conflict with activate definition
+   019  SEF  12/06/04  added CSMI_SAS_GET_LOCATION
+                       added bSSPStatus to CSMI_SAS_SSP_PASSTHRU_STATUS
+                       structure
+   020  SEF   5/25/05  added CSMI_SAS_PHY_VIRTUAL_SMP, and changes to
+                       CSMI_SAS_GET_LOCATION
+   021  SEF  11/03/05  added new RAID creation functionality
+   022  SEF   2/01/06  corrected typo bNegotitiatedLInkRate
+                       Added two more RAID_TYPES, 7 and 8
+   023  SEF   4/04/06  added CSMI_RAID_TYPE_1E
+                       changed structures that contained surface scan
+                       to priority approach rather than time, causes
+                       0.89 to incompatible with 0.87, so a version
+                       check is necessary when interpreting the
+                       raid structures
+                       Added netware section
+   024 DRG    5/22/06  Added uFailureCode to CSMI_SAS_RAID_CONFIG and
+                       CSMI_SAS_RAID_FEATURES
+                       Changed __u64 fields to high and low __u32 fields in
+                       order to avoid backward compatibility issues with
+                       packing and alignment.
+                       Fixed alignment problem in CSMI_SAS_RAID_DRIVES.
+                       Added CSMI_SAS_CNTLR_SMART_ARRAY to uControllerFlags
+                       Reassigned the value of CSMI_SAS_CNTLR_RAID_CFG_SUPPORT
+                       to avoid a conflict.
+
+**************************************************************************/
+
+#ifndef _CSMI_SAS_H_
+#define _CSMI_SAS_H_
+
+// CSMI Specification Revision, the intent is that all versions of the
+// specification will be backward compatible after the 1.00 release.
+// Major revision number, corresponds to xxxx. of CSMI specification
+// Minor revision number, corresponds to .xxxx of CSMI specification
+#define CSMI_MAJOR_REVISION   0
+#define CSMI_MINOR_REVISION   90
+
+/*************************************************************************/
+/* PATCHES FOR TYPOS                                                     */
+/*************************************************************************/
+
+#define bNegotitiatedLInkRate bNegotiatedLinkRate
+
+/*************************************************************************/
+/* TARGET OS LINUX SPECIFIC CODE                                         */
+/*************************************************************************/
+
+// EDM #ifdef _linux
+#ifdef __KERNEL__
+
+// Linux base types
+
+#include <linux/types.h>
+
+#define __i8    char
+
+// pack definition
+
+// EDM #define CSMI_SAS_BEGIN_PACK(x)    pack(x)
+// EDM #define CSMI_SAS_END_PACK         pack()
+
+// IOCTL Control Codes
+// (IoctlHeader.ControlCode)
+
+// Control Codes prior to 0.77
+
+// Control Codes requiring CSMI_ALL_SIGNATURE
+
+// #define CC_CSMI_SAS_GET_DRIVER_INFO    0x12345678
+// #define CC_CSMI_SAS_GET_CNTLR_CONFIG   0x23456781
+// #define CC_CSMI_SAS_GET_CNTLR_STATUS   0x34567812
+// #define CC_CSMI_SAS_FIRMWARE_DOWNLOAD  0x92345678
+
+// Control Codes requiring CSMI_RAID_SIGNATURE
+
+// #define CC_CSMI_SAS_GET_RAID_INFO      0x45678123
+// #define CC_CSMI_SAS_GET_RAID_CONFIG    0x56781234
+
+// Control Codes requiring CSMI_SAS_SIGNATURE
+
+// #define CC_CSMI_SAS_GET_PHY_INFO       0x67812345
+// #define CC_CSMI_SAS_SET_PHY_INFO       0x78123456
+// #define CC_CSMI_SAS_GET_LINK_ERRORS    0x81234567
+// #define CC_CSMI_SAS_SMP_PASSTHRU       0xA1234567
+// #define CC_CSMI_SAS_SSP_PASSTHRU       0xB1234567
+// #define CC_CSMI_SAS_STP_PASSTHRU       0xC1234567
+// #define CC_CSMI_SAS_GET_SATA_SIGNATURE 0xD1234567
+// #define CC_CSMI_SAS_GET_SCSI_ADDRESS   0xE1234567
+// #define CC_CSMI_SAS_GET_DEVICE_ADDRESS 0xF1234567
+// #define CC_CSMI_SAS_TASK_MANAGEMENT    0xA2345678
+
+// Control Codes for 0.77 and later
+
+// Control Codes requiring CSMI_ALL_SIGNATURE
+
+#define CC_CSMI_SAS_GET_DRIVER_INFO    0xCC770001
+#define CC_CSMI_SAS_GET_CNTLR_CONFIG   0xCC770002
+#define CC_CSMI_SAS_GET_CNTLR_STATUS   0xCC770003
+#define CC_CSMI_SAS_FIRMWARE_DOWNLOAD  0xCC770004
+
+// Control Codes requiring CSMI_RAID_SIGNATURE
+
+#define CC_CSMI_SAS_GET_RAID_INFO      0xCC77000A
+#define CC_CSMI_SAS_GET_RAID_CONFIG    0xCC77000B
+#define CC_CSMI_SAS_GET_RAID_FEATURES  0xCC77000C
+#define CC_CSMI_SAS_SET_RAID_CONTROL   0xCC77000D
+#define CC_CSMI_SAS_GET_RAID_ELEMENT   0xCC77000E
+#define CC_CSMI_SAS_SET_RAID_OPERATION 0xCC77000F
+
+// Control Codes requiring CSMI_SAS_SIGNATURE
+
+#define CC_CSMI_SAS_GET_PHY_INFO       0xCC770014
+#define CC_CSMI_SAS_SET_PHY_INFO       0xCC770015
+#define CC_CSMI_SAS_GET_LINK_ERRORS    0xCC770016
+#define CC_CSMI_SAS_SMP_PASSTHRU       0xCC770017
+#define CC_CSMI_SAS_SSP_PASSTHRU       0xCC770018
+#define CC_CSMI_SAS_STP_PASSTHRU       0xCC770019
+#define CC_CSMI_SAS_GET_SATA_SIGNATURE 0xCC770020
+#define CC_CSMI_SAS_GET_SCSI_ADDRESS   0xCC770021
+#define CC_CSMI_SAS_GET_DEVICE_ADDRESS 0xCC770022
+#define CC_CSMI_SAS_TASK_MANAGEMENT    0xCC770023
+#define CC_CSMI_SAS_GET_CONNECTOR_INFO 0xCC770024
+#define CC_CSMI_SAS_GET_LOCATION       0xCC770025
+
+
+// Control Codes requiring CSMI_PHY_SIGNATURE
+
+#define CC_CSMI_SAS_PHY_CONTROL        0xCC77003C
+
+// EDM #pragma CSMI_SAS_BEGIN_PACK(8)
+#pragma pack(8)
+
+// IOCTL_HEADER
+typedef struct _IOCTL_HEADER {
+    __u32 IOControllerNumber;
+    __u32 Length;
+    __u32 ReturnCode;
+    __u32 Timeout;
+    __u16 Direction;
+} IOCTL_HEADER,
+  *PIOCTL_HEADER;
+
+// EDM #pragma CSMI_SAS_END_PACK
+#pragma pack()
+
+#endif
+
+/*************************************************************************/
+/* TARGET OS WINDOWS SPECIFIC CODE                                       */
+/*************************************************************************/
+
+#ifdef _WIN32
+
+// windows IOCTL definitions
+
+#ifndef _NTDDSCSIH_
+#include <ntddscsi.h>
+#endif
+
+// pack definition
+
+#if defined _MSC_VER
+   #define CSMI_SAS_BEGIN_PACK(x)    pack(push,x)
+   #define CSMI_SAS_END_PACK         pack(pop)
+#elif defined __BORLANDC__
+   #define CSMI_SAS_BEGIN_PACK(x)    option -a##x
+   #define CSMI_SAS_END_PACK         option -a.
+#else
+   #error "CSMISAS.H - Must externally define a pack compiler designator."
+#endif
+
+// base types
+
+#define __u8    unsigned char
+#define __u16   unsigned short
+#define __u32   unsigned long
+#define __u64   unsigned __int64
+
+#define __i8    char
+
+// IOCTL Control Codes
+// (IoctlHeader.ControlCode)
+
+// Control Codes requiring CSMI_ALL_SIGNATURE
+
+#define CC_CSMI_SAS_GET_DRIVER_INFO    1
+#define CC_CSMI_SAS_GET_CNTLR_CONFIG   2
+#define CC_CSMI_SAS_GET_CNTLR_STATUS   3
+#define CC_CSMI_SAS_FIRMWARE_DOWNLOAD  4
+
+// Control Codes requiring CSMI_RAID_SIGNATURE
+
+#define CC_CSMI_SAS_GET_RAID_INFO      10
+#define CC_CSMI_SAS_GET_RAID_CONFIG    11
+#define CC_CSMI_SAS_GET_RAID_FEATURES  12
+#define CC_CSMI_SAS_SET_RAID_CONTROL   13
+#define CC_CSMI_SAS_GET_RAID_ELEMENT   14
+#define CC_CSMI_SAS_SET_RAID_OPERATION 15
+
+// Control Codes requiring CSMI_SAS_SIGNATURE
+
+#define CC_CSMI_SAS_GET_PHY_INFO       20
+#define CC_CSMI_SAS_SET_PHY_INFO       21
+#define CC_CSMI_SAS_GET_LINK_ERRORS    22
+#define CC_CSMI_SAS_SMP_PASSTHRU       23
+#define CC_CSMI_SAS_SSP_PASSTHRU       24
+#define CC_CSMI_SAS_STP_PASSTHRU       25
+#define CC_CSMI_SAS_GET_SATA_SIGNATURE 26
+#define CC_CSMI_SAS_GET_SCSI_ADDRESS   27
+#define CC_CSMI_SAS_GET_DEVICE_ADDRESS 28
+#define CC_CSMI_SAS_TASK_MANAGEMENT    29
+#define CC_CSMI_SAS_GET_CONNECTOR_INFO 30
+#define CC_CSMI_SAS_GET_LOCATION       31
+
+// Control Codes requiring CSMI_PHY_SIGNATURE
+
+#define CC_CSMI_SAS_PHY_CONTROL        60
+
+#define IOCTL_HEADER SRB_IO_CONTROL
+#define PIOCTL_HEADER PSRB_IO_CONTROL
+
+#endif
+
+/*************************************************************************/
+/* TARGET OS NETWARE SPECIFIC CODE                                       */
+/*************************************************************************/
+
+#ifdef _NETWARE
+
+// NetWare IOCTL definitions
+
+#define CSMI_SAS_BEGIN_PACK(x)    pack(x)
+#define CSMI_SAS_END_PACK         pack()
+
+#ifndef LONG
+typedef unsigned long LONG;
+#endif
+
+#ifndef WORD
+typedef unsigned short WORD;
+#endif
+
+#ifndef BYTE
+typedef unsigned char BYTE;
+#endif
+
+/* Need to have these definitions for Netware */
+#define __u8    unsigned char
+#define __u16   unsigned short
+#define __u32   unsigned long
+#define __u64   unsigned __int64
+
+#define __i8    char
+
+
+// EDM #pragma CSMI_SAS_BEGIN_PACK(8)
+#pragma pack(8)
+
+// IOCTL_HEADER
+typedef struct _IOCTL_HEADER {
+    __u32 Length;
+    __u32 ReturnCode;
+} IOCTL_HEADER,
+  *PIOCTL_HEADER;
+
+// EDM #pragma CSMI_SAS_END_PACK
+#pragma pack()
+
+// IOCTL Control Codes
+// (IoctlHeader.ControlCode)
+
+// Control Codes requiring CSMI_ALL_SIGNATURE
+
+#define CC_CSMI_SAS_GET_DRIVER_INFO    0x01FF0001
+#define CC_CSMI_SAS_GET_CNTLR_CONFIG   0x01FF0002
+#define CC_CSMI_SAS_GET_CNTLR_STATUS   0x01FF0003
+#define CC_CSMI_SAS_FIRMWARE_DOWNLOAD  0x01FF0004
+
+// Control Codes requiring CSMI_RAID_SIGNATURE
+
+#define CC_CSMI_SAS_GET_RAID_INFO      0x01FF000A
+#define CC_CSMI_SAS_GET_RAID_CONFIG    0x01FF000B
+#define CC_CSMI_SAS_GET_RAID_FEATURES  0x01FF000C
+#define CC_CSMI_SAS_SET_RAID_CONTROL   0x01FF000D
+#define CC_CSMI_SAS_GET_RAID_ELEMENT   0x01FF000E
+#define CC_CSMI_SAS_SET_RAID_OPERATION 0x01FF000F
+
+// Control Codes requiring CSMI_SAS_SIGNATURE
+
+#define CC_CSMI_SAS_GET_PHY_INFO       0x01FF0014
+#define CC_CSMI_SAS_SET_PHY_INFO       0x01FF0015
+#define CC_CSMI_SAS_GET_LINK_ERRORS    0x01FF0016
+#define CC_CSMI_SAS_SMP_PASSTHRU       0x01FF0017
+#define CC_CSMI_SAS_SSP_PASSTHRU       0x01FF0018
+#define CC_CSMI_SAS_STP_PASSTHRU       0x01FF0019
+#define CC_CSMI_SAS_GET_SATA_SIGNATURE 0x01FF001A
+#define CC_CSMI_SAS_GET_SCSI_ADDRESS   0x01FF001B
+#define CC_CSMI_SAS_GET_DEVICE_ADDRESS 0x01FF001C
+#define CC_CSMI_SAS_TASK_MANAGEMENT    0x01FF001D
+#define CC_CSMI_SAS_GET_CONNECTOR_INFO 0x01FF001E
+#define CC_CSMI_SAS_GET_LOCATION       0x01FF001F
+
+// Control Codes requiring CSMI_PHY_SIGNATURE
+
+#define CC_CSMI_SAS_PHY_CONTROL        60
+
+#endif
+
+/*************************************************************************/
+/* TARGET OS NOT DEFINED ERROR                                           */
+/*************************************************************************/
+
+// EDM
+//#if (!_WIN32 && !_linux && !_NETWARE)
+//   #error "Unknown target OS."
+//#endif
+
+/*************************************************************************/
+/* OS INDEPENDENT CODE                                                   */
+/*************************************************************************/
+
+/* * * * * * * * * * Class Independent IOCTL Constants * * * * * * * * * */
+
+// Return codes for all IOCTL's regardless of class
+// (IoctlHeader.ReturnCode)
+
+#define CSMI_SAS_STATUS_SUCCESS              0
+#define CSMI_SAS_STATUS_FAILED               1
+#define CSMI_SAS_STATUS_BAD_CNTL_CODE        2
+#define CSMI_SAS_STATUS_INVALID_PARAMETER    3
+#define CSMI_SAS_STATUS_WRITE_ATTEMPTED      4
+
+// Signature value
+// (IoctlHeader.Signature)
+
+#define CSMI_ALL_SIGNATURE    "CSMIALL"
+
+// Timeout value default of 60 seconds
+// (IoctlHeader.Timeout)
+
+#define CSMI_ALL_TIMEOUT      60
+
+//  Direction values for data flow on this IOCTL
+// (IoctlHeader.Direction, Linux only)
+#define CSMI_SAS_DATA_READ    0
+#define CSMI_SAS_DATA_WRITE   1
+
+// I/O Bus Types
+// ISA and EISA bus types are not supported
+// (bIoBusType)
+
+#define CSMI_SAS_BUS_TYPE_PCI       3
+#define CSMI_SAS_BUS_TYPE_PCMCIA    4
+
+// Controller Status
+// (uStatus)
+
+#define CSMI_SAS_CNTLR_STATUS_GOOD     1
+#define CSMI_SAS_CNTLR_STATUS_FAILED   2
+#define CSMI_SAS_CNTLR_STATUS_OFFLINE  3
+#define CSMI_SAS_CNTLR_STATUS_POWEROFF 4
+
+// Offline Status Reason
+// (uOfflineReason)
+
+#define CSMI_SAS_OFFLINE_REASON_NO_REASON             0
+#define CSMI_SAS_OFFLINE_REASON_INITIALIZING          1
+#define CSMI_SAS_OFFLINE_REASON_BACKSIDE_BUS_DEGRADED 2
+#define CSMI_SAS_OFFLINE_REASON_BACKSIDE_BUS_FAILURE  3
+
+// Controller Class
+// (bControllerClass)
+
+#define CSMI_SAS_CNTLR_CLASS_HBA    5
+
+// Controller Flag bits
+// (uControllerFlags)
+
+#define CSMI_SAS_CNTLR_SAS_HBA          0x00000001
+#define CSMI_SAS_CNTLR_SAS_RAID         0x00000002
+#define CSMI_SAS_CNTLR_SATA_HBA         0x00000004
+#define CSMI_SAS_CNTLR_SATA_RAID        0x00000008
+#define CSMI_SAS_CNTLR_SMART_ARRAY      0x00000010
+
+// for firmware download
+#define CSMI_SAS_CNTLR_FWD_SUPPORT      0x00010000
+#define CSMI_SAS_CNTLR_FWD_ONLINE       0x00020000
+#define CSMI_SAS_CNTLR_FWD_SRESET       0x00040000
+#define CSMI_SAS_CNTLR_FWD_HRESET       0x00080000
+#define CSMI_SAS_CNTLR_FWD_RROM         0x00100000
+
+// for RAID configuration supported
+#define CSMI_SAS_CNTLR_RAID_CFG_SUPPORT 0x01000000
+
+// Download Flag bits
+// (uDownloadFlags)
+#define CSMI_SAS_FWD_VALIDATE       0x00000001
+#define CSMI_SAS_FWD_SOFT_RESET     0x00000002
+#define CSMI_SAS_FWD_HARD_RESET     0x00000004
+
+// Firmware Download Status
+// (usStatus)
+#define CSMI_SAS_FWD_SUCCESS        0
+#define CSMI_SAS_FWD_FAILED         1
+#define CSMI_SAS_FWD_USING_RROM     2
+#define CSMI_SAS_FWD_REJECT         3
+#define CSMI_SAS_FWD_DOWNREV        4
+
+// Firmware Download Severity
+// (usSeverity>
+#define CSMI_SAS_FWD_INFORMATION    0
+#define CSMI_SAS_FWD_WARNING        1
+#define CSMI_SAS_FWD_ERROR          2
+#define CSMI_SAS_FWD_FATAL          3
+
+/* * * * * * * * * * SAS RAID Class IOCTL Constants  * * * * * * * * */
+
+// Return codes for the RAID IOCTL's regardless of class
+// (IoctlHeader.ReturnCode)
+
+#define CSMI_SAS_RAID_SET_OUT_OF_RANGE       1000
+#define CSMI_SAS_RAID_SET_BUFFER_TOO_SMALL   1001
+#define CSMI_SAS_RAID_SET_DATA_CHANGED       1002
+
+// Signature value
+// (IoctlHeader.Signature)
+
+#define CSMI_RAID_SIGNATURE    "CSMIARY"
+
+// Timeout value default of 60 seconds
+// (IoctlHeader.Timeout)
+
+#define CSMI_RAID_TIMEOUT      60
+
+// RAID Types
+// (bRaidType)
+#define CSMI_SAS_RAID_TYPE_NONE     0
+#define CSMI_SAS_RAID_TYPE_0        1
+#define CSMI_SAS_RAID_TYPE_1        2
+#define CSMI_SAS_RAID_TYPE_10       3
+#define CSMI_SAS_RAID_TYPE_5        4
+#define CSMI_SAS_RAID_TYPE_15       5
+#define CSMI_SAS_RAID_TYPE_6        6
+#define CSMI_SAS_RAID_TYPE_50       7
+#define CSMI_SAS_RAID_TYPE_VOLUME   8
+#define CSMI_SAS_RAID_TYPE_1E       9
+#define CSMI_SAS_RAID_TYPE_OTHER    255
+// the last value 255 was already defined for other
+// so end is defined as 254
+#define CSMI_SAS_RAID_TYPE_END      254
+
+// RAID Status
+// (bStatus)
+#define CSMI_SAS_RAID_SET_STATUS_OK             0
+#define CSMI_SAS_RAID_SET_STATUS_DEGRADED       1
+#define CSMI_SAS_RAID_SET_STATUS_REBUILDING     2
+#define CSMI_SAS_RAID_SET_STATUS_FAILED         3
+#define CSMI_SAS_RAID_SET_STATUS_OFFLINE        4
+#define CSMI_SAS_RAID_SET_STATUS_TRANSFORMING   5
+#define CSMI_SAS_RAID_SET_STATUS_QUEUED_FOR_REBUILD         6
+#define CSMI_SAS_RAID_SET_STATUS_QUEUED_FOR_TRANSFORMATION  7
+
+// RAID Drive Count
+// (bDriveCount, 0xF1 to 0xFF are reserved)
+#define CSMI_SAS_RAID_DRIVE_COUNT_TOO_BIG   0xF1
+#define CSMI_SAS_RAID_DRIVE_COUNT_SUPRESSED 0xF2
+
+// RAID Data Type
+// (bDataType)
+#define CSMI_SAS_RAID_DATA_DRIVES           0
+#define CSMI_SAS_RAID_DATA_DEVICE_ID        1
+#define CSMI_SAS_RAID_DATA_ADDITIONAL_DATA  2
+
+// RAID Drive Status
+// (bDriveStatus)
+#define CSMI_SAS_DRIVE_STATUS_OK          0
+#define CSMI_SAS_DRIVE_STATUS_REBUILDING  1
+#define CSMI_SAS_DRIVE_STATUS_FAILED      2
+#define CSMI_SAS_DRIVE_STATUS_DEGRADED    3
+#define CSMI_SAS_DRIVE_STATUS_OFFLINE     4
+#define CSMI_SAS_DRIVE_STATUS_QUEUED_FOR_REBUILD 5
+
+// RAID Drive Usage
+// (bDriveUsage)
+#define CSMI_SAS_DRIVE_CONFIG_NOT_USED      0
+#define CSMI_SAS_DRIVE_CONFIG_MEMBER        1
+#define CSMI_SAS_DRIVE_CONFIG_SPARE         2
+#define CSMI_SAS_DRIVE_CONFIG_SPARE_ACTIVE  3
+
+// RAID Drive Type
+// (bDriveType)
+#define CSMI_SAS_DRIVE_TYPE_UNKNOWN         0
+#define CSMI_SAS_DRIVE_TYPE_SINGLE_PORT_SAS 1
+#define CSMI_SAS_DRIVE_TYPE_DUAL_PORT_SAS   2
+#define CSMI_SAS_DRIVE_TYPE_SATA            3
+#define CSMI_SAS_DRIVE_TYPE_SATA_PS         4
+#define CSMI_SAS_DRIVE_TYPE_OTHER           255
+
+// RAID Write Protect
+// (bWriteProtect)
+#define CSMI_SAS_RAID_SET_WRITE_PROTECT_UNKNOWN     0
+#define CSMI_SAS_RAID_SET_WRITE_PROTECT_UNCHANGED   0
+#define CSMI_SAS_RAID_SET_WRITE_PROTECT_ENABLED     1
+#define CSMI_SAS_RAID_SET_WRITE_PROTECT_DISABLED    2
+
+// RAID Cache Setting
+// (bCacheSetting)
+#define CSMI_SAS_RAID_SET_CACHE_UNKNOWN             0
+#define CSMI_SAS_RAID_SET_CACHE_UNCHANGED           0
+#define CSMI_SAS_RAID_SET_CACHE_ENABLED             1
+#define CSMI_SAS_RAID_SET_CACHE_DISABLED            2
+#define CSMI_SAS_RAID_SET_CACHE_CORRUPT             3
+
+// RAID Features
+// (uFeatures)
+#define CSMI_SAS_RAID_FEATURE_TRANSFORMATION    0x00000001
+#define CSMI_SAS_RAID_FEATURE_REBUILD           0x00000002
+#define CSMI_SAS_RAID_FEATURE_SPLIT_MIRROR      0x00000004
+#define CSMI_SAS_RAID_FEATURE_MERGE_MIRROR      0x00000008
+#define CSMI_SAS_RAID_FEATURE_LUN_RENUMBER      0x00000010
+#define CSMI_SAS_RAID_FEATURE_SURFACE_SCAN      0x00000020
+#define CSMI_SAS_RAID_FEATURE_SPARES_SHARED     0x00000040
+
+// RAID Priority
+// (bDefaultTransformPriority, etc.)
+#define CSMI_SAS_PRIORITY_UNKNOWN   0
+#define CSMI_SAS_PRIORITY_UNCHANGED 0
+#define CSMI_SAS_PRIORITY_AUTO      1
+#define CSMI_SAS_PRIORITY_OFF       2
+#define CSMI_SAS_PRIORITY_LOW       3
+#define CSMI_SAS_PRIORITY_MEDIUM    4
+#define CSMI_SAS_PRIORITY_HIGH      5
+
+// RAID Transformation Rules
+// (uRaidSetTransformationRules)
+#define CSMI_SAS_RAID_RULE_AVAILABLE_MEMORY     0x00000001
+#define CSMI_SAS_RAID_RULE_OVERLAPPED_EXTENTS   0x00000002
+
+// RAID Cache Ratios Supported
+// (bCacheRatiosSupported)
+// from 0 to 100 defines the write to read ratio, 0 is 100% write
+#define CSMI_SAS_RAID_CACHE_RATIO_RANGE     101
+#define CSMI_SAS_RAID_CACHE_RATIO_FIXED     102
+#define CSMI_SAS_RAID_CACHE_RATIO_AUTO      103
+#define CSMI_SAS_RAID_CACHE_RATIO_END       255
+
+// RAID Cache Ratio Flag
+// (bCacheRatioFlag)
+#define CSMI_SAS_RAID_CACHE_RATIO_DISABLE   0
+#define CSMI_SAS_RAID_CACHE_RATIO_ENABLE    1
+
+// RAID Clear Configuration Signature
+// (bClearConfiguration)
+#define CSMI_SAS_RAID_CLEAR_CONFIGURATION_SIGNATURE "RAIDCLR"
+
+// RAID Failure Codes
+// (uFailureCode)
+#define CSMI_SAS_FAIL_CODE_OK                           0
+#define CSMI_SAS_FAIL_CODE_PARAMETER_INVALID            1000
+#define CSMI_SAS_FAIL_CODE_TRANSFORM_PRIORITY_INVALID   1001
+#define CSMI_SAS_FAIL_CODE_REBUILD_PRIORITY_INVALID     1002
+#define CSMI_SAS_FAIL_CODE_CACHE_RATIO_INVALID          1003
+#define CSMI_SAS_FAIL_CODE_SURFACE_SCAN_INVALID         1004
+#define CSMI_SAS_FAIL_CODE_CLEAR_CONFIGURATION_INVALID  1005
+#define CSMI_SAS_FAIL_CODE_ELEMENT_INDEX_INVALID        1006
+#define CSMI_SAS_FAIL_CODE_SUBELEMENT_INDEX_INVALID     1007
+#define CSMI_SAS_FAIL_CODE_EXTENT_INVALID               1008
+#define CSMI_SAS_FAIL_CODE_BLOCK_COUNT_INVALID          1009
+#define CSMI_SAS_FAIL_CODE_DRIVE_INDEX_INVALID          1010
+#define CSMI_SAS_FAIL_CODE_EXISTING_LUN_INVALID         1011
+#define CSMI_SAS_FAIL_CODE_RAID_TYPE_INVALID            1012
+#define CSMI_SAS_FAIL_CODE_STRIPE_SIZE_INVALID          1013
+#define CSMI_SAS_FAIL_CODE_TRANSFORMATION_INVALID       1014
+#define CSMI_SAS_FAIL_CODE_CHANGE_COUNT_INVALID         1015
+#define CSMI_SAS_FAIL_CODE_ENUMERATION_TYPE_INVALID     1016
+
+#define CSMI_SAS_FAIL_CODE_EXCEEDED_RAID_SET_COUNT      2000
+#define CSMI_SAS_FAIL_CODE_DUPLICATE_LUN                2001
+
+#define CSMI_SAS_FAIL_CODE_WAIT_FOR_OPERATION           3000
+
+// RAID Enumeration Types
+// (uEnumerationType)
+#define CSMI_SAS_RAID_ELEMENT_TYPE_DRIVE                0
+#define CSMI_SAS_RAID_ELEMENT_TYPE_MODULE               1
+#define CSMI_SAS_RAID_ELEMENT_TYPE_DRIVE_RAID_SET       2
+#define CSMI_SAS_RAID_ELEMENT_TYPE_EXTENT_DRIVE         3
+
+// RAID Extent Types
+// (bExtentType)
+#define CSMI_SAS_RAID_EXTENT_RESERVED       0
+#define CSMI_SAS_RAID_EXTENT_METADATA       1
+#define CSMI_SAS_RAID_EXTENT_ALLOCATED      2
+#define CSMI_SAS_RAID_EXTENT_UNALLOCATED    3
+
+// RAID Operation Types
+// (uOperationType)
+#define CSMI_SAS_RAID_SET_CREATE            0
+#define CSMI_SAS_RAID_SET_LABEL             1
+#define CSMI_SAS_RAID_SET_TRANSFORM         2
+#define CSMI_SAS_RAID_SET_DELETE            3
+#define CSMI_SAS_RAID_SET_WRITE_PROTECT     4
+#define CSMI_SAS_RAID_SET_CACHE             5
+#define CSMI_SAS_RAID_SET_ONLINE_STATE      6
+#define CSMI_SAS_RAID_SET_SPARE             7
+
+// RAID Transform Types
+// (bTransformType)
+#define CSMI_SAS_RAID_SET_TRANSFORM_SPLIT_MIRROR    0
+#define CSMI_SAS_RAID_SET_TRANSFORM_MERGE_RAID_0    1
+#define CSMI_SAS_RAID_SET_TRANSFORM_LUN_RENUMBER    2
+#define CSMI_SAS_RAID_SET_TRANSFORM_RAID_SET        3
+
+// RAID Online State
+// (bOnlineState)
+#define CSMI_SAS_RAID_SET_STATE_UNKNOWN     0
+#define CSMI_SAS_RAID_SET_STATE_ONLINE      1
+#define CSMI_SAS_RAID_SET_STATE_OFFLINE     2
+
+/* * * * * * * * * * SAS HBA Class IOCTL Constants * * * * * * * * * */
+
+// Return codes for SAS IOCTL's
+// (IoctlHeader.ReturnCode)
+
+#define CSMI_SAS_PHY_INFO_CHANGED            CSMI_SAS_STATUS_SUCCESS
+#define CSMI_SAS_PHY_INFO_NOT_CHANGEABLE     2000
+#define CSMI_SAS_LINK_RATE_OUT_OF_RANGE      2001
+
+#define CSMI_SAS_PHY_DOES_NOT_EXIST          2002
+#define CSMI_SAS_PHY_DOES_NOT_MATCH_PORT     2003
+#define CSMI_SAS_PHY_CANNOT_BE_SELECTED      2004
+#define CSMI_SAS_SELECT_PHY_OR_PORT          2005
+#define CSMI_SAS_PORT_DOES_NOT_EXIST         2006
+#define CSMI_SAS_PORT_CANNOT_BE_SELECTED     2007
+#define CSMI_SAS_CONNECTION_FAILED           2008
+
+#define CSMI_SAS_NO_SATA_DEVICE              2009
+#define CSMI_SAS_NO_SATA_SIGNATURE           2010
+#define CSMI_SAS_SCSI_EMULATION              2011
+#define CSMI_SAS_NOT_AN_END_DEVICE           2012
+#define CSMI_SAS_NO_SCSI_ADDRESS             2013
+#define CSMI_SAS_NO_DEVICE_ADDRESS           2014
+
+// Signature value
+// (IoctlHeader.Signature)
+
+#define CSMI_SAS_SIGNATURE    "CSMISAS"
+
+// Timeout value default of 60 seconds
+// (IoctlHeader.Timeout)
+
+#define CSMI_SAS_TIMEOUT      60
+
+// Device types
+// (bDeviceType)
+
+#define CSMI_SAS_PHY_UNUSED               0x00
+#define CSMI_SAS_NO_DEVICE_ATTACHED       0x00
+#define CSMI_SAS_END_DEVICE               0x10
+#define CSMI_SAS_EDGE_EXPANDER_DEVICE     0x20
+#define CSMI_SAS_FANOUT_EXPANDER_DEVICE   0x30
+
+// Protocol options
+// (bInitiatorPortProtocol, bTargetPortProtocol)
+
+#define CSMI_SAS_PROTOCOL_SATA   0x01
+#define CSMI_SAS_PROTOCOL_SMP    0x02
+#define CSMI_SAS_PROTOCOL_STP    0x04
+#define CSMI_SAS_PROTOCOL_SSP    0x08
+
+// Negotiated and hardware link rates
+// (bNegotiatedLinkRate, bMinimumLinkRate, bMaximumLinkRate)
+
+#define CSMI_SAS_LINK_RATE_UNKNOWN  0x00
+#define CSMI_SAS_PHY_DISABLED       0x01
+#define CSMI_SAS_LINK_RATE_FAILED   0x02
+#define CSMI_SAS_SATA_SPINUP_HOLD   0x03
+#define CSMI_SAS_SATA_PORT_SELECTOR 0x04
+#define CSMI_SAS_LINK_RATE_1_5_GBPS 0x08
+#define CSMI_SAS_LINK_RATE_3_0_GBPS 0x09
+#define CSMI_SAS_LINK_VIRTUAL       0x10
+
+// Discover state
+// (bAutoDiscover)
+
+#define CSMI_SAS_DISCOVER_NOT_SUPPORTED   0x00
+#define CSMI_SAS_DISCOVER_NOT_STARTED     0x01
+#define CSMI_SAS_DISCOVER_IN_PROGRESS     0x02
+#define CSMI_SAS_DISCOVER_COMPLETE        0x03
+#define CSMI_SAS_DISCOVER_ERROR           0x04
+
+// Phy features
+
+#define CSMI_SAS_PHY_VIRTUAL_SMP          0x01
+
+// Programmed link rates
+// (bMinimumLinkRate, bMaximumLinkRate)
+// (bProgrammedMinimumLinkRate, bProgrammedMaximumLinkRate)
+
+#define CSMI_SAS_PROGRAMMED_LINK_RATE_UNCHANGED 0x00
+#define CSMI_SAS_PROGRAMMED_LINK_RATE_1_5_GBPS  0x08
+#define CSMI_SAS_PROGRAMMED_LINK_RATE_3_0_GBPS  0x09
+
+// Link rate
+// (bNegotiatedLinkRate in CSMI_SAS_SET_PHY_INFO)
+
+#define CSMI_SAS_LINK_RATE_NEGOTIATE      0x00
+#define CSMI_SAS_LINK_RATE_PHY_DISABLED   0x01
+
+// Signal class
+// (bSignalClass in CSMI_SAS_SET_PHY_INFO)
+
+#define CSMI_SAS_SIGNAL_CLASS_UNKNOWN     0x00
+#define CSMI_SAS_SIGNAL_CLASS_DIRECT      0x01
+#define CSMI_SAS_SIGNAL_CLASS_SERVER      0x02
+#define CSMI_SAS_SIGNAL_CLASS_ENCLOSURE   0x03
+
+// Link error reset
+// (bResetCounts)
+
+#define CSMI_SAS_LINK_ERROR_DONT_RESET_COUNTS   0x00
+#define CSMI_SAS_LINK_ERROR_RESET_COUNTS        0x01
+
+// Phy identifier
+// (bPhyIdentifier)
+
+#define CSMI_SAS_USE_PORT_IDENTIFIER   0xFF
+
+// Port identifier
+// (bPortIdentifier)
+
+#define CSMI_SAS_IGNORE_PORT           0xFF
+
+// Programmed link rates
+// (bConnectionRate)
+
+#define CSMI_SAS_LINK_RATE_NEGOTIATED  0x00
+#define CSMI_SAS_LINK_RATE_1_5_GBPS    0x08
+#define CSMI_SAS_LINK_RATE_3_0_GBPS    0x09
+
+// Connection status
+// (bConnectionStatus)
+
+#define CSMI_SAS_OPEN_ACCEPT                          0
+#define CSMI_SAS_OPEN_REJECT_BAD_DESTINATION          1
+#define CSMI_SAS_OPEN_REJECT_RATE_NOT_SUPPORTED       2
+#define CSMI_SAS_OPEN_REJECT_NO_DESTINATION           3
+#define CSMI_SAS_OPEN_REJECT_PATHWAY_BLOCKED          4
+#define CSMI_SAS_OPEN_REJECT_PROTOCOL_NOT_SUPPORTED   5
+#define CSMI_SAS_OPEN_REJECT_RESERVE_ABANDON          6
+#define CSMI_SAS_OPEN_REJECT_RESERVE_CONTINUE         7
+#define CSMI_SAS_OPEN_REJECT_RESERVE_INITIALIZE       8
+#define CSMI_SAS_OPEN_REJECT_RESERVE_STOP             9
+#define CSMI_SAS_OPEN_REJECT_RETRY                    10
+#define CSMI_SAS_OPEN_REJECT_STP_RESOURCES_BUSY       11
+#define CSMI_SAS_OPEN_REJECT_WRONG_DESTINATION        12
+
+// SSP Status
+// (bSSPStatus)
+
+#define CSMI_SAS_SSP_STATUS_UNKNOWN     0x00
+#define CSMI_SAS_SSP_STATUS_WAITING     0x01
+#define CSMI_SAS_SSP_STATUS_COMPLETED   0x02
+#define CSMI_SAS_SSP_STATUS_FATAL_ERROR 0x03
+#define CSMI_SAS_SSP_STATUS_RETRY       0x04
+#define CSMI_SAS_SSP_STATUS_NO_TAG      0x05
+
+// SSP Flags
+// (uFlags)
+
+#define CSMI_SAS_SSP_READ           0x00000001
+#define CSMI_SAS_SSP_WRITE          0x00000002
+#define CSMI_SAS_SSP_UNSPECIFIED    0x00000004
+
+#define CSMI_SAS_SSP_TASK_ATTRIBUTE_SIMPLE         0x00000000
+#define CSMI_SAS_SSP_TASK_ATTRIBUTE_HEAD_OF_QUEUE  0x00000010
+#define CSMI_SAS_SSP_TASK_ATTRIBUTE_ORDERED        0x00000020
+#define CSMI_SAS_SSP_TASK_ATTRIBUTE_ACA            0x00000040
+
+// SSP Data present
+// (bDataPresent)
+
+#define CSMI_SAS_SSP_NO_DATA_PRESENT         0x00
+#define CSMI_SAS_SSP_RESPONSE_DATA_PRESENT   0x01
+#define CSMI_SAS_SSP_SENSE_DATA_PRESENT      0x02
+
+// STP Flags
+// (uFlags)
+
+#define CSMI_SAS_STP_READ           0x00000001
+#define CSMI_SAS_STP_WRITE          0x00000002
+#define CSMI_SAS_STP_UNSPECIFIED    0x00000004
+#define CSMI_SAS_STP_PIO            0x00000010
+#define CSMI_SAS_STP_DMA            0x00000020
+#define CSMI_SAS_STP_PACKET         0x00000040
+#define CSMI_SAS_STP_DMA_QUEUED     0x00000080
+#define CSMI_SAS_STP_EXECUTE_DIAG   0x00000100
+#define CSMI_SAS_STP_RESET_DEVICE   0x00000200
+
+// Task Management Flags
+// (uFlags)
+
+#define CSMI_SAS_TASK_IU               0x00000001
+#define CSMI_SAS_HARD_RESET_SEQUENCE   0x00000002
+#define CSMI_SAS_SUPPRESS_RESULT       0x00000004
+
+// Task Management Functions
+// (bTaskManagement)
+
+#define CSMI_SAS_SSP_ABORT_TASK           0x01
+#define CSMI_SAS_SSP_ABORT_TASK_SET       0x02
+#define CSMI_SAS_SSP_CLEAR_TASK_SET       0x04
+#define CSMI_SAS_SSP_LOGICAL_UNIT_RESET   0x08
+#define CSMI_SAS_SSP_CLEAR_ACA            0x40
+#define CSMI_SAS_SSP_QUERY_TASK           0x80
+
+// Task Management Information
+// (uInformation)
+
+#define CSMI_SAS_SSP_TEST           1
+#define CSMI_SAS_SSP_EXCEEDED       2
+#define CSMI_SAS_SSP_DEMAND         3
+#define CSMI_SAS_SSP_TRIGGER        4
+
+// Connector Pinout Information
+// (uPinout)
+
+#define CSMI_SAS_CON_UNKNOWN              0x00000001
+#define CSMI_SAS_CON_SFF_8482             0x00000002
+#define CSMI_SAS_CON_SFF_8470_LANE_1      0x00000100
+#define CSMI_SAS_CON_SFF_8470_LANE_2      0x00000200
+#define CSMI_SAS_CON_SFF_8470_LANE_3      0x00000400
+#define CSMI_SAS_CON_SFF_8470_LANE_4      0x00000800
+#define CSMI_SAS_CON_SFF_8484_LANE_1      0x00010000
+#define CSMI_SAS_CON_SFF_8484_LANE_2      0x00020000
+#define CSMI_SAS_CON_SFF_8484_LANE_3      0x00040000
+#define CSMI_SAS_CON_SFF_8484_LANE_4      0x00080000
+
+// Connector Location Information
+// (bLocation)
+
+// same as uPinout above...
+// #define CSMI_SAS_CON_UNKNOWN              0x01
+#define CSMI_SAS_CON_INTERNAL             0x02
+#define CSMI_SAS_CON_EXTERNAL             0x04
+#define CSMI_SAS_CON_SWITCHABLE           0x08
+#define CSMI_SAS_CON_AUTO                 0x10
+#define CSMI_SAS_CON_NOT_PRESENT          0x20
+#define CSMI_SAS_CON_NOT_CONNECTED        0x80
+
+// Device location identification
+// (bIdentify)
+
+#define CSMI_SAS_LOCATE_UNKNOWN           0x00
+#define CSMI_SAS_LOCATE_FORCE_OFF         0x01
+#define CSMI_SAS_LOCATE_FORCE_ON          0x02
+
+// Location Valid flags
+// (uLocationFlags)
+
+#define CSMI_SAS_LOCATE_SAS_ADDRESS_VALID           0x00000001
+#define CSMI_SAS_LOCATE_SAS_LUN_VALID               0x00000002
+#define CSMI_SAS_LOCATE_ENCLOSURE_IDENTIFIER_VALID  0x00000004
+#define CSMI_SAS_LOCATE_ENCLOSURE_NAME_VALID        0x00000008
+#define CSMI_SAS_LOCATE_BAY_PREFIX_VALID            0x00000010
+#define CSMI_SAS_LOCATE_BAY_IDENTIFIER_VALID        0x00000020
+#define CSMI_SAS_LOCATE_LOCATION_STATE_VALID        0x00000040
+
+/* * * * * * * * SAS Phy Control Class IOCTL Constants * * * * * * * * */
+
+// Return codes for SAS Phy Control IOCTL's
+// (IoctlHeader.ReturnCode)
+
+// Signature value
+// (IoctlHeader.Signature)
+
+#define CSMI_PHY_SIGNATURE    "CSMIPHY"
+
+// Phy Control Functions
+// (bFunction)
+
+// values 0x00 to 0xFF are consistent in definition with the SMP PHY CONTROL
+// function defined in the SAS spec
+#define CSMI_SAS_PC_NOP                   0x00000000
+#define CSMI_SAS_PC_LINK_RESET            0x00000001
+#define CSMI_SAS_PC_HARD_RESET            0x00000002
+#define CSMI_SAS_PC_PHY_DISABLE           0x00000003
+// 0x04 to 0xFF reserved...
+#define CSMI_SAS_PC_GET_PHY_SETTINGS      0x00000100
+
+// Link Flags
+#define CSMI_SAS_PHY_ACTIVATE_CONTROL     0x00000001
+#define CSMI_SAS_PHY_UPDATE_SPINUP_RATE   0x00000002
+#define CSMI_SAS_PHY_AUTO_COMWAKE         0x00000004
+
+// Device Types for Phy Settings
+// (bType)
+#define CSMI_SAS_UNDEFINED 0x00
+#define CSMI_SAS_SATA      0x01
+#define CSMI_SAS_SAS       0x02
+
+// Transmitter Flags
+// (uTransmitterFlags)
+#define CSMI_SAS_PHY_PREEMPHASIS_DISABLED    0x00000001
+
+// Receiver Flags
+// (uReceiverFlags)
+#define CSMI_SAS_PHY_EQUALIZATION_DISABLED   0x00000001
+
+// Pattern Flags
+// (uPatternFlags)
+// #define CSMI_SAS_PHY_ACTIVATE_CONTROL     0x00000001
+#define CSMI_SAS_PHY_DISABLE_SCRAMBLING      0x00000002
+#define CSMI_SAS_PHY_DISABLE_ALIGN           0x00000004
+#define CSMI_SAS_PHY_DISABLE_SSC             0x00000008
+
+#define CSMI_SAS_PHY_FIXED_PATTERN           0x00000010
+#define CSMI_SAS_PHY_USER_PATTERN            0x00000020
+
+// Fixed Patterns
+// (bFixedPattern)
+#define CSMI_SAS_PHY_CJPAT                   0x00000001
+#define CSMI_SAS_PHY_ALIGN                   0x00000002
+
+// Type Flags
+// (bTypeFlags)
+#define CSMI_SAS_PHY_POSITIVE_DISPARITY      0x01
+#define CSMI_SAS_PHY_NEGATIVE_DISPARITY      0x02
+#define CSMI_SAS_PHY_CONTROL_CHARACTER       0x04
+
+// Miscellaneous
+#define SLOT_NUMBER_UNKNOWN   0xFFFF
+
+/*************************************************************************/
+/* DATA STRUCTURES                                                       */
+/*************************************************************************/
+
+/* * * * * * * * * * Class Independent Structures * * * * * * * * * */
+
+// EDM #pragma CSMI_SAS_BEGIN_PACK(8)
+#pragma pack(8)
+
+// CC_CSMI_SAS_DRIVER_INFO
+
+typedef struct _CSMI_SAS_DRIVER_INFO {
+   __u8  szName[81];
+   __u8  szDescription[81];
+   __u16 usMajorRevision;
+   __u16 usMinorRevision;
+   __u16 usBuildRevision;
+   __u16 usReleaseRevision;
+   __u16 usCSMIMajorRevision;
+   __u16 usCSMIMinorRevision;
+} CSMI_SAS_DRIVER_INFO,
+  *PCSMI_SAS_DRIVER_INFO;
+
+typedef struct _CSMI_SAS_DRIVER_INFO_BUFFER {
+   IOCTL_HEADER IoctlHeader;
+   CSMI_SAS_DRIVER_INFO Information;
+} CSMI_SAS_DRIVER_INFO_BUFFER,
+  *PCSMI_SAS_DRIVER_INFO_BUFFER;
+
+// CC_CSMI_SAS_CNTLR_CONFIGURATION
+
+typedef struct _CSMI_SAS_PCI_BUS_ADDRESS {
+   __u8  bBusNumber;
+   __u8  bDeviceNumber;
+   __u8  bFunctionNumber;
+   __u8  bReserved;
+} CSMI_SAS_PCI_BUS_ADDRESS,
+  *PCSMI_SAS_PCI_BUS_ADDRESS;
+
+typedef union _CSMI_SAS_IO_BUS_ADDRESS {
+   CSMI_SAS_PCI_BUS_ADDRESS PciAddress;
+   __u8  bReserved[32];
+} CSMI_SAS_IO_BUS_ADDRESS,
+  *PCSMI_SAS_IO_BUS_ADDRESS;
+
+typedef struct _CSMI_SAS_CNTLR_CONFIG {
+   __u32 uBaseIoAddress;
+   struct {
+      __u32 uLowPart;
+      __u32 uHighPart;
+   } BaseMemoryAddress;
+   __u32 uBoardID;
+   __u16 usSlotNumber;
+   __u8  bControllerClass;
+   __u8  bIoBusType;
+   CSMI_SAS_IO_BUS_ADDRESS BusAddress;
+   __u8  szSerialNumber[81];
+   __u16 usMajorRevision;
+   __u16 usMinorRevision;
+   __u16 usBuildRevision;
+   __u16 usReleaseRevision;
+   __u16 usBIOSMajorRevision;
+   __u16 usBIOSMinorRevision;
+   __u16 usBIOSBuildRevision;
+   __u16 usBIOSReleaseRevision;
+   __u32 uControllerFlags;
+   __u16 usRromMajorRevision;
+   __u16 usRromMinorRevision;
+   __u16 usRromBuildRevision;
+   __u16 usRromReleaseRevision;
+   __u16 usRromBIOSMajorRevision;
+   __u16 usRromBIOSMinorRevision;
+   __u16 usRromBIOSBuildRevision;
+   __u16 usRromBIOSReleaseRevision;
+   __u8  bReserved[7];
+} CSMI_SAS_CNTLR_CONFIG,
+  *PCSMI_SAS_CNTLR_CONFIG;
+
+typedef struct _CSMI_SAS_CNTLR_CONFIG_BUFFER {
+   IOCTL_HEADER IoctlHeader;
+   CSMI_SAS_CNTLR_CONFIG Configuration;
+} CSMI_SAS_CNTLR_CONFIG_BUFFER,
+  *PCSMI_SAS_CNTLR_CONFIG_BUFFER;
+
+// CC_CSMI_SAS_CNTLR_STATUS
+
+typedef struct _CSMI_SAS_CNTLR_STATUS {
+   __u32 uStatus;
+   __u32 uOfflineReason;
+   __u8  bReserved[28];
+} CSMI_SAS_CNTLR_STATUS,
+  *PCSMI_SAS_CNTLR_STATUS;
+
+typedef struct _CSMI_SAS_CNTLR_STATUS_BUFFER {
+   IOCTL_HEADER IoctlHeader;
+   CSMI_SAS_CNTLR_STATUS Status;
+} CSMI_SAS_CNTLR_STATUS_BUFFER,
+  *PCSMI_SAS_CNTLR_STATUS_BUFFER;
+
+// CC_CSMI_SAS_FIRMWARE_DOWNLOAD
+
+typedef struct _CSMI_SAS_FIRMWARE_DOWNLOAD {
+   __u32 uBufferLength;
+   __u32 uDownloadFlags;
+   __u8  bReserved[32];
+   __u16 usStatus;
+   __u16 usSeverity;
+} CSMI_SAS_FIRMWARE_DOWNLOAD,
+  *PCSMI_SAS_FIRMWARE_DOWNLOAD;
+
+typedef struct _CSMI_SAS_FIRMWARE_DOWNLOAD_BUFFER {
+   IOCTL_HEADER IoctlHeader;
+   CSMI_SAS_FIRMWARE_DOWNLOAD Information;
+   __u8  bDataBuffer[1];
+} CSMI_SAS_FIRMWARE_DOWNLOAD_BUFFER,
+  *PCSMI_SAS_FIRMWARE_DOWNLOAD_BUFFER;
+
+// CC_CSMI_SAS_RAID_INFO
+
+typedef struct _CSMI_SAS_RAID_INFO {
+   __u32 uNumRaidSets;
+   __u32 uMaxDrivesPerSet;
+   __u32 uMaxRaidSets;
+   __u8  bMaxRaidTypes;
+   __u8  bReservedByteFields[7];
+   struct
+   {
+      __u32 uLowPart;
+      __u32 uHighPart;
+   } ulMinRaidSetBlocks;
+   struct
+   {
+      __u32 uLowPart;
+      __u32 uHighPart;
+   } ulMaxRaidSetBlocks;
+   __u32 uMaxPhysicalDrives;
+   __u32 uMaxExtents;
+   __u32 uMaxModules;
+   __u32 uMaxTransformationMemory;
+   __u32 uChangeCount;
+   __u8  bReserved[44];
+} CSMI_SAS_RAID_INFO,
+  *PCSMI_SAS_RAID_INFO;
+
+typedef struct _CSMI_SAS_RAID_INFO_BUFFER {
+   IOCTL_HEADER IoctlHeader;
+   CSMI_SAS_RAID_INFO Information;
+} CSMI_SAS_RAID_INFO_BUFFER,
+  *PCSMI_SAS_RAID_INFO_BUFFER;
+
+// CC_CSMI_SAS_GET_RAID_CONFIG
+
+typedef struct _CSMI_SAS_RAID_DRIVES {
+   __u8  bModel[40];
+   __u8  bFirmware[8];
+   __u8  bSerialNumber[40];
+   __u8  bSASAddress[8];
+   __u8  bSASLun[8];
+   __u8  bDriveStatus;
+   __u8  bDriveUsage;
+   __u16 usBlockSize;
+   __u8  bDriveType;
+   __u8  bReserved[15];
+   __u32 uDriveIndex;
+   struct
+   {
+      __u32 uLowPart;
+      __u32 uHighPart;
+   } ulTotalUserBlocks;
+} CSMI_SAS_RAID_DRIVES,
+  *PCSMI_SAS_RAID_DRIVES;
+
+typedef struct _CSMI_SAS_RAID_DEVICE_ID {
+   __u8  bDeviceIdentificationVPDPage[1];
+} CSMI_SAS_RAID_DEVICE_ID,
+  *PCSMI_SAS_RAID_DEVICE_ID;
+
+typedef struct _CSMI_SAS_RAID_SET_ADDITIONAL_DATA {
+   __u8  bLabel[16];
+   __u8  bRaidSetLun[8];
+   __u8  bWriteProtection;
+   __u8  bCacheSetting;
+   __u8  bCacheRatio;
+   __u16 usBlockSize;
+   __u8  bReservedBytes[11];
+   struct
+   {
+      __u32 uLowPart;
+      __u32 uHighPart;
+   } ulRaidSetExtentOffset;
+   struct
+   {
+      __u32 uLowPart;
+      __u32 uHighPart;
+   } ulRaidSetBlocks;
+   __u32 uStripeSizeInBlocks;
+   __u32 uSectorsPerTrack;
+   __u8  bApplicationScratchPad[16];
+   __u32 uNumberOfHeads;
+   __u32 uNumberOfTracks;
+   __u8  bReserved[24];
+} CSMI_SAS_RAID_SET_ADDITIONAL_DATA,
+  *PCSMI_SAS_RAID_SET_ADDITIONAL_DATA;
+
+typedef struct _CSMI_SAS_RAID_CONFIG {
+   __u32 uRaidSetIndex;
+   __u32 uCapacity;
+   __u32 uStripeSize;
+   __u8  bRaidType;
+   __u8  bStatus;
+   __u8  bInformation;
+   __u8  bDriveCount;
+   __u8  bDataType;
+   __u8  bReserved[11];
+   __u32 uFailureCode;
+   __u32 uChangeCount;
+   union {
+      CSMI_SAS_RAID_DRIVES Drives[1];
+      CSMI_SAS_RAID_DEVICE_ID DeviceId[1];
+      CSMI_SAS_RAID_SET_ADDITIONAL_DATA Data[1];
+   };
+} CSMI_SAS_RAID_CONFIG,
+   *PCSMI_SAS_RAID_CONFIG;
+
+typedef struct _CSMI_SAS_RAID_CONFIG_BUFFER {
+   IOCTL_HEADER IoctlHeader;
+   CSMI_SAS_RAID_CONFIG Configuration;
+} CSMI_SAS_RAID_CONFIG_BUFFER,
+  *PCSMI_SAS_RAID_CONFIG_BUFFER;
+
+// CC_CSMI_SAS_GET_RAID_FEATURES
+
+typedef struct _CSMI_SAS_RAID_TYPE_DESCRIPTION {
+  __u8  bRaidType;
+  __u8  bReservedBytes[7];
+  __u32 uSupportedStripeSizeMap;
+  __u8  bReserved[24];
+} CSMI_SAS_RAID_TYPE_DESCRIPTION,
+  *PCSMI_SAS_RAID_TYPE_DESCRIPTION;
+
+typedef struct _CSMI_SAS_RAID_FEATURES {
+   __u32 uFeatures;
+   __u8  bReservedFeatures[32];
+   __u8  bDefaultTransformPriority;
+   __u8  bTransformPriority;
+   __u8  bDefaultRebuildPriority;
+   __u8  bRebuildPriority;
+   __u8  bDefaultSurfaceScanPriority;
+   __u8  bSurfaceScanPriority;
+   __u16 usReserved;
+   __u32 uRaidSetTransformationRules;
+   __u32 uReserved[11];
+   CSMI_SAS_RAID_TYPE_DESCRIPTION RaidType[24];
+   __u8  bCacheRatiosSupported[104];
+   __u32 uChangeCount;
+   __u32 uFailureCode;
+   __u8  bReserved[120];
+} CSMI_SAS_RAID_FEATURES,
+  *PCSMI_SAS_RAID_FEATURES;
+
+typedef struct _CSMI_SAS_RAID_FEATURES_BUFFER {
+   IOCTL_HEADER IoctlHeader;
+   CSMI_SAS_RAID_FEATURES Information;
+} CSMI_SAS_RAID_FEATURES_BUFFER,
+  *PCSMI_SAS_RAID_FEATURES_BUFFER;
+
+// CC_CSMI_SAS_SET_RAID_CONTROL
+
+typedef struct _CSMI_SAS_RAID_CONTROL {
+   __u8  bTransformPriority;
+   __u8  bRebuildPriority;
+   __u8  bCacheRatioFlag;
+   __u8  bCacheRatio;
+   __u8  bSurfaceScanPriority;
+   __u8  bReservedBytes[15];
+   __u8  bClearConfiguration[8];
+   __u32 uChangeCount;
+   __u8  bReserved[88];
+   __u32 uFailureCode;
+   __u8  bFailureDescription[80];
+} CSMI_SAS_RAID_CONTROL,
+  *PCSMI_SAS_RAID_CONTROL;
+
+typedef struct _CSMI_SAS_RAID_CONTROL_BUFFER {
+   IOCTL_HEADER IoctlHeader;
+   CSMI_SAS_RAID_CONTROL Information;
+} CSMI_SAS_RAID_CONTROL_BUFFER,
+  *PCSMI_SAS_RAID_CONTROL_BUFFER;
+
+// CC_CSMI_SAS_GET_RAID_ELEMENT
+
+typedef struct _CSMI_SAS_DRIVE_EXTENT_INFO {
+   __u32 uDriveIndex;
+   __u8  bExtentType;
+   __u8  bReservedBytes[7];
+   struct
+   {
+      __u32 uLowPart;
+      __u32 uHighPart;
+   } ulExtentOffset;
+   struct
+   {
+      __u32 uLowPart;
+      __u32 uHighPart;
+   } ulExtentBlocks;
+   __u32 uRaidSetIndex;
+   __u8  bReserved[96];
+} CSMI_SAS_DRIVE_EXTENT_INFO,
+  *PCSMI_SAS_DRIVE_EXTENT_INFO;
+
+typedef struct _CSMI_SAS_RAID_MODULE_INFO {
+   __u8  bReserved[128];
+} CSMI_SAS_RAID_MODULE_INFO,
+  *PCSMI_SAS_RAID_MODULE_INFO;
+
+typedef struct _CSMI_SAS_DRIVE_LOCATION {
+   __u8  bConnector[16];
+   __u8  bBoxName[16];
+   __u32 uBay;
+   __u8  bReservedBytes[4];
+   __u8  bAttachedSASAddress[8];
+   __u8  bAttachedPhyIdentifier;
+   __u8  bReserved[79];
+} CSMI_SAS_DRIVE_LOCATION,
+  *PCSMI_SAS_DRIVE_LOCATION;
+
+typedef struct _CSMI_SAS_RAID_DRIVES_ADDITIONAL_DATA {
+   __u8  bNegotiatedLinkRate[2];
+   __u8  bReserved[126];
+} CSMI_SAS_RAID_DRIVES_ADDITIONAL_DATA,
+  *PCSMI_SAS_RAID_DRIVES_ADDITIONAL_DATA;
+
+typedef struct _CSMI_SAS_DRIVE_INFO {
+   CSMI_SAS_RAID_DRIVES Device;
+   CSMI_SAS_RAID_DRIVES_ADDITIONAL_DATA Data;
+   CSMI_SAS_DRIVE_LOCATION Location;
+   __u8  bReserved[16];
+} CSMI_SAS_DRIVE_INFO,
+  *PCSMI_SAS_DRIVE_INFO;
+
+typedef struct _CSMI_SAS_RAID_ELEMENT {
+   __u32 uEnumerationType;
+   __u32 uElementIndex;
+   __u32 uNumElements;
+   __u32 uChangeCount;
+   __u32 uSubElementIndex;
+   __u8  bReserved[32];
+   __u32 uFailureCode;
+   __u8  bFailureDescription[80];
+   union {
+       CSMI_SAS_DRIVE_INFO Drive;
+       CSMI_SAS_RAID_MODULE_INFO Module;
+       CSMI_SAS_DRIVE_EXTENT_INFO Extent;
+   } Element;
+} CSMI_SAS_RAID_ELEMENT,
+  *PCSMI_SAS_RAID_ELEMENT;
+
+typedef struct _CSMI_SAS_RAID_ELEMENT_BUFFER {
+   IOCTL_HEADER IoctlHeader;
+   CSMI_SAS_RAID_ELEMENT Information;
+} CSMI_SAS_RAID_ELEMENT_BUFFER,
+  *PCSMI_SAS_RAID_ELEMENT_BUFFER;
+
+// CC_CSMI_SAS_SET_RAID_OPERATION
+
+typedef struct _CSMI_SAS_RAID_SET_LIST {
+   __u32 uRaidSetIndex;
+   __u8  bExistingLun[8];
+   __u8  bNewLun[8];
+   __u8  bReserved[12];
+} CSMI_SAS_RAID_SET_LIST,
+  *PCSMI_SAS_RAID_SET_LIST;
+
+typedef struct _CSMI_SAS_RAID_SET_DRIVE_LIST {
+   __u32 uDriveIndex;
+   __u8  bDriveUsage;
+   __u8  bReserved[27];
+} CSMI_SAS_RAID_SET_DRIVE_LIST,
+  *PCSMI_SAS_RAID_SET_DRIVE_LIST;
+
+typedef struct _CSMI_SAS_RAID_SET_SPARE_INFO {
+   __u32 uRaidSetIndex;
+   __u32 uDriveCount;
+   __u8  bApplicationScratchPad[16];
+   __u8  bReserved[104];
+} CSMI_SAS_RAID_SET_SPARE_INFO,
+  *PCSMI_SAS_RAID_SET_SPARE_INFO;
+
+typedef struct _CSMI_SAS_RAID_SET_ONLINE_STATE_INFO {
+   __u32 uRaidSetIndex;
+   __u8  bOnlineState;
+   __u8  bReserved[123];
+} CSMI_SAS_RAID_SET_ONLINE_STATE_INFO,
+  *PCSMI_SAS_RAID_SET_ONLINE_STATE_INFO;
+
+typedef struct _CSMI_SAS_RAID_SET_CACHE_INFO {
+   __u32 uRaidSetIndex;
+   __u8  bCacheSetting;
+   __u8  bCacheRatioFlag;
+   __u8  bCacheRatio;
+   __u8  bReserved[121];
+} CSMI_SAS_RAID_SET_CACHE_INFO,
+  *PCSMI_SAS_RAID_SET_CACHE_INFO;
+
+typedef struct _CSMI_SAS_RAID_SET_WRITE_PROTECT_INFO {
+   __u32 uRaidSetIndex;
+   __u8  bWriteProtectSetting;
+   __u8  bReserved[123];
+} CSMI_SAS_RAID_SET_WRITE_PROTECT_INFO,
+  *PCSMI_SAS_RAID_SET_WRITE_PROTECT_INFO;
+
+typedef struct _CSMI_SAS_RAID_SET_DELETE_INFO {
+   __u32 uRaidSetIndex;
+   __u8  bReserved[124];
+} CSMI_SAS_RAID_SET_DELETE_INFO,
+  *PCSMI_SAS_RAID_SET_DELETE_INFO;
+
+typedef struct _CSMI_SAS_RAID_SET_MODIFY_INFO {
+   __u8  bRaidType;
+   __u8  bReservedBytes[7];
+   __u32 uStripeSize;
+   struct
+   {
+      __u32 uLowPart;
+      __u32 uHighPart;
+   } ulRaidSetBlocks;
+   struct
+   {
+      __u32 uLowPart;
+      __u32 uHighPart;
+   } ulRaidSetExtentOffset;
+   __u32 uDriveCount;
+   __u8  bReserved[96];
+} CSMI_SAS_RAID_SET_MODIFY_INFO,
+  *PCSMI_SAS_RAID_SET_MODIFY_INFO;
+
+typedef struct _CSMI_SAS_RAID_SET_TRANSFORM_INFO {
+   __u8  bTransformType;
+   __u8  bReservedBytes[3];
+   __u32 uRaidSetIndex;
+   __u8  bRaidType;
+   __u8  bReservedBytes2[11];
+   __u32 uAdditionalRaidSetIndex;
+   __u32 uRaidSetCount;
+   __u8  bApplicationScratchPad[16];
+   CSMI_SAS_RAID_SET_MODIFY_INFO Modify;
+   __u8  bReserved[80];
+} CSMI_SAS_RAID_SET_TRANSFORM_INFO,
+  *PCSMI_SAS_RAID_SET_TRANSFORM_INFO;
+
+typedef struct _CSMI_SAS_RAID_SET_LABEL_INFO {
+   __u32 uRaidSetIndex;
+   __u8  bLabel[16];
+   __u8  bReserved[108];
+} CSMI_SAS_RAID_SET_LABEL_INFO,
+  *PCSMI_SAS_RAID_SET_LABEL_INFO;
+
+typedef struct _CSMI_SAS_RAID_SET_CREATE_INFO {
+   __u8  bRaidType;
+   __u8  bReservedBytes[7];
+   __u32 uStripeSize;
+   __u32 uTrackSectorCount;
+   struct
+   {
+      __u32 uLowPart;
+      __u32 uHighPart;
+   } ulRaidSetBlocks;
+   struct
+   {
+      __u32 uLowPart;
+      __u32 uHighPart;
+   } ulRaidSetExtentOffset;
+   __u32 uDriveCount;
+   __u8  bLabel[16];
+   __u32 uRaidSetIndex;
+   __u8  bApplicationScratchPad[16];
+   __u32 uNumberOfHeads;
+   __u32 uNumberOfTracks;
+   __u8  bReserved[48];
+} CSMI_SAS_RAID_SET_CREATE_INFO,
+  *PCSMI_SAS_RAID_SET_CREATE_INFO;
+
+typedef struct _CSMI_SAS_RAID_SET_OPERATION {
+   __u32 uOperationType;
+   __u32 uChangeCount;
+   __u32 uFailureCode;
+   __u8  bFailureDescription[80];
+   __u8  bReserved[28];
+   union {
+       CSMI_SAS_RAID_SET_CREATE_INFO Create;
+       CSMI_SAS_RAID_SET_LABEL_INFO Label;
+       CSMI_SAS_RAID_SET_TRANSFORM_INFO Transform;
+       CSMI_SAS_RAID_SET_DELETE_INFO Delete;
+       CSMI_SAS_RAID_SET_WRITE_PROTECT_INFO Protect;
+       CSMI_SAS_RAID_SET_CACHE_INFO Cache;
+       CSMI_SAS_RAID_SET_ONLINE_STATE_INFO State;
+       CSMI_SAS_RAID_SET_SPARE_INFO Spare;
+   } Operation;
+   union {
+       CSMI_SAS_RAID_SET_DRIVE_LIST DriveList[1];
+       CSMI_SAS_RAID_SET_LIST RaidSetList[1];
+   } Parameters;
+} CSMI_SAS_RAID_SET_OPERATION,
+  *PCSMI_SAS_RAID_SET_OPERATION;
+
+typedef struct _CSMI_SAS_RAID_SET_OPERATION_BUFFER {
+   IOCTL_HEADER IoctlHeader;
+   CSMI_SAS_RAID_SET_OPERATION Information;
+} CSMI_SAS_RAID_SET_OPERATION_BUFFER,
+  *PCSMI_SAS_RAID_SET_OPERATION_BUFFER;
+
+/* * * * * * * * * * SAS HBA Class Structures * * * * * * * * * */
+
+// CC_CSMI_SAS_GET_PHY_INFO
+
+typedef struct _CSMI_SAS_IDENTIFY {
+   __u8  bDeviceType;
+   __u8  bRestricted;
+   __u8  bInitiatorPortProtocol;
+   __u8  bTargetPortProtocol;
+   __u8  bRestricted2[8];
+   __u8  bSASAddress[8];
+   __u8  bPhyIdentifier;
+   __u8  bSignalClass;
+   __u8  bReserved[6];
+} CSMI_SAS_IDENTIFY,
+  *PCSMI_SAS_IDENTIFY;
+
+typedef struct _CSMI_SAS_PHY_ENTITY {
+   CSMI_SAS_IDENTIFY Identify;
+   __u8  bPortIdentifier;
+   __u8  bNegotiatedLinkRate;
+   __u8  bMinimumLinkRate;
+   __u8  bMaximumLinkRate;
+   __u8  bPhyChangeCount;
+   __u8  bAutoDiscover;
+   __u8  bPhyFeatures;
+   __u8  bReserved;
+   CSMI_SAS_IDENTIFY Attached;
+} CSMI_SAS_PHY_ENTITY,
+  *PCSMI_SAS_PHY_ENTITY;
+
+typedef struct _CSMI_SAS_PHY_INFO {
+   __u8  bNumberOfPhys;
+   __u8  bReserved[3];
+   CSMI_SAS_PHY_ENTITY Phy[32];
+} CSMI_SAS_PHY_INFO,
+  *PCSMI_SAS_PHY_INFO;
+
+typedef struct _CSMI_SAS_PHY_INFO_BUFFER {
+   IOCTL_HEADER IoctlHeader;
+   CSMI_SAS_PHY_INFO Information;
+} CSMI_SAS_PHY_INFO_BUFFER,
+  *PCSMI_SAS_PHY_INFO_BUFFER;
+
+// CC_CSMI_SAS_SET_PHY_INFO
+
+typedef struct _CSMI_SAS_SET_PHY_INFO {
+   __u8  bPhyIdentifier;
+   __u8  bNegotiatedLinkRate;
+   __u8  bProgrammedMinimumLinkRate;
+   __u8  bProgrammedMaximumLinkRate;
+   __u8  bSignalClass;
+   __u8  bReserved[3];
+} CSMI_SAS_SET_PHY_INFO,
+  *PCSMI_SAS_SET_PHY_INFO;
+
+typedef struct _CSMI_SAS_SET_PHY_INFO_BUFFER {
+   IOCTL_HEADER IoctlHeader;
+   CSMI_SAS_SET_PHY_INFO Information;
+} CSMI_SAS_SET_PHY_INFO_BUFFER,
+  *PCSMI_SAS_SET_PHY_INFO_BUFFER;
+
+// CC_CSMI_SAS_GET_LINK_ERRORS
+
+typedef struct _CSMI_SAS_LINK_ERRORS {
+   __u8  bPhyIdentifier;
+   __u8  bResetCounts;
+   __u8  bReserved[2];
+   __u32 uInvalidDwordCount;
+   __u32 uRunningDisparityErrorCount;
+   __u32 uLossOfDwordSyncCount;
+   __u32 uPhyResetProblemCount;
+} CSMI_SAS_LINK_ERRORS,
+  *PCSMI_SAS_LINK_ERRORS;
+
+typedef struct _CSMI_SAS_LINK_ERRORS_BUFFER {
+   IOCTL_HEADER IoctlHeader;
+   CSMI_SAS_LINK_ERRORS Information;
+} CSMI_SAS_LINK_ERRORS_BUFFER,
+  *PCSMI_SAS_LINK_ERRORS_BUFFER;
+
+// CC_CSMI_SAS_SMP_PASSTHRU
+
+typedef struct _CSMI_SAS_SMP_REQUEST {
+   __u8  bFrameType;
+   __u8  bFunction;
+   __u8  bReserved[2];
+   __u8  bAdditionalRequestBytes[1016];
+} CSMI_SAS_SMP_REQUEST,
+  *PCSMI_SAS_SMP_REQUEST;
+
+typedef struct _CSMI_SAS_SMP_RESPONSE {
+   __u8  bFrameType;
+   __u8  bFunction;
+   __u8  bFunctionResult;
+   __u8  bReserved;
+   __u8  bAdditionalResponseBytes[1016];
+} CSMI_SAS_SMP_RESPONSE,
+  *PCSMI_SAS_SMP_RESPONSE;
+
+typedef struct _CSMI_SAS_SMP_PASSTHRU {
+   __u8  bPhyIdentifier;
+   __u8  bPortIdentifier;
+   __u8  bConnectionRate;
+   __u8  bReserved;
+   __u8  bDestinationSASAddress[8];
+   __u32 uRequestLength;
+   CSMI_SAS_SMP_REQUEST Request;
+   __u8  bConnectionStatus;
+   __u8  bReserved2[3];
+   __u32 uResponseBytes;
+   CSMI_SAS_SMP_RESPONSE Response;
+} CSMI_SAS_SMP_PASSTHRU,
+  *PCSMI_SAS_SMP_PASSTHRU;
+
+typedef struct _CSMI_SAS_SMP_PASSTHRU_BUFFER {
+   IOCTL_HEADER IoctlHeader;
+   CSMI_SAS_SMP_PASSTHRU Parameters;
+} CSMI_SAS_SMP_PASSTHRU_BUFFER,
+  *PCSMI_SAS_SMP_PASSTHRU_BUFFER;
+
+// CC_CSMI_SAS_SSP_PASSTHRU
+
+typedef struct _CSMI_SAS_SSP_PASSTHRU {
+   __u8  bPhyIdentifier;
+   __u8  bPortIdentifier;
+   __u8  bConnectionRate;
+   __u8  bReserved;
+   __u8  bDestinationSASAddress[8];
+   __u8  bLun[8];
+   __u8  bCDBLength;
+   __u8  bAdditionalCDBLength;
+   __u8  bReserved2[2];
+   __u8  bCDB[16];
+   __u32 uFlags;
+   __u8  bAdditionalCDB[24];
+   __u32 uDataLength;
+} CSMI_SAS_SSP_PASSTHRU,
+  *PCSMI_SAS_SSP_PASSTHRU;
+
+typedef struct _CSMI_SAS_SSP_PASSTHRU_STATUS {
+   __u8  bConnectionStatus;
+   __u8  bSSPStatus;
+   __u8  bReserved[2];
+   __u8  bDataPresent;
+   __u8  bStatus;
+   __u8  bResponseLength[2];
+   __u8  bResponse[256];
+   __u32 uDataBytes;
+} CSMI_SAS_SSP_PASSTHRU_STATUS,
+  *PCSMI_SAS_SSP_PASSTHRU_STATUS;
+
+typedef struct _CSMI_SAS_SSP_PASSTHRU_BUFFER {
+   IOCTL_HEADER IoctlHeader;
+   CSMI_SAS_SSP_PASSTHRU Parameters;
+   CSMI_SAS_SSP_PASSTHRU_STATUS Status;
+   __u8  bDataBuffer[1];
+} CSMI_SAS_SSP_PASSTHRU_BUFFER,
+  *PCSMI_SAS_SSP_PASSTHRU_BUFFER;
+
+// CC_CSMI_SAS_STP_PASSTHRU
+
+typedef struct _CSMI_SAS_STP_PASSTHRU {
+   __u8  bPhyIdentifier;
+   __u8  bPortIdentifier;
+   __u8  bConnectionRate;
+   __u8  bReserved;
+   __u8  bDestinationSASAddress[8];
+   __u8  bReserved2[4];
+   __u8  bCommandFIS[20];
+   __u32 uFlags;
+   __u32 uDataLength;
+} CSMI_SAS_STP_PASSTHRU,
+  *PCSMI_SAS_STP_PASSTHRU;
+
+typedef struct _CSMI_SAS_STP_PASSTHRU_STATUS {
+   __u8  bConnectionStatus;
+   __u8  bReserved[3];
+   __u8  bStatusFIS[20];
+   __u32 uSCR[16];
+   __u32 uDataBytes;
+} CSMI_SAS_STP_PASSTHRU_STATUS,
+  *PCSMI_SAS_STP_PASSTHRU_STATUS;
+
+typedef struct _CSMI_SAS_STP_PASSTHRU_BUFFER {
+   IOCTL_HEADER IoctlHeader;
+   CSMI_SAS_STP_PASSTHRU Parameters;
+   CSMI_SAS_STP_PASSTHRU_STATUS Status;
+   __u8  bDataBuffer[1];
+} CSMI_SAS_STP_PASSTHRU_BUFFER,
+  *PCSMI_SAS_STP_PASSTHRU_BUFFER;
+
+// CC_CSMI_SAS_GET_SATA_SIGNATURE
+
+typedef struct _CSMI_SAS_SATA_SIGNATURE {
+   __u8  bPhyIdentifier;
+   __u8  bReserved[3];
+   __u8  bSignatureFIS[20];
+} CSMI_SAS_SATA_SIGNATURE,
+  *PCSMI_SAS_SATA_SIGNATURE;
+
+typedef struct _CSMI_SAS_SATA_SIGNATURE_BUFFER {
+   IOCTL_HEADER IoctlHeader;
+   CSMI_SAS_SATA_SIGNATURE Signature;
+} CSMI_SAS_SATA_SIGNATURE_BUFFER,
+  *PCSMI_SAS_SATA_SIGNATURE_BUFFER;
+
+// CC_CSMI_SAS_GET_SCSI_ADDRESS
+
+typedef struct _CSMI_SAS_GET_SCSI_ADDRESS_BUFFER {
+   IOCTL_HEADER IoctlHeader;
+   __u8  bSASAddress[8];
+   __u8  bSASLun[8];
+   __u8  bHostIndex;
+   __u8  bPathId;
+   __u8  bTargetId;
+   __u8  bLun;
+} CSMI_SAS_GET_SCSI_ADDRESS_BUFFER,
+   *PCSMI_SAS_GET_SCSI_ADDRESS_BUFFER;
+
+// CC_CSMI_SAS_GET_DEVICE_ADDRESS
+
+typedef struct _CSMI_SAS_GET_DEVICE_ADDRESS_BUFFER {
+   IOCTL_HEADER IoctlHeader;
+   __u8  bHostIndex;
+   __u8  bPathId;
+   __u8  bTargetId;
+   __u8  bLun;
+   __u8  bSASAddress[8];
+   __u8  bSASLun[8];
+} CSMI_SAS_GET_DEVICE_ADDRESS_BUFFER,
+  *PCSMI_SAS_GET_DEVICE_ADDRESS_BUFFER;
+
+// CC_CSMI_SAS_TASK_MANAGEMENT
+
+typedef struct _CSMI_SAS_SSP_TASK_IU {
+   __u8  bHostIndex;
+   __u8  bPathId;
+   __u8  bTargetId;
+   __u8  bLun;
+   __u32 uFlags;
+   __u32 uQueueTag;
+   __u32 uReserved;
+   __u8  bTaskManagementFunction;
+   __u8  bReserved[7];
+   __u32 uInformation;
+} CSMI_SAS_SSP_TASK_IU,
+  *PCSMI_SAS_SSP_TASK_IU;
+
+typedef struct _CSMI_SAS_SSP_TASK_IU_BUFFER {
+   IOCTL_HEADER IoctlHeader;
+   CSMI_SAS_SSP_TASK_IU Parameters;
+   CSMI_SAS_SSP_PASSTHRU_STATUS Status;
+} CSMI_SAS_SSP_TASK_IU_BUFFER,
+  *PCSMI_SAS_SSP_TASK_IU_BUFFER;
+
+// CC_CSMI_SAS_GET_CONNECTOR_INFO
+
+typedef struct _CSMI_SAS_GET_CONNECTOR_INFO {
+   __u32 uPinout;
+   __u8  bConnector[16];
+   __u8  bLocation;
+   __u8  bReserved[15];
+} CSMI_SAS_CONNECTOR_INFO,
+  *PCSMI_SAS_CONNECTOR_INFO;
+
+typedef struct _CSMI_SAS_CONNECTOR_INFO_BUFFER {
+   IOCTL_HEADER IoctlHeader;
+   CSMI_SAS_CONNECTOR_INFO Reference[32];
+} CSMI_SAS_CONNECTOR_INFO_BUFFER,
+  *PCSMI_SAS_CONNECTOR_INFO_BUFFER;
+
+// CC_CSMI_SAS_GET_LOCATION
+
+typedef struct _CSMI_SAS_LOCATION_IDENTIFIER {
+   __u32 bLocationFlags;
+   __u8  bSASAddress[8];
+   __u8  bSASLun[8];
+   __u8  bEnclosureIdentifier[8];
+   __u8  bEnclosureName[32];
+   __u8  bBayPrefix[32];
+   __u8  bBayIdentifier;
+   __u8  bLocationState;
+   __u8  bReserved[2];
+} CSMI_SAS_LOCATION_IDENTIFIER,
+  *PCSMI_SAS_LOCATION_IDENTIFIER;
+
+typedef struct _CSMI_SAS_GET_LOCATION_BUFFER {
+   IOCTL_HEADER IoctlHeader;
+   __u8  bHostIndex;
+   __u8  bPathId;
+   __u8  bTargetId;
+   __u8  bLun;
+   __u8  bIdentify;
+   __u8  bNumberOfLocationIdentifiers;
+   __u8  bLengthOfLocationIdentifier;
+   CSMI_SAS_LOCATION_IDENTIFIER Location[1];
+} CSMI_SAS_GET_LOCATION_BUFFER,
+  *PCSMI_SAS_GET_LOCATION_BUFFER;
+
+// CC_CSMI_SAS_PHY_CONTROL
+
+typedef struct _CSMI_SAS_CHARACTER {
+   __u8  bTypeFlags;
+   __u8  bValue;
+} CSMI_SAS_CHARACTER,
+  *PCSMI_SAS_CHARACTER;
+
+typedef struct _CSMI_SAS_PHY_CONTROL {
+   __u8  bType;
+   __u8  bRate;
+   __u8  bReserved[6];
+   __u32 uVendorUnique[8];
+   __u32 uTransmitterFlags;
+   __i8  bTransmitAmplitude;
+   __i8  bTransmitterPreemphasis;
+   __i8  bTransmitterSlewRate;
+   __i8  bTransmitterReserved[13];
+   __u8  bTransmitterVendorUnique[64];
+   __u32 uReceiverFlags;
+   __i8  bReceiverThreshold;
+   __i8  bReceiverEqualizationGain;
+   __i8  bReceiverReserved[14];
+   __u8  bReceiverVendorUnique[64];
+   __u32 uPatternFlags;
+   __u8  bFixedPattern;
+   __u8  bUserPatternLength;
+   __u8  bPatternReserved[6];
+   CSMI_SAS_CHARACTER UserPatternBuffer[16];
+} CSMI_SAS_PHY_CONTROL,
+  *PCSMI_SAS_PHY_CONTROL;
+
+typedef struct _CSMI_SAS_PHY_CONTROL_BUFFER {
+   IOCTL_HEADER IoctlHeader;
+   __u32 uFunction;
+   __u8  bPhyIdentifier;
+   __u16 usLengthOfControl;
+   __u8  bNumberOfControls;
+   __u8  bReserved[4];
+   __u32 uLinkFlags;
+   __u8  bSpinupRate;
+   __u8  bLinkReserved[7];
+   __u32 uVendorUnique[8];
+   CSMI_SAS_PHY_CONTROL Control[1];
+} CSMI_SAS_PHY_CONTROL_BUFFER,
+  *PCSMI_SAS_PHY_CONTROL_BUFFER;
+
+//EDM #pragma CSMI_SAS_END_PACK
+#pragma pack()
+
+#endif // _CSMI_SAS_H_
index f8cdc3c9aceb6485f36822945094327f8e0239e1..05d24587b7d871c08c0d04b99df9639c1891a73c 100644 (file)
@@ -1,8 +1,73 @@
 /* drivers/message/fusion/linux_compat.h */
-
 #ifndef FUSION_LINUX_COMPAT_H
 #define FUSION_LINUX_COMPAT_H
 
+#include <linux/version.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_transport_sas.h>
+
+#ifndef PCI_VENDOR_ID_ATTO
+#define PCI_VENDOR_ID_ATTO     0x117c
+#endif
+
+#ifndef PCI_VENDOR_ID_BROCADE
+#define PCI_VENDOR_ID_BROCADE  0x1657
+#endif
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23))
+static inline void *shost_private(struct Scsi_Host *shost)
+{
+        return (void *)shost->hostdata;
+}
+#endif
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,6))
+static int inline scsi_device_online(struct scsi_device *sdev)
+{
+       return sdev->online;
+}
+#endif
+
+#ifndef spi_dv_pending
 #define spi_dv_pending(x) (((struct spi_transport_attrs *)&(x)->starget_data)->dv_pending)
+#endif
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23))
+/**
+ * mpt_scsilun_to_int: convert a scsi_lun to an int
+ * @scsilun:    struct scsi_lun to be converted.
+ *
+ * Description:
+ *     Convert @scsilun from a struct scsi_lun to a four byte host byte-ordered
+ *     integer, and return the result. The caller must check for
+ *     truncation before using this function.
+ *
+ * Notes:
+ *     The struct scsi_lun is assumed to be four levels, with each level
+ *     effectively containing a SCSI byte-ordered (big endian) short; the
+ *     addressing bits of each level are ignored (the highest two bits).
+ *     For a description of the LUN format, post SCSI-3 see the SCSI
+ *     Architecture Model, for SCSI-3 see the SCSI Controller Commands.
+ *
+ *     Given a struct scsi_lun of: 0a 04 0b 03 00 00 00 00, this function returns
+ *     the integer: 0x0b030a04
+ **/
+static inline int mpt_scsilun_to_int(struct scsi_lun *scsilun)
+{
+        int i;
+        unsigned int lun;
 
+        lun = 0;
+        for (i = 0; i < sizeof(lun); i += 2)
+                lun = lun | (((scsilun->scsi_lun[i] << 8) |
+                              scsilun->scsi_lun[i + 1]) << (i * 8));
+        return lun;
+}
+#endif
+#if (defined(CONFIG_SUSE_KERNEL) && !defined(scsi_is_sas_phy_local))
+#define SUSE_KERNEL_BASE       1
+#endif
+/*}-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 #endif /* _LINUX_COMPAT_H */
index 1acbdd61b670e421c7f410e44c56c16821589362..37058d428ff5f44343f6c514581ac9a5bce4545f 100644 (file)
@@ -6,7 +6,7 @@
  *          Title:  MPI Message independent structures and definitions
  *  Creation Date:  July 27, 2000
  *
- *    mpi.h Version:  01.05.13
+ *    mpi.h Version:  01.05.14
  *
  *  Version History
  *  ---------------
@@ -79,6 +79,7 @@
  *  03-27-06  01.05.11  Bumped MPI_HEADER_VERSION_UNIT.
  *  10-11-06  01.05.12  Bumped MPI_HEADER_VERSION_UNIT.
  *  05-24-07  01.05.13  Bumped MPI_HEADER_VERSION_UNIT.
+ *  08-07-07  01.05.14  Bumped MPI_HEADER_VERSION_UNIT.
  *  --------------------------------------------------------------------------
  */
 
 /* Note: The major versions of 0xe0 through 0xff are reserved */
 
 /* versioning for this MPI header set */
-#define MPI_HEADER_VERSION_UNIT             (0x10)
+#define MPI_HEADER_VERSION_UNIT             (0x11)
 #define MPI_HEADER_VERSION_DEV              (0x00)
 #define MPI_HEADER_VERSION_UNIT_MASK        (0xFF00)
 #define MPI_HEADER_VERSION_UNIT_SHIFT       (8)
index 2bd8adae0f002f0a01f3b052be8da4898bff2ac2..9244cc70b86b0f0b8ce85cc3a5c402d9b580f9fa 100644 (file)
@@ -6,7 +6,7 @@
  *          Title:  MPI Config message, structures, and Pages
  *  Creation Date:  July 27, 2000
  *
- *    mpi_cnfg.h Version:  01.05.15
+ *    mpi_cnfg.h Version:  01.05.16
  *
  *  Version History
  *  ---------------
  *                      Expander Page 0 Flags field.
  *                      Fixed define for
  *                      MPI_SAS_EXPANDER1_DISCINFO_BAD_PHY_DISABLED.
+ *  08-07-07  01.05.16  Added MPI_IOCPAGE6_CAP_FLAGS_MULTIPORT_DRIVE_SUPPORT
+ *                      define.
+ *                      Added BIOS Page 4 structure.
+ *                      Added MPI_RAID_PHYS_DISK1_PATH_MAX define for RAID
+ *                      Physcial Disk Page 1.
  *  --------------------------------------------------------------------------
  */
 
@@ -1159,6 +1164,7 @@ typedef struct _CONFIG_PAGE_IOC_6
 
 /* IOC Page 6 Capabilities Flags */
 
+#define MPI_IOCPAGE6_CAP_FLAGS_MULTIPORT_DRIVE_SUPPORT  (0x00000010)
 #define MPI_IOCPAGE6_CAP_FLAGS_DISABLE_SMART_POLLING    (0x00000008)
 
 #define MPI_IOCPAGE6_CAP_FLAGS_MASK_METADATA_SIZE       (0x00000006)
@@ -1428,6 +1434,15 @@ typedef struct _CONFIG_PAGE_BIOS_2
 #define MPI_BIOSPAGE2_FORM_SAS_WWN                      (0x05)
 #define MPI_BIOSPAGE2_FORM_ENCLOSURE_SLOT               (0x06)
 
+typedef struct _CONFIG_PAGE_BIOS_4
+{
+    CONFIG_PAGE_HEADER      Header;                     /* 00h */
+    U64                     ReassignmentBaseWWID;       /* 04h */
+} CONFIG_PAGE_BIOS_4, MPI_POINTER PTR_CONFIG_PAGE_BIOS_4,
+  BIOSPage4_t, MPI_POINTER pBIOSPage4_t;
+
+#define MPI_BIOSPAGE4_PAGEVERSION                       (0x00)
+
 
 /****************************************************************************
 *   SCSI Port Config Pages
@@ -2419,6 +2434,15 @@ typedef struct _RAID_PHYS_DISK1_PATH
 #define MPI_RAID_PHYSDISK1_FLAG_BROKEN          (0x0002)
 #define MPI_RAID_PHYSDISK1_FLAG_INVALID         (0x0001)
 
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check Header.PageLength or NumPhysDiskPaths at runtime.
+ */
+#ifndef MPI_RAID_PHYS_DISK1_PATH_MAX
+#define MPI_RAID_PHYS_DISK1_PATH_MAX    (1)
+#endif
+
 typedef struct _CONFIG_PAGE_RAID_PHYS_DISK_1
 {
     CONFIG_PAGE_HEADER              Header;             /* 00h */
@@ -2426,7 +2450,7 @@ typedef struct _CONFIG_PAGE_RAID_PHYS_DISK_1
     U8                              PhysDiskNum;        /* 05h */
     U16                             Reserved2;          /* 06h */
     U32                             Reserved1;          /* 08h */
-    RAID_PHYS_DISK1_PATH            Path[1];            /* 0Ch */
+    RAID_PHYS_DISK1_PATH            Path[MPI_RAID_PHYS_DISK1_PATH_MAX];/* 0Ch */
 } CONFIG_PAGE_RAID_PHYS_DISK_1, MPI_POINTER PTR_CONFIG_PAGE_RAID_PHYS_DISK_1,
   RaidPhysDiskPage1_t, MPI_POINTER pRaidPhysDiskPage1_t;
 
index 241592ab13adb6bc8ceddb9e3c9beec78c6c6f18..54622e4962973401677d08d9ff4797a28552f91f 100644 (file)
@@ -6,20 +6,20 @@
  Copyright (c) 2000-2007 LSI Corporation.
 
  ---------------------------------------
- Header Set Release Version:    01.05.16
- Header Set Release Date:       05-24-07
+ Header Set Release Version:    01.05.17
+ Header Set Release Date:       08-08-07
  ---------------------------------------
 
  Filename               Current version     Prior version
  ----------             ---------------     -------------
- mpi.h                  01.05.13            01.05.12
- mpi_ioc.h              01.05.14            01.05.13
- mpi_cnfg.h             01.05.15            01.05.14
+ mpi.h                  01.05.14            01.05.13
+ mpi_ioc.h              01.05.15            01.05.14
+ mpi_cnfg.h             01.05.16            01.05.15
  mpi_init.h             01.05.09            01.05.09
  mpi_targ.h             01.05.06            01.05.06
  mpi_fc.h               01.05.01            01.05.01
  mpi_lan.h              01.05.01            01.05.01
- mpi_raid.h             01.05.03            01.05.03
+ mpi_raid.h             01.05.04            01.05.03
  mpi_tool.h             01.05.03            01.05.03
  mpi_inb.h              01.05.01            01.05.01
  mpi_sas.h              01.05.04            01.05.04
@@ -96,6 +96,7 @@ mpi.h
  *  03-27-06  01.05.11  Bumped MPI_HEADER_VERSION_UNIT.
  *  10-11-06  01.05.12  Bumped MPI_HEADER_VERSION_UNIT.
  *  05-24-07  01.05.13  Bumped MPI_HEADER_VERSION_UNIT.
+ *  08-07-07  01.05.14  Bumped MPI_HEADER_VERSION_UNIT.
  *  --------------------------------------------------------------------------
 
 mpi_ioc.h
@@ -199,6 +200,11 @@ mpi_ioc.h
  *                      added _MULTI_PORT_DOMAIN.
  *  05-24-07  01.05.14  Added Common Boot Block type to FWDownload Request.
  *                      Added Common Boot Block type to FWUpload Request.
+ *  08-07-07  01.05.15  Added MPI_EVENT_SAS_INIT_RC_REMOVED define.
+ *                      Added MPI_EVENT_IR2_RC_DUAL_PORT_ADDED and
+ *                      MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED for IR2 event data.
+ *                      Added SASAddress field to SAS Initiator Device Table
+ *                      Overflow event data structure.
  *  --------------------------------------------------------------------------
 
 mpi_cnfg.h
@@ -496,6 +502,11 @@ mpi_cnfg.h
  *                      Expander Page 0 Flags field.
  *                      Fixed define for
  *                      MPI_SAS_EXPANDER1_DISCINFO_BAD_PHY_DISABLED.
+ *  08-07-07  01.05.16  Added MPI_IOCPAGE6_CAP_FLAGS_MULTIPORT_DRIVE_SUPPORT
+ *                      define.
+ *                      Added BIOS Page 4 structure.
+ *                      Added MPI_RAID_PHYS_DISK1_PATH_MAX define for RAID
+ *                      Physcial Disk Page 1.
  *  --------------------------------------------------------------------------
 
 mpi_init.h
@@ -661,6 +672,8 @@ mpi_raid.h
  *                      _SET_RESYNC_RATE and _SET_DATA_SCRUB_RATE.
  *  02-28-07  01.05.03  Added new RAID Action, Device FW Update Mode, and
  *                      associated defines.
+ *  08-07-07  01.05.04  Added Disable Full Rebuild bit to the ActionDataWord
+ *                      for the RAID Action MPI_RAID_ACTION_DISABLE_VOLUME.
  *  --------------------------------------------------------------------------
 
 mpi_tool.h
index 5cbb6bd048e146ae2e508661edfe9272b82ae31c..7bb422ac4ac03a87fdfc42578455923fd5aa289d 100644 (file)
@@ -6,7 +6,7 @@
  *          Title:  MPI IOC, Port, Event, FW Download, and FW Upload messages
  *  Creation Date:  August 11, 2000
  *
- *    mpi_ioc.h Version:  01.05.14
+ *    mpi_ioc.h Version:  01.05.15
  *
  *  Version History
  *  ---------------
  *                      added _MULTI_PORT_DOMAIN.
  *  05-24-07  01.05.14  Added Common Boot Block type to FWDownload Request.
  *                      Added Common Boot Block type to FWUpload Request.
+ *  08-07-07  01.05.15  Added MPI_EVENT_SAS_INIT_RC_REMOVED define.
+ *                      Added MPI_EVENT_IR2_RC_DUAL_PORT_ADDED and
+ *                      MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED for IR2 event data.
+ *                      Added SASAddress field to SAS Initiator Device Table
+ *                      Overflow event data structure.
  *  --------------------------------------------------------------------------
  */
 
@@ -708,6 +713,8 @@ typedef struct _MPI_EVENT_DATA_IR2
 #define MPI_EVENT_IR2_RC_PD_REMOVED                 (0x05)
 #define MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED       (0x06)
 #define MPI_EVENT_IR2_RC_REBUILD_MEDIUM_ERROR       (0x07)
+#define MPI_EVENT_IR2_RC_DUAL_PORT_ADDED            (0x08)
+#define MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED          (0x09)
 
 /* defines for logical disk states */
 #define MPI_LD_STATE_OPTIMAL                        (0x00)
@@ -902,6 +909,7 @@ typedef struct _EVENT_DATA_SAS_INIT_DEV_STATUS_CHANGE
 
 /* defines for the ReasonCode field of the SAS Initiator Device Status Change event */
 #define MPI_EVENT_SAS_INIT_RC_ADDED                 (0x01)
+#define MPI_EVENT_SAS_INIT_RC_REMOVED               (0x02)
 
 /* SAS Initiator Device Table Overflow Event data */
 
@@ -910,6 +918,7 @@ typedef struct _EVENT_DATA_SAS_INIT_TABLE_OVERFLOW
     U8                      MaxInit;                    /* 00h */
     U8                      CurrentInit;                /* 01h */
     U16                     Reserved1;                  /* 02h */
+    U64                     SASAddress;                 /* 04h */
 } EVENT_DATA_SAS_INIT_TABLE_OVERFLOW,
   MPI_POINTER PTR_EVENT_DATA_SAS_INIT_TABLE_OVERFLOW,
   MpiEventDataSasInitTableOverflow_t,
index 6be1f6b65777a07208da7ad26eb084c7c8308b7e..503094940e8f25bc452fbd278dbea4e51e56a2f8 100644 (file)
@@ -1,6 +1,6 @@
 /***************************************************************************
  *                                                                         *
- *  Copyright 2003 LSI Corporation.  All rights reserved.            *
+ *  Copyright 2007 LSI Corporation.  All rights reserved.            *
  *                                                                         *
  * Description                                                             *
  * ------------                                                            *
@@ -73,6 +73,8 @@
 #define IOP_LOGINFO_CODE_TARGET_MODE_ABORT_EXACT_IO          (0x00070004)
 #define IOP_LOGINFO_CODE_TARGET_MODE_ABORT_EXACT_IO_REQ      (0x00070005)
 
+#define IOP_LOGINFO_CODE_LOG_TIMESTAMP_EVENT                 (0x00080000)
+
 /****************************************************************************/
 /* PL LOGINFO_CODE defines, valid if IOC_LOGINFO_ORIGINATOR = PL            */
 /****************************************************************************/
@@ -92,7 +94,7 @@
 #define PL_LOGINFO_SUB_CODE_OPEN_FAIL_OPEN_TIMEOUT_EXP       (0x0000000C)
 #define PL_LOGINFO_SUB_CODE_OPEN_FAIL_UNUSED_0D              (0x0000000D)
 #define PL_LOGINFO_SUB_CODE_OPEN_FAIL_DVTBLE_ACCSS_FAIL      (0x0000000E)
-#define PL_LOGINFO_SUB CODE_OPEN_FAIL_BAD_DEST               (0x00000011)
+#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_BAD_DEST               (0x00000011)
 #define PL_LOGINFO_SUB_CODE_OPEN_FAIL_RATE_NOT_SUPP          (0x00000012)
 #define PL_LOGINFO_SUB_CODE_OPEN_FAIL_PROT_NOT_SUPP          (0x00000013)
 #define PL_LOGINFO_SUB_CODE_OPEN_FAIL_RESERVED_ABANDON0      (0x00000014)
 #define PL_LOGINFO_SUB_CODE_DISCOVERY_REMOTE_SEP_RESET       (0x00000E01)
 #define PL_LOGINFO_SUB_CODE_SECOND_OPEN                      (0x00000F00)
 #define PL_LOGINFO_SUB_CODE_DSCVRY_SATA_INIT_TIMEOUT         (0x00001000)
+#define PL_LOGINFO_SUB_CODE_BREAK_ON_SATA_CONNECTION            (0x00002000) /* not currently used in mainline */
+#define PL_LOGINFO_SUB_CODE_BREAK_ON_STUCK_LINK              (0x00003000)
+#define PL_LOGINFO_SUB_CODE_BREAK_ON_STUCK_LINK_AIP          (0x00004000)
+#define PL_LOGINFO_SUB_CODE_BREAK_ON_INCOMPLETE_BREAK_RCVD   (0x00005000)
 
 #define PL_LOGINFO_CODE_ENCL_MGMT_SMP_FRAME_FAILURE          (0x00200000) /* Can't get SMP Frame */
 #define PL_LOGINFO_CODE_ENCL_MGMT_SMP_READ_ERROR             (0x00200010) /* Error occured on SMP Read */
 #define IR_LOGINFO_VOLUME_ACTIVATE_VOLUME_FAILED               (0x00010014)
 /* Activation failed trying to import the volume */
 #define IR_LOGINFO_VOLUME_ACTIVATING_IMPORT_VOLUME_FAILED      (0x00010015)
+/* Activation failed trying to import the volume */
+#define IR_LOGINFO_VOLUME_ACTIVATING_TOO_MANY_PHYS_DISKS       (0x00010016)
 
 /* Phys Disk failed, too many phys disks */
 #define IR_LOGINFO_PHYSDISK_CREATE_TOO_MANY_DISKS              (0x00010020)
 /* Compatibility Error : IME size limited to < 2TB */
 #define IR_LOGINFO_COMPAT_ERROR_IME_VOL_NOT_CURRENTLY_SUPPORTED (0x0001003D)
 
+/* Device Firmware Update: DFU can only be started once */
+#define IR_LOGINFO_DEV_FW_UPDATE_ERR_DFU_IN_PROGRESS            (0x00010050)
+/* Device Firmware Update: Volume must be Optimal/Active/non-Quiesced */
+#define IR_LOGINFO_DEV_FW_UPDATE_ERR_DEVICE_IN_INVALID_STATE    (0x00010051)
+/* Device Firmware Update: DFU Timeout cannot be zero */
+#define IR_LOGINFO_DEV_FW_UPDATE_ERR_INVALID_TIMEOUT            (0x00010052)
+/* Device Firmware Update: CREATE TIMER FAILED */
+#define IR_LOGINFO_DEV_FW_UPDATE_ERR_NO_TIMERS                  (0x00010053)
+/* Device Firmware Update: Failed to read SAS_IO_UNIT_PG_1 */
+#define IR_LOGINFO_DEV_FW_UPDATE_ERR_READING_CFG_PAGE           (0x00010054)
+/* Device Firmware Update: Invalid SAS_IO_UNIT_PG_1 value(s) */
+#define IR_LOGINFO_DEV_FW_UPDATE_ERR_PORT_IO_TIMEOUTS_REQUIRED  (0x00010055)
+/* Device Firmware Update: Unable to allocate memory for page */
+#define IR_LOGINFO_DEV_FW_UPDATE_ERR_ALLOC_CFG_PAGE             (0x00010056)
+/* Device Firmware Update:  */
+//#define IR_LOGINFO_DEV_FW_UPDATE_ERR_                         (0x00010054)
+
 
 /****************************************************************************/
 /* Defines for convenience                                                  */
index 2856108421d71fa1b88d73a45e7f38765cf012d8..3e99f9c3d99b9045932f277cdb98e0e80d3800e5 100644 (file)
@@ -6,7 +6,7 @@
  *          Title:  MPI RAID message and structures
  *  Creation Date:  February 27, 2001
  *
- *    mpi_raid.h Version:  01.05.03
+ *    mpi_raid.h Version:  01.05.04
  *
  *  Version History
  *  ---------------
@@ -34,6 +34,8 @@
  *                      _SET_RESYNC_RATE and _SET_DATA_SCRUB_RATE.
  *  02-28-07  01.05.03  Added new RAID Action, Device FW Update Mode, and
  *                      associated defines.
+ *  08-07-07  01.05.04  Added Disable Full Rebuild bit to the ActionDataWord
+ *                      for the RAID Action MPI_RAID_ACTION_DISABLE_VOLUME.
  *  --------------------------------------------------------------------------
  */
 
@@ -105,6 +107,9 @@ typedef struct _MSG_RAID_ACTION
 #define MPI_RAID_ACTION_ADATA_KEEP_LBA0             (0x00000000)
 #define MPI_RAID_ACTION_ADATA_ZERO_LBA0             (0x00000002)
 
+/* ActionDataWord defines for use with MPI_RAID_ACTION_DISABLE_VOLUME action */
+#define MPI_RAID_ACTION_ADATA_DISABLE_FULL_REBUILD  (0x00000001)
+
 /* ActionDataWord defines for use with MPI_RAID_ACTION_ACTIVATE_VOLUME action */
 #define MPI_RAID_ACTION_ADATA_INACTIVATE_ALL        (0x00000001)
 
index 08dad9c1e4465e9bd3db4c03fe4c16bfeb0df621..bef230c3b3d35867ae365bf87499571f038db0ba 100644 (file)
@@ -6,7 +6,7 @@
  *          Title:  MPI Basic type definitions
  *  Creation Date:  June 6, 2000
  *
- *    mpi_type.h Version:  01.05.01
+ *    mpi_type.h Version:  01.05.02
  *
  *  Version History
  *  ---------------
@@ -20,6 +20,7 @@
  *  08-08-01  01.02.01  Original release for v1.2 work.
  *  05-11-04  01.03.01  Original release for MPI v1.3.
  *  08-19-04  01.05.01  Original release for MPI v1.5.
+ *  08-30-05  01.05.02  Added PowerPC option to #ifdef's.
  *  --------------------------------------------------------------------------
  */
 
@@ -49,8 +50,18 @@ typedef signed   short  S16;
 typedef unsigned short  U16;
 
 
-typedef int32_t   S32;
-typedef u_int32_t U32;
+#if defined(unix) || defined(__arm) || defined(ALPHA) || defined(__PPC__) || defined(__ppc)
+
+    typedef signed   int   S32;
+    typedef unsigned int   U32;
+
+#else
+
+    typedef signed   long  S32;
+    typedef unsigned long  U32;
+
+#endif
+
 
 typedef struct _S64
 {
index eea5287659b25faf422f6baf3a360302bac4b4b7..4c64dc8a7f1d69437c8a327612b6e7bc047219a5 100644 (file)
@@ -45,7 +45,7 @@
     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-
+#include <linux/version.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>           /* needed for in_interrupt() proto */
 #include <linux/dma-mapping.h>
+#include <linux/sort.h>
 #include <asm/io.h>
 #ifdef CONFIG_MTRR
 #include <asm/mtrr.h>
 #endif
 
 #include "mptbase.h"
+#include "linux_compat.h"      /* linux-2.6 tweaks */
 #include "lsi/mpi_log_fc.h"
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -87,11 +89,20 @@ static int mpt_channel_mapping;
 module_param(mpt_channel_mapping, int, 0);
 MODULE_PARM_DESC(mpt_channel_mapping, " Mapping id's to channels (default=0)");
 
-static int mpt_debug_level;
+int mpt_debug_level;
 static int mpt_set_debug_level(const char *val, struct kernel_param *kp);
 module_param_call(mpt_debug_level, mpt_set_debug_level, param_get_int,
                  &mpt_debug_level, 0600);
 MODULE_PARM_DESC(mpt_debug_level, " debug level - refer to mptdebug.h - (default=0)");
+EXPORT_SYMBOL(mpt_debug_level);
+
+int mpt_fwfault_debug;
+module_param_call(mpt_fwfault_debug, param_set_int, param_get_int,
+                 &mpt_fwfault_debug, 0600);
+MODULE_PARM_DESC(mpt_fwfault_debug, "Enable detection of Firmware fault"
+               " and halt Firmware on fault - (default=0)");
+EXPORT_SYMBOL(mpt_fwfault_debug);
+
 
 #ifdef MFCNT
 static int mfcounter = 0;
@@ -102,7 +113,6 @@ static int mfcounter = 0;
 /*
  *  Public data...
  */
-
 struct proc_dir_entry *mpt_proc_root_dir;
 
 #define WHOINIT_UNKNOWN                0xAA
@@ -125,6 +135,8 @@ static struct mpt_pci_driver        *MptDeviceDriverHandlers[MPT_MAX_PROTOCOL_DRIVERS]
 
 static DECLARE_WAIT_QUEUE_HEAD(mpt_waitq);
 
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
 /*
  *  Driver Callback Index's
  */
@@ -135,8 +147,7 @@ static u8 last_drv_idx;
 /*
  *  Forward protos...
  */
-static irqreturn_t 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     mptbase_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply);
 static int     mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes,
                        u32 *req, int replyBytes, u16 *u16reply, int maxwait,
                        int sleepFlag);
@@ -167,9 +178,8 @@ static int  mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum);
 static int     mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum);
 static void    mpt_read_ioc_pg_1(MPT_ADAPTER *ioc);
 static void    mpt_read_ioc_pg_4(MPT_ADAPTER *ioc);
-static void    mpt_timer_expired(unsigned long data);
 static void    mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc);
-static int     SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch);
+static int     SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch, int sleepFlag);
 static int     SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp);
 static int     mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag);
 static int     mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init);
@@ -184,7 +194,6 @@ static int  procmpt_iocinfo_read(char *buf, char **start, off_t offset,
 #endif
 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_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf);
 static void    mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info);
@@ -193,6 +202,7 @@ static void mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info);
 static int     mpt_read_ioc_pg_3(MPT_ADAPTER *ioc);
 static void    mpt_inactive_raid_list_free(MPT_ADAPTER *ioc);
 
+
 /* module entry point */
 static int  __init    fusion_init  (void);
 static void __exit    fusion_exit  (void);
@@ -223,7 +233,16 @@ pci_enable_io_access(struct pci_dev *pdev)
        pci_write_config_word(pdev, PCI_COMMAND, command_reg);
 }
 
-static int mpt_set_debug_level(const char *val, struct kernel_param *kp)
+/**
+ *     mpt_set_debug_level - global setting of the mpt_debug_level
+ *     found via /sys/module/mptbase/parameters/mpt_debug_level
+ *     @val:
+ *     @kp:
+ *
+ *     Returns
+ **/
+static int
+mpt_set_debug_level(const char *val, struct kernel_param *kp)
 {
        int ret = param_set_int(val, kp);
        MPT_ADAPTER *ioc;
@@ -253,6 +272,116 @@ mpt_get_cb_idx(MPT_DRIVER_CLASS dclass)
        return 0;
 }
 
+/**
+ * mpt_is_discovery_complete - determine if discovery has completed
+ * @ioc: per adatper instance
+ *
+ * Returns 1 when discovery completed, else zero.
+ */
+static int
+mpt_is_discovery_complete(MPT_ADAPTER *ioc)
+{
+       ConfigExtendedPageHeader_t hdr;
+       CONFIGPARMS cfg;
+       SasIOUnitPage0_t *buffer;
+       dma_addr_t dma_handle;
+       int rc = 0;
+
+       memset(&hdr, 0, sizeof(ConfigExtendedPageHeader_t));
+       memset(&cfg, 0, sizeof(CONFIGPARMS));
+       hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION;
+       hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
+       hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
+       cfg.cfghdr.ehdr = &hdr;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+
+       if ((mpt_config(ioc, &cfg)))
+               goto out;
+       if (!hdr.ExtPageLength)
+               goto out;
+
+       buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
+           &dma_handle);
+       if (!buffer)
+               goto out;
+
+       cfg.physAddr = dma_handle;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+
+       if ((mpt_config(ioc, &cfg)))
+               goto out_free_consistent;
+
+       if (!(buffer->PhyData[0].PortFlags &
+           MPI_SAS_IOUNIT0_PORT_FLAGS_DISCOVERY_IN_PROGRESS))
+               rc = 1;
+
+ out_free_consistent:
+       pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
+           buffer, dma_handle);
+ out:
+       return rc;
+}
+
+/**
+ *     mpt_fault_reset_work - work performed on workq after ioc fault
+ *     @work: input argument, used to derive ioc
+ *
+**/
+static void
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19))
+mpt_fault_reset_work(struct work_struct *work)
+{
+       MPT_ADAPTER     *ioc =
+           container_of(work, MPT_ADAPTER, fault_reset_work.work);
+#else
+mpt_fault_reset_work(void *arg)
+{
+       MPT_ADAPTER     *ioc = (MPT_ADAPTER *)arg;
+#endif
+       u32              ioc_raw_state;
+       int              rc;
+       unsigned long    flags;
+
+       if (ioc->ioc_reset_in_progress || !ioc->active)
+               goto out;
+
+       ioc_raw_state = mpt_GetIocState(ioc, 0);
+       if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
+               printk(MYIOC_s_WARN_FMT "IOC is in FAULT state (%04xh)!!!\n",
+                   ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK);
+               printk(MYIOC_s_WARN_FMT "Issuing HardReset from %s!!\n",
+                   ioc->name, __FUNCTION__);
+               rc = mpt_HardResetHandler(ioc, CAN_SLEEP);
+               printk(MYIOC_s_WARN_FMT "%s: HardReset: %s\n", ioc->name,
+                   __FUNCTION__, (rc == 0) ? "success" : "failed");
+               ioc_raw_state = mpt_GetIocState(ioc, 0);
+               if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT)
+                       printk(MYIOC_s_WARN_FMT "IOC is in FAULT state after "
+                           "reset (%04xh)\n", ioc->name, ioc_raw_state &
+                           MPI_DOORBELL_DATA_MASK);
+       } else if (ioc->bus_type == SAS && ioc->sas_discovery_quiesce_io) {
+               if ((mpt_is_discovery_complete(ioc))) {
+                       devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "clearing "
+                           "discovery_quiesce_io flag\n", ioc->name));
+                       ioc->sas_discovery_quiesce_io = 0;
+               }
+       }
+
+ out:
+       /*
+        * Take turns polling alternate controller
+        */
+       if (ioc->alt_ioc)
+               ioc = ioc->alt_ioc;
+
+       /* rearm the timer */
+       spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
+       if (ioc->reset_work_q)
+               queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work,
+                       msecs_to_jiffies(MPT_POLLING_INTERVAL));
+       spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
+}
+
 /*
  *  Process turbo (context) reply...
  */
@@ -305,7 +434,7 @@ mpt_turbo_reply(MPT_ADAPTER *ioc, u32 pa)
 
        /*  Check for (valid) IO callback!  */
        if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
-               MptCallbacks[cb_idx] == NULL) {
+           MptCallbacks[cb_idx] == NULL) {
                printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
                                __FUNCTION__, ioc->name, cb_idx);
                goto out;
@@ -349,6 +478,7 @@ mpt_reply(MPT_ADAPTER *ioc, u32 pa)
 
        dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got non-TURBO reply=%p req_idx=%x cb_idx=%x Function=%x\n",
                        ioc->name, mr, req_idx, cb_idx, mr->u.hdr.Function));
+
        DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mr);
 
         /*  Check/log IOC log info
@@ -364,12 +494,15 @@ mpt_reply(MPT_ADAPTER *ioc, u32 pa)
                        mpt_sas_log_info(ioc, log_info);
        }
 
+       /* TODO - add shost_attrs, or command line option, and
+        * extend this to SAS/FC
+        */
        if (ioc_stat & MPI_IOCSTATUS_MASK)
                mpt_iocstatus_info(ioc, (u32)ioc_stat, mf);
 
        /*  Check for (valid) IO callback!  */
        if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
-               MptCallbacks[cb_idx] == NULL) {
+           MptCallbacks[cb_idx] == NULL) {
                printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
                                __FUNCTION__, ioc->name, cb_idx);
                freeme = 0;
@@ -387,11 +520,11 @@ mpt_reply(MPT_ADAPTER *ioc, u32 pa)
        mb();
 }
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *     mpt_interrupt - MPT adapter (IOC) specific interrupt handler.
  *     @irq: irq number (not used)
  *     @bus_id: bus identifier cookie == pointer to MPT_ADAPTER structure
+ *     @r: pt_regs pointer (not used)
  *
  *     This routine is registered via the request_irq() kernel API call,
  *     and handles all interrupts generated from a specific MPT adapter
@@ -403,9 +536,13 @@ mpt_reply(MPT_ADAPTER *ioc, u32 pa)
  *     This routine handles register-level access of the adapter but
  *     dispatches (calls) a protocol-specific callback routine to handle
  *     the protocol-specific details of the MPT request completion.
- */
+ **/
 static irqreturn_t
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18))
+mpt_interrupt(int irq, void *bus_id)
+#else
 mpt_interrupt(int irq, void *bus_id, struct pt_regs *r)
+#endif
 {
        MPT_ADAPTER *ioc = bus_id;
        u32 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);
@@ -429,9 +566,9 @@ mpt_interrupt(int irq, void *bus_id, struct pt_regs *r)
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
- *     mpt_base_reply - MPT base driver's callback routine
+ *     mptbase_reply - MPT base driver's callback routine
  *     @ioc: Pointer to MPT_ADAPTER structure
- *     @mf: Pointer to original MPT request frame
+ *     @req: Pointer to original MPT request frame
  *     @reply: Pointer to MPT reply frame (NULL if TurboReply)
  *
  *     MPT base driver's callback routine; all base driver
@@ -442,122 +579,49 @@ mpt_interrupt(int irq, void *bus_id, struct pt_regs *r)
  *     should be freed, or 0 if it shouldn't.
  */
 static int
-mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply)
+mptbase_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply)
 {
+       EventNotificationReply_t *pEventReply;
+       u8 event;
+       int evHandlers;
        int freereq = 1;
-       u8 func;
-
-       dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_base_reply() called\n", ioc->name));
-#ifdef CONFIG_FUSION_LOGGING
-       if ((ioc->debug_level & MPT_DEBUG_MSG_FRAME) &&
-                       !(reply->u.hdr.MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)) {
-               dmfprintk(ioc, printk(MYIOC_s_INFO_FMT ": Original request frame (@%p) header\n",
-                   ioc->name, mf));
-               DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)mf);
-       }
-#endif
-
-       func = reply->u.hdr.Function;
-       dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_base_reply, Function=%02Xh\n",
-                       ioc->name, func));
-
-       if (func == MPI_FUNCTION_EVENT_NOTIFICATION) {
-               EventNotificationReply_t *pEvReply = (EventNotificationReply_t *) reply;
-               int evHandlers = 0;
-               int results;
-
-               results = ProcessEventNotification(ioc, pEvReply, &evHandlers);
-               if (results != evHandlers) {
-                       /* CHECKME! Any special handling needed here? */
-                       devtverboseprintk(ioc, printk(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.
-                */
-               if (pEvReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY) {
+       switch (reply->u.hdr.Function) {
+       case MPI_FUNCTION_EVENT_NOTIFICATION:
+               pEventReply = (EventNotificationReply_t *)reply;
+               evHandlers = 0;
+               ProcessEventNotification(ioc, pEventReply, &evHandlers);
+               event = le32_to_cpu(pEventReply->Event) & 0xFF;
+               if (pEventReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)
                        freereq = 0;
-               } else {
-                       devtverboseprintk(ioc, printk(MYIOC_s_WARN_FMT "EVENT_NOTIFICATION reply %p returns Request frame\n",
-                               ioc->name, pEvReply));
-               }
-
-#ifdef CONFIG_PROC_FS
-//             LogEvent(ioc, pEvReply);
-#endif
-
-       } else if (func == MPI_FUNCTION_EVENT_ACK) {
-               dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_base_reply, EventAck reply received\n",
-                               ioc->name));
-       } else if (func == MPI_FUNCTION_CONFIG) {
-               CONFIGPARMS *pCfg;
-               unsigned long flags;
-
-               dcprintk(ioc, printk(MYIOC_s_DEBUG_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);
-                       list_del(&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;
-                               dcprintk(ioc, printk(MYIOC_s_NOTE_FMT "  IOCStatus=%04xh, IOCLogInfo=%08xh\n",
-                                    ioc->name, status, le32_to_cpu(pReply->IOCLogInfo)));
-
-                               pCfg->status = status;
-                               if (status == MPI_IOCSTATUS_SUCCESS) {
-                                       if ((pReply->Header.PageType &
-                                           MPI_CONFIG_PAGETYPE_MASK) ==
-                                           MPI_CONFIG_PAGETYPE_EXTENDED) {
-                                               pCfg->cfghdr.ehdr->ExtPageLength =
-                                                   le16_to_cpu(pReply->ExtPageLength);
-                                               pCfg->cfghdr.ehdr->ExtPageType =
-                                                   pReply->ExtPageType;
-                                       }
-                                       pCfg->cfghdr.hdr->PageVersion = pReply->Header.PageVersion;
-
-                                       /* If this is a regular header, save PageLength. */
-                                       /* LMP Do this better so not using a reserved field! */
-                                       pCfg->cfghdr.hdr->PageLength = pReply->Header.PageLength;
-                                       pCfg->cfghdr.hdr->PageNumber = pReply->Header.PageNumber;
-                                       pCfg->cfghdr.hdr->PageType = pReply->Header.PageType;
-                               }
-                       }
-
-                       /*
-                        *      Wake up the original calling thread
-                        */
-                       pCfg->wait_done = 1;
-                       wake_up(&mpt_waitq);
+               if (event != MPI_EVENT_EVENT_CHANGE)
+                       break;
+       case MPI_FUNCTION_CONFIG:
+       case MPI_FUNCTION_SAS_IO_UNIT_CONTROL:
+               ioc->mptbase_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
+               if (reply) {
+                       ioc->mptbase_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
+                       memcpy(ioc->mptbase_cmds.reply, reply,
+                           min(MPT_DEFAULT_FRAME_SIZE,
+                               4 * reply->u.reply.MsgLength));
                }
-       } else if (func == MPI_FUNCTION_SAS_IO_UNIT_CONTROL) {
-               /* we should be always getting a reply frame */
-               memcpy(ioc->persist_reply_frame, reply,
-                   min(MPT_DEFAULT_FRAME_SIZE,
-                   4*reply->u.reply.MsgLength));
-               del_timer(&ioc->persist_timer);
-               ioc->persist_wait_done = 1;
-               wake_up(&mpt_waitq);
-       } else {
-               printk(MYIOC_s_ERR_FMT "Unexpected msg function (=%02Xh) reply received!\n",
-                               ioc->name, func);
+               if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_PENDING) {
+                       ioc->mptbase_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
+                       complete(&ioc->mptbase_cmds.done);
+               } else
+                       freereq = 0;
+               if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_FREE_MF)
+                       freereq = 1;
+               break;
+       case MPI_FUNCTION_EVENT_ACK:
+               devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "EventAck reply received\n", ioc->name));
+               break;
+       default:
+               printk(MYIOC_s_ERR_FMT
+                   "Unexpected msg function (=%02Xh) reply received!\n",
+                   ioc->name, reply->u.hdr.Function);
+               break;
        }
 
        /*
@@ -567,7 +631,6 @@ mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply)
        return freereq;
 }
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *     mpt_register - Register protocol-specific main callback handler.
  *     @cbfunc: callback function pointer
@@ -586,7 +649,7 @@ mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply)
  *     {N,...,7,6,5,...,1} if successful.
  *     A return value of MPT_MAX_PROTOCOL_DRIVERS (including zero!) should be
  *     considered an error by the caller.
- */
+ **/
 u8
 mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass)
 {
@@ -610,14 +673,13 @@ mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass)
        return last_drv_idx;
 }
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *     mpt_deregister - Deregister a protocol drivers resources.
  *     @cb_idx: previously registered callback handle
  *
  *     Each protocol-specific driver should call this routine when its
  *     module is unloaded.
- */
+ **/
 void
 mpt_deregister(u8 cb_idx)
 {
@@ -630,7 +692,6 @@ mpt_deregister(u8 cb_idx)
        }
 }
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *     mpt_event_register - Register protocol-specific event callback
  *     handler.
@@ -641,7 +702,7 @@ mpt_deregister(u8 cb_idx)
  *     if/when they choose to be notified of MPT events.
  *
  *     Returns 0 for success.
- */
+ **/
 int
 mpt_event_register(u8 cb_idx, MPT_EVHANDLER ev_cbfunc)
 {
@@ -652,7 +713,6 @@ mpt_event_register(u8 cb_idx, MPT_EVHANDLER ev_cbfunc)
        return 0;
 }
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *     mpt_event_deregister - Deregister protocol-specific event callback
  *     handler.
@@ -661,7 +721,7 @@ mpt_event_register(u8 cb_idx, MPT_EVHANDLER ev_cbfunc)
  *     Each protocol-specific driver should call this routine
  *     when it does not (or can no longer) handle events,
  *     or when its module is unloaded.
- */
+ **/
 void
 mpt_event_deregister(u8 cb_idx)
 {
@@ -671,7 +731,6 @@ mpt_event_deregister(u8 cb_idx)
        MptEvHandlers[cb_idx] = NULL;
 }
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *     mpt_reset_register - Register protocol-specific IOC reset handler.
  *     @cb_idx: previously registered (via mpt_register) callback handle
@@ -681,7 +740,7 @@ mpt_event_deregister(u8 cb_idx)
  *     if/when they choose to be notified of IOC resets.
  *
  *     Returns 0 for success.
- */
+ **/
 int
 mpt_reset_register(u8 cb_idx, MPT_RESETHANDLER reset_func)
 {
@@ -692,7 +751,6 @@ mpt_reset_register(u8 cb_idx, MPT_RESETHANDLER reset_func)
        return 0;
 }
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *     mpt_reset_deregister - Deregister protocol-specific IOC reset handler.
  *     @cb_idx: previously registered callback handle
@@ -700,7 +758,7 @@ mpt_reset_register(u8 cb_idx, MPT_RESETHANDLER reset_func)
  *     Each protocol-specific driver should call this routine
  *     when it does not (or can no longer) handle IOC reset handling,
  *     or when its module is unloaded.
- */
+ **/
 void
 mpt_reset_deregister(u8 cb_idx)
 {
@@ -710,12 +768,11 @@ mpt_reset_deregister(u8 cb_idx)
        MptResetHandlers[cb_idx] = NULL;
 }
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *     mpt_device_driver_register - Register device driver hooks
  *     @dd_cbfunc: driver callbacks struct
  *     @cb_idx: MPT protocol driver index
- */
+ **/
 int
 mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, u8 cb_idx)
 {
@@ -729,20 +786,21 @@ mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, u8 cb_idx)
 
        /* call per pci device probe entry point */
        list_for_each_entry(ioc, &ioc_list, list) {
+               if (!pci_get_drvdata(ioc->pcidev))
+                       continue;
                id = ioc->pcidev->driver ?
                    ioc->pcidev->driver->id_table : NULL;
                if (dd_cbfunc->probe)
                        dd_cbfunc->probe(ioc->pcidev, id);
-        }
+       }
 
        return 0;
 }
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *     mpt_device_driver_deregister - DeRegister device driver hooks
  *     @cb_idx: MPT protocol driver index
- */
+ **/
 void
 mpt_device_driver_deregister(u8 cb_idx)
 {
@@ -762,8 +820,6 @@ mpt_device_driver_deregister(u8 cb_idx)
        MptDeviceDriverHandlers[cb_idx] = NULL;
 }
 
-
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *     mpt_get_msg_frame - Obtain a MPT request frame from the pool (of 1024)
  *     allocated per MPT adapter.
@@ -772,7 +828,7 @@ mpt_device_driver_deregister(u8 cb_idx)
  *
  *     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(u8 cb_idx, MPT_ADAPTER *ioc)
 {
@@ -802,7 +858,6 @@ mpt_get_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc)
                mf->u.frame.linkage.arg1 = 0;
                mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx;  /* byte */
                req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
-                                                               /* u16! */
                req_idx = req_offset / ioc->req_sz;
                mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
                mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
@@ -832,7 +887,6 @@ mpt_get_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc)
        return mf;
 }
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *     mpt_put_msg_frame - Send a protocol specific MPT request frame
  *     to a IOC.
@@ -842,7 +896,7 @@ mpt_get_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc)
  *
  *     This routine posts a MPT request frame to the request post FIFO of a
  *     specific MPT adapter.
- */
+ **/
 void
 mpt_put_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
 {
@@ -853,14 +907,14 @@ mpt_put_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
        /* ensure values are reset properly! */
        mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx;          /* byte */
        req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
-                                                               /* u16! */
        req_idx = req_offset / ioc->req_sz;
        mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
        mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
 
        DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf);
 
-       mf_dma_addr = (ioc->req_frames_low_dma + req_offset) | ioc->RequestNB[req_idx];
+       mf_dma_addr = (ioc->req_frames_low_dma + req_offset) |
+           ioc->RequestNB[req_idx];
        dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d "
            "RequestNB=%x\n", ioc->name, mf_dma_addr, req_idx,
            ioc->RequestNB[req_idx]));
@@ -899,7 +953,6 @@ mpt_put_msg_frame_hi_pri(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
        CHIPREG_WRITE32(&ioc->chip->RequestHiPriFifo, mf_dma_addr);
 }
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *     mpt_free_msg_frame - Place MPT request frame back on FreeQ.
  *     @handle: Handle of registered MPT protocol driver
@@ -908,7 +961,7 @@ mpt_put_msg_frame_hi_pri(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
  *
  *     This routine places a MPT request frame back on the MPT adapter's
  *     FreeQ.
- */
+ **/
 void
 mpt_free_msg_frame(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
 {
@@ -916,61 +969,72 @@ mpt_free_msg_frame(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
 
        /*  Put Request back on FreeQ!  */
        spin_lock_irqsave(&ioc->FreeQlock, flags);
-       mf->u.frame.linkage.arg1 = 0xdeadbeaf; /* signature to know if this mf is freed */
+       if (cpu_to_le32(mf->u.frame.linkage.arg1) == 0xdeadbeaf)
+               goto out;
+       mf->u.frame.linkage.arg1 = cpu_to_le32(0xdeadbeaf); /* signature to know if this mf is freed */
        list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
 #ifdef MFCNT
        ioc->mfcnt--;
 #endif
+ out:
        spin_unlock_irqrestore(&ioc->FreeQlock, flags);
 }
 
-
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
- *     mpt_add_sge - Place a simple 32 bit SGE at address addr.
- *     @addr: virtual address for SGE
+ *     mpt_add_sge - Place a simple 32 bit 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.
+ **/
 static void
-mpt_add_sge(char *addr, u32 flagslength, dma_addr_t dma_addr)
+mpt_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr)
 {
-       SGESimple32_t *pSge = (SGESimple32_t *) addr;
+       SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
        pSge->FlagsLength = cpu_to_le32(flagslength);
        pSge->Address = cpu_to_le32(dma_addr);
 }
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
 /**
- *     mpt_add_sge_64bit - Place a simple 64 bit SGE at address addr.
- *     @addr: virtual address for SGE
+ *     mpt_add_sge_64bit - Place a simple 64 bit 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.
+ **/
 static void
-mpt_add_sge_64bit(char *addr, u32 flagslength, dma_addr_t dma_addr)
+mpt_add_sge_64bit(char *pAddr, u32 flagslength, dma_addr_t dma_addr)
 {
-       SGESimple64_t *pSge = (SGESimple64_t *) addr;
-       u32 tmp = dma_addr & 0xFFFFFFFF;
+       SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
+       u32 tmp;
 
-       pSge->FlagsLength = cpu_to_le32(flagslength);
+       tmp = dma_addr & 0xFFFFFFFF;
        pSge->Address.Low = cpu_to_le32(tmp);
        tmp = (u32) ((u64)dma_addr >> 32);
+       pSge->FlagsLength = cpu_to_le32(flagslength);
        pSge->Address.High = cpu_to_le32(tmp);
 }
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
 /**
- *     mpt_add_sge_64bit_1078 - Place a simple 64 bit SGE at address addr
+ *     mpt_add_sge_64bit_1078 - Place a simple 64 bit SGE at address pAddr
  *     (1078 workaround).
- *     @addr: virtual address for SGE
+ *     @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.
+ **/
 static void
-mpt_add_sge_64bit_1078(char *addr, u32 flagslength, dma_addr_t dma_addr)
+mpt_add_sge_64bit_1078(char *pAddr, u32 flagslength, dma_addr_t dma_addr)
 {
-       SGESimple64_t *pSge = (SGESimple64_t *) addr;
+       SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
        u32 tmp;
 
        tmp = dma_addr & 0xFFFFFFFF;
@@ -1011,11 +1075,11 @@ mpt_add_sge_64bit_1078(char *addr, u32 flagslength, dma_addr_t dma_addr)
  *     request which are greater than 1 byte in size.
  *
  *     Returns 0 for success, non-zero for failure.
- */
+ **/
 int
 mpt_send_handshake_request(u8 cb_idx, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag)
 {
-       int     r = 0;
+       int      r = 0;
        u8      *req_as_bytes;
        int      ii;
 
@@ -1030,7 +1094,7 @@ mpt_send_handshake_request(u8 cb_idx, MPT_ADAPTER *ioc, int reqBytes, u32 *req,
         * is in proper (pre-alloc'd) request buffer range...
         */
        ii = MFPTR_2_MPT_INDEX(ioc,(MPT_FRAME_HDR*)req);
-       if (reqBytes >= 12 && ii >= 0 && ii < ioc->req_depth) {
+       if (ii >= 0 && ii < ioc->req_depth) {
                MPT_FRAME_HDR *mf = (MPT_FRAME_HDR*)req;
                mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(ii);
                mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx;
@@ -1088,7 +1152,6 @@ mpt_send_handshake_request(u8 cb_idx, MPT_ADAPTER *ioc, int reqBytes, u32 *req,
        return r;
 }
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  * mpt_host_page_access_control - control the IOC's Host Page Buffer access
  * @ioc: Pointer to MPT adapter structure
@@ -1105,8 +1168,7 @@ mpt_send_handshake_request(u8 cb_idx, MPT_ADAPTER *ioc, int reqBytes, u32 *req,
  * 3h Free Buffer { MPI_DB_HPBAC_FREE_BUFFER }
  *
  * Returns 0 for success, non-zero for failure.
- */
-
+ **/
 static int
 mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag)
 {
@@ -1131,7 +1193,6 @@ mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int slee
                return 0;
 }
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *     mpt_host_page_alloc - allocate system memory for the fw
  *     @ioc: Pointer to pointer to IOC adapter
@@ -1139,7 +1200,7 @@ mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int slee
  *
  *     If we already allocated memory in past, then resend the same pointer.
  *     Returns 0 for success, non-zero for failure.
- */
+ **/
 static int
 mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init)
 {
@@ -1163,7 +1224,7 @@ mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init)
                            host_page_buffer_sz,
                            &ioc->HostPageBuffer_dma)) != NULL) {
 
-                               dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                               dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
                                    "host_page_buffer @ %p, dma @ %x, sz=%d bytes\n",
                                    ioc->name, ioc->HostPageBuffer,
                                    (u32)ioc->HostPageBuffer_dma,
@@ -1201,7 +1262,6 @@ mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init)
 return 0;
 }
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *     mpt_verify_adapter - Given IOC identifier, set pointer to its adapter structure.
  *     @iocid: IOC unique identifier (integer)
@@ -1212,7 +1272,7 @@ return 0;
  *
  *     Returns iocid and sets iocpp if iocid is found.
  *     Returns -1 if iocid is not found.
- */
+ **/
 int
 mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp)
 {
@@ -1471,60 +1531,44 @@ mpt_get_product_name(u16 vendor, u16 device, u8 revision, char *prod_name)
                sprintf(prod_name, "%s", product_str);
 }
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
- *     mpt_attach - Install a PCI intelligent MPT adapter.
- *     @pdev: Pointer to pci_dev structure
- *     @id: PCI device ID information
- *
- *     This routine performs all the steps necessary to bring the IOC of
- *     a MPT adapter to a OPERATIONAL state.  This includes registering
- *     memory regions, registering the interrupt, and allocating request
- *     and reply memory pools.
- *
- *     This routine also pre-fetches the LAN MAC address of a Fibre Channel
- *     MPT adapter.
- *
- *     Returns 0 for success, non-zero for failure.
+ *     mpt_mapresources - map in memory mapped io
+ *     @ioc: Pointer to pointer to IOC adapter
  *
- *     TODO: Add support for polled controllers
- */
-int
-mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
+ **/
+static int
+mpt_mapresources(MPT_ADAPTER *ioc)
 {
-       MPT_ADAPTER     *ioc;
        u8              __iomem *mem;
-       u8              __iomem *pmem;
+       int              ii;
        unsigned long    mem_phys;
        unsigned long    port;
        u32              msize;
        u32              psize;
-       int              ii;
-       u8               cb_idx;
        int              r = -ENODEV;
-       u8               revision;
-       u8               pcixcmd;
-       static int       mpt_ids = 0;
-#ifdef CONFIG_PROC_FS
-       struct proc_dir_entry *dent, *ent;
-#endif
+       struct pci_dev *pdev;
 
-       if (mpt_debug_level)
-               printk(KERN_INFO MYNAM ": mpt_debug_level=%xh\n", mpt_debug_level);
+       pdev = ioc->pcidev;
 
-       if (pci_enable_device(pdev))
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21))
+       if (pci_enable_device(pdev)) {
+               printk(MYIOC_s_WARN_FMT "pci_enable_device: failed\n",
+                   ioc->name);
                return r;
-
-       ioc = kzalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC);
-       if (ioc == NULL) {
-               printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n");
-               return -ENOMEM;
        }
-       ioc->debug_level = mpt_debug_level;
-       ioc->id = mpt_ids++;
-       sprintf(ioc->name, "ioc%d", ioc->id);
-
-       dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": mpt_adapter_install\n", ioc->name));
+#else
+       ioc->bars = pci_select_bars(pdev, IORESOURCE_MEM);
+       if (pci_enable_device_bars(pdev, ioc->bars)) {
+               printk(MYIOC_s_ERR_FMT "pci_enable_device_bars() with MEM "
+                   "failed\n",ioc->name);
+               return r;
+       }
+       if (pci_request_selected_regions(pdev, ioc->bars, "mpt")) {
+               printk(MYIOC_s_ERR_FMT "pci_request_selected_regions() with "
+                   "MEM failed\n",ioc->name);
+               return r;
+       }
+#endif
 
        if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)
            && !pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK)) {
@@ -1541,29 +1585,130 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
        } else {
                printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n",
                    ioc->name, pci_name(pdev));
-               kfree(ioc);
                return r;
        }
 
-       ioc->alloc_total = sizeof(MPT_ADAPTER);
-       ioc->req_sz = MPT_DEFAULT_FRAME_SIZE;           /* avoid div by zero! */
-       ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
+       mem_phys = msize = 0;
+       port = psize = 0;
+       for (ii=0; ii < DEVICE_COUNT_RESOURCE; ii++) {
+               if (pci_resource_flags(pdev, ii) & PCI_BASE_ADDRESS_SPACE_IO) {
+                       if (psize)
+                               continue;
+                       /* Get I/O space! */
+                       port = pci_resource_start(pdev, ii);
+                       psize = pci_resource_len(pdev,ii);
+               } else {
+                       if (msize)
+                               continue;
+                       /* Get memmap */
+                       mem_phys = pci_resource_start(pdev, ii);
+                       msize = pci_resource_len(pdev,ii);
+               }
+       }
+       ioc->mem_size = msize;
 
-       /*
-        * Setting up proper handlers for scatter gather handling
-        */
-       if (sizeof(dma_addr_t) == sizeof(u64)) {
-               if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078)
-                       ioc->add_sge = &mpt_add_sge_64bit_1078;
-               else
-                       ioc->add_sge = &mpt_add_sge_64bit;
-       } else
+       mem = NULL;
+       /* Get logical ptr for PciMem0 space */
+       /*mem = ioremap(mem_phys, msize);*/
+       mem = ioremap(mem_phys, msize);
+       if (mem == NULL) {
+               printk(MYIOC_s_ERR_FMT ": ERROR - Unable to map adapter memory!\n", ioc->name);
+               return -EINVAL;
+       }
+       ioc->memmap = mem;
+       dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "mem = %p, mem_phys = %lx\n",
+           ioc->name, mem, mem_phys));
+
+       ioc->mem_phys = mem_phys;
+       ioc->chip = (SYSIF_REGS __iomem *)mem;
+
+       /* Save Port IO values in case we need to do downloadboot */
+       {
+               u8 *pmem = (u8*)port;
+               ioc->pio_mem_phys = port;
+               ioc->pio_chip = (SYSIF_REGS __iomem *)pmem;
+       }
+       
+       return 0;
+}
+
+/**
+ *     mpt_attach - Install a PCI intelligent MPT adapter.
+ *     @pdev: Pointer to pci_dev structure
+ *     @id: PCI device ID information
+ *
+ *     This routine performs all the steps necessary to bring the IOC of
+ *     a MPT adapter to a OPERATIONAL state.  This includes registering
+ *     memory regions, registering the interrupt, and allocating request
+ *     and reply memory pools.
+ *
+ *     This routine also pre-fetches the LAN MAC address of a Fibre Channel
+ *     MPT adapter.
+ *
+ *     Returns 0 for success, non-zero for failure.
+ *
+ *     TODO: Add support for polled controllers
+ **/
+int
+mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+       MPT_ADAPTER     *ioc;
+       u8               cb_idx;
+       int              r = -ENODEV;
+       u8               revision;
+       u8               pcixcmd;
+       static int       mpt_ids = 0;
+#ifdef CONFIG_PROC_FS
+       struct proc_dir_entry *dent, *ent;
+#endif
+
+       ioc = kzalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC);
+       if (ioc == NULL) {
+               printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n");
+               return -ENOMEM;
+       }
+
+       ioc->id = mpt_ids++;
+       sprintf(ioc->name, "ioc%d", ioc->id);
+       dinitprintk(ioc, printk(KERN_WARNING MYNAM ": mpt_adapter_install\n"));
+
+       /*
+        * set initial debug level
+        * (refer to mptdebug.h)
+        */
+       ioc->debug_level = mpt_debug_level;
+       if (mpt_debug_level)
+               printk("mpt_debug_level=%xh\n", mpt_debug_level);
+
+       /*
+        * Setting up proper handlers for scatter gather handling
+        */
+       if (sizeof(dma_addr_t) == sizeof(u64)) {
+               if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078)
+                       ioc->add_sge = &mpt_add_sge_64bit_1078;
+               else
+                       ioc->add_sge = &mpt_add_sge_64bit;
+       } else
                ioc->add_sge = &mpt_add_sge;
 
+
        ioc->pcidev = pdev;
-       ioc->diagPending = 0;
-       spin_lock_init(&ioc->diagLock);
-       spin_lock_init(&ioc->initializing_hba_lock);
+       if (mpt_mapresources(ioc)) {
+               kfree(ioc);
+               return r;
+       }
+
+       ioc->alloc_total = sizeof(MPT_ADAPTER);
+       ioc->req_sz = MPT_DEFAULT_FRAME_SIZE;           /* avoid div by zero! */
+       ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
+
+       spin_lock_init(&ioc->taskmgmt_lock);
+       mutex_init(&ioc->internal_cmds.mutex);
+       init_completion(&ioc->internal_cmds.done);
+       mutex_init(&ioc->mptbase_cmds.mutex);
+       init_completion(&ioc->mptbase_cmds.done);
+       mutex_init(&ioc->taskmgmt_cmds.mutex);
+       init_completion(&ioc->taskmgmt_cmds.done);
 
        /* Initialize the event logging.
         */
@@ -1576,16 +1721,13 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
        ioc->mfcnt = 0;
 #endif
 
+       ioc->sh = NULL;
        ioc->cached_fw = NULL;
 
        /* Initilize SCSI Config Data structure
         */
        memset(&ioc->spi_data, 0, sizeof(SpiCfgData));
 
-       /* Initialize the running configQ head.
-        */
-       INIT_LIST_HEAD(&ioc->configQ);
-
        /* Initialize the fc rport list head.
         */
        INIT_LIST_HEAD(&ioc->fc_rports);
@@ -1593,47 +1735,26 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
        /* Find lookup slot. */
        INIT_LIST_HEAD(&ioc->list);
 
-       mem_phys = msize = 0;
-       port = psize = 0;
-       for (ii=0; ii < DEVICE_COUNT_RESOURCE; ii++) {
-               if (pci_resource_flags(pdev, ii) & PCI_BASE_ADDRESS_SPACE_IO) {
-                       if (psize)
-                               continue;
-                       /* Get I/O space! */
-                       port = pci_resource_start(pdev, ii);
-                       psize = pci_resource_len(pdev,ii);
-               } else {
-                       if (msize)
-                               continue;
-                       /* Get memmap */
-                       mem_phys = pci_resource_start(pdev, ii);
-                       msize = pci_resource_len(pdev,ii);
-               }
-       }
-       ioc->mem_size = msize;
+       /* Initialize work */
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19))
+       INIT_DELAYED_WORK(&ioc->fault_reset_work, mpt_fault_reset_work);
+#else
+       INIT_WORK(&ioc->fault_reset_work, mpt_fault_reset_work, (void *)ioc);
+#endif
 
-       mem = NULL;
-       /* Get logical ptr for PciMem0 space */
-       /*mem = ioremap(mem_phys, msize);*/
-       mem = ioremap(mem_phys, msize);
-       if (mem == NULL) {
-               printk(MYIOC_s_ERR_FMT "Unable to map adapter memory!\n", ioc->name);
+       /* Initialize workqueue */
+       snprintf(ioc->reset_work_q_name, KOBJ_NAME_LEN, "mpt_poll_%d", ioc->id);
+       ioc->reset_work_q =
+               create_singlethread_workqueue(ioc->reset_work_q_name);
+       if (!ioc->reset_work_q) {
+               printk(MYIOC_s_ERR_FMT "Insufficient memory to add adapter!\n",
+                   ioc->name);
                kfree(ioc);
-               return -EINVAL;
+               return -ENOMEM;
        }
-       ioc->memmap = mem;
-       dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "mem = %p, mem_phys = %lx\n", ioc->name, mem, mem_phys));
-
-       dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "facts @ %p, pfacts[0] @ %p\n",
-           ioc->name, &ioc->facts, &ioc->pfacts[0]));
-
-       ioc->mem_phys = mem_phys;
-       ioc->chip = (SYSIF_REGS __iomem *)mem;
 
-       /* Save Port IO values in case we need to do downloadboot */
-       ioc->pio_mem_phys = port;
-       pmem = (u8 __iomem *)port;
-       ioc->pio_chip = (SYSIF_REGS __iomem *)pmem;
+       dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "facts @ %p, pfacts[0] @ %p\n",
+               ioc->name, &ioc->facts, &ioc->pfacts[0]));
 
        pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
        mpt_get_product_name(pdev->vendor, pdev->device, revision, ioc->prod_name);
@@ -1678,6 +1799,7 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
                ioc->bus_type = FC;
                break;
 
+
        case MPI_MANUFACTPAGE_DEVID_53C1030:
                /* 1030 Chip Fix. Disable Split transactions
                 * for PCIX. Set MOST bits to zero if Rev < C0( = 8).
@@ -1695,13 +1817,25 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
        case MPI_MANUFACTPAGE_DEVID_SAS1064:
        case MPI_MANUFACTPAGE_DEVID_SAS1068:
                ioc->errata_flag_1064 = 1;
+               ioc->bus_type = SAS;
+               break;
 
        case MPI_MANUFACTPAGE_DEVID_SAS1064E:
        case MPI_MANUFACTPAGE_DEVID_SAS1068E:
        case MPI_MANUFACTPAGE_DEVID_SAS1078:
                ioc->bus_type = SAS;
+               break;
        }
 
+       if (ioc->bus_type == SAS)
+#if defined(SUSE_KERNEL_BASE)
+               ioc->msi_enable = mpt_msi_enable;
+#else
+               ioc->msi_enable = 1;
+#endif
+       else
+               ioc->msi_enable = mpt_msi_enable;
+
        if (ioc->errata_flag_1064)
                pci_disable_io_access(pdev);
 
@@ -1721,13 +1855,14 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
 
        if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
            CAN_SLEEP)) != 0){
-               printk(MYIOC_s_ERR_FMT "didn't initialize properly! (%d)\n",
-                   ioc->name, r);
+               printk(MYIOC_s_ERR_FMT
+                 "didn't initialize properly! (%d)\n",
+                 ioc->name, r);
 
                list_del(&ioc->list);
                if (ioc->alt_ioc)
                        ioc->alt_ioc->alt_ioc = NULL;
-               iounmap(mem);
+               iounmap(ioc->memmap);
                kfree(ioc);
                pci_set_drvdata(pdev, NULL);
                return r;
@@ -1760,21 +1895,34 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
        }
 #endif
 
+       if (!ioc->alt_ioc)
+               queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work,
+                       msecs_to_jiffies(MPT_POLLING_INTERVAL));
        return 0;
 }
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *     mpt_detach - Remove a PCI intelligent MPT adapter.
  *     @pdev: Pointer to pci_dev structure
- */
-
+ **/
 void
 mpt_detach(struct pci_dev *pdev)
 {
        MPT_ADAPTER     *ioc = pci_get_drvdata(pdev);
        char pname[32];
        u8 cb_idx;
+       unsigned long    flags;
+       struct workqueue_struct *wq;
+
+       /*
+        * Stop polling ioc for fault condition
+        */
+       spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
+       wq = ioc->reset_work_q;
+       ioc->reset_work_q = NULL;
+       spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
+       cancel_delayed_work(&ioc->fault_reset_work);
+       destroy_workqueue(wq);
 
        sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name);
        remove_proc_entry(pname, NULL);
@@ -1791,45 +1939,28 @@ mpt_detach(struct pci_dev *pdev)
                }
        }
 
-       /* Disable interrupts! */
-       CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
-
-       ioc->active = 0;
-       synchronize_irq(pdev->irq);
-
-       /* Clear any lingering interrupt */
-       CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
-
-       CHIPREG_READ32(&ioc->chip->IntStatus);
-
        mpt_adapter_dispose(ioc);
-
-       pci_set_drvdata(pdev, NULL);
 }
 
 /**************************************************************************
  * Power Management
  */
 #ifdef CONFIG_PM
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *     mpt_suspend - Fusion MPT base driver suspend routine.
  *     @pdev: Pointer to pci_dev structure
  *     @state: new state to enter
- */
+ **/
 int
 mpt_suspend(struct pci_dev *pdev, pm_message_t state)
 {
        u32 device_state;
        MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
 
-       device_state=pci_choose_state(pdev, state);
-
-       printk(MYIOC_s_INFO_FMT
-       "pci-suspend: pdev=0x%p, slot=%s, Entering operating state [D%d]\n",
-               ioc->name, pdev, pci_name(pdev), device_state);
-
-       pci_save_state(pdev);
+       device_state = pci_choose_state(pdev, state);
+       printk(MYIOC_s_INFO_FMT "pci-suspend: pdev=0x%p, slot=%s, Entering "
+           "operating state [D%d]\n", ioc->name, pdev, pci_name(pdev),
+           device_state);
 
        /* put ioc into READY_STATE */
        if(SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, CAN_SLEEP)) {
@@ -1840,21 +1971,26 @@ mpt_suspend(struct pci_dev *pdev, pm_message_t state)
        /* disable interrupts */
        CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
        ioc->active = 0;
-
        /* Clear any lingering interrupt */
        CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
 
+       free_irq(ioc->pci_irq, ioc);
+       if (ioc->msi_enable)
+               pci_disable_msi(ioc->pcidev);
+       ioc->pci_irq = -1;
+       pci_save_state(pdev);
        pci_disable_device(pdev);
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21))
+       pci_release_selected_regions(ioc->pcidev, ioc->bars);
+#endif
        pci_set_power_state(pdev, device_state);
-
        return 0;
 }
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *     mpt_resume - Fusion MPT base driver resume routine.
  *     @pdev: Pointer to pci_dev structure
- */
+ **/
 int
 mpt_resume(struct pci_dev *pdev)
 {
@@ -1863,37 +1999,48 @@ mpt_resume(struct pci_dev *pdev)
        int recovery_state;
        int err;
 
-       printk(MYIOC_s_INFO_FMT
-       "pci-resume: pdev=0x%p, slot=%s, Previous operating state [D%d]\n",
-               ioc->name, pdev, pci_name(pdev), device_state);
+       printk(MYIOC_s_INFO_FMT "pci-resume: pdev=0x%p, slot=%s, Previous "
+           "operating state [D%d]\n", ioc->name, pdev, pci_name(pdev),
+           device_state);
 
-       pci_set_power_state(pdev, 0);
+       pci_set_power_state(pdev, PCI_D0);
+       pci_enable_wake(pdev, PCI_D0, 0);
        pci_restore_state(pdev);
-       err = pci_enable_device(pdev);
+       ioc->pcidev = pdev;
+       err = mpt_mapresources(ioc);
        if (err)
                return err;
 
-       /* enable interrupts */
-       CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
-       ioc->active = 1;
+       printk(MYIOC_s_INFO_FMT "pci-resume: ioc-state=0x%x,doorbell=0x%x\n",
+           ioc->name, (mpt_GetIocState(ioc, 1) >> MPI_IOC_STATE_SHIFT),
+           CHIPREG_READ32(&ioc->chip->Doorbell));
 
-       printk(MYIOC_s_INFO_FMT
-               "pci-resume: ioc-state=0x%x,doorbell=0x%x\n",
-               ioc->name,
-               (mpt_GetIocState(ioc, 1) >> MPI_IOC_STATE_SHIFT),
-               CHIPREG_READ32(&ioc->chip->Doorbell));
+       /*
+        * Errata workaround for SAS pci express:
+        * Upon returning to the D0 state, the contents of the doorbell will be
+        * stale data, and this will incorrectly signal to the host driver that
+        * the firmware is ready to process mpt commands.   The workaround is
+        * to issue a diagnostic reset.
+        */
+       if (ioc->bus_type == SAS && (pdev->device ==
+           MPI_MANUFACTPAGE_DEVID_SAS1068E || pdev->device ==
+           MPI_MANUFACTPAGE_DEVID_SAS1064E)) {
+               if (KickStart(ioc, 1, CAN_SLEEP) < 0) {
+                       printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover\n",
+                           ioc->name);
+                       goto out;
+               }
+       }
 
        /* bring ioc to operational state */
-       if ((recovery_state = mpt_do_ioc_recovery(ioc,
-           MPT_HOSTEVENT_IOC_RECOVER, CAN_SLEEP)) != 0) {
-               printk(MYIOC_s_INFO_FMT
-                       "pci-resume: Cannot recover, error:[%x]\n",
-                       ioc->name, recovery_state);
-       } else {
+       printk(MYIOC_s_INFO_FMT "Sending mpt_do_ioc_recovery\n", ioc->name);
+       if ((recovery_state = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP, CAN_SLEEP)) != 0)
+               printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover, "
+                   "error:[%x]\n", ioc->name, recovery_state);
+       else
                printk(MYIOC_s_INFO_FMT
-                       "pci-resume: success\n", ioc->name);
-       }
-
+                   "pci-resume: success\n", ioc->name);
+ out:
        return 0;
 }
 #endif
@@ -1913,7 +2060,6 @@ mpt_signal_reset(u8 index, MPT_ADAPTER *ioc, int reset_phase)
        return (MptResetHandlers[index])(ioc, reset_phase);
 }
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *     mpt_do_ioc_recovery - Initialize or recover MPT adapter.
  *     @ioc: Pointer to MPT adapter structure
@@ -1932,7 +2078,7 @@ mpt_signal_reset(u8 index, MPT_ADAPTER *ioc, int reset_phase)
  *             -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, int sleepFlag)
 {
@@ -1941,14 +2087,12 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
        int      hard;
        int      rc=0;
        int      ii;
-       u8       cb_idx;
-       int      handlers;
        int      ret = 0;
        int      reset_alt_ioc_active = 0;
        int      irq_allocated = 0;
        u8      *a;
 
-       printk(MYIOC_s_INFO_FMT "Initiating %s\n", ioc->name,
+       printk(MYIOC_s_DEBUG_FMT "Initiating %s\n", ioc->name,
            reason == MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery");
 
        /* Disable reply interrupts (also blocks FreeQ) */
@@ -1956,7 +2100,7 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
        ioc->active = 0;
 
        if (ioc->alt_ioc) {
-               if (ioc->alt_ioc->active)
+               if (ioc->alt_ioc->active || reason == MPT_HOSTEVENT_IOC_RECOVER)
                        reset_alt_ioc_active = 1;
 
                /* Disable alt-IOC's reply interrupts (and FreeQ) for a bit ... */
@@ -1975,16 +2119,17 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
 
                        if (reset_alt_ioc_active && ioc->alt_ioc) {
                                /* (re)Enable alt-IOC! (reply interrupt, FreeQ) */
-                               dprintk(ioc, printk(MYIOC_s_INFO_FMT
-                                   "alt_ioc reply irq re-enabled\n", ioc->alt_ioc->name));
+                               dprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": alt-ioc reply irq re-enabled\n",
+                                   ioc->alt_ioc->name));
                                CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
                                ioc->alt_ioc->active = 1;
                        }
 
                } else {
-                       printk(MYIOC_s_WARN_FMT "NOT READY!\n", ioc->name);
+                       printk(MYIOC_s_WARN_FMT "NOT READY WARNING!\n", ioc->name);
                }
-               return -1;
+               ret = -1;
+               goto out;
        }
 
        /* hard_reset_done = 0 if a soft reset was performed
@@ -1994,7 +2139,8 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
                if ((rc = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0)
                        alt_ioc_ready = 1;
                else
-                       printk(MYIOC_s_WARN_FMT "alt_ioc not ready!\n", ioc->alt_ioc->name);
+                       printk(MYIOC_s_WARN_FMT
+                           ": alt-ioc Not ready WARNING!\n", ioc->alt_ioc->name);
        }
 
        for (ii=0; ii<5; ii++) {
@@ -2030,6 +2176,20 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
                }
        }
 
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21))
+       if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP) &&
+           (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)) {
+               pci_release_selected_regions(ioc->pcidev, ioc->bars);
+               ioc->bars = pci_select_bars(ioc->pcidev, IORESOURCE_MEM |
+                   IORESOURCE_IO);
+               if (pci_enable_device_bars(ioc->pcidev, ioc->bars))
+                       return -5;
+               if (pci_request_selected_regions(ioc->pcidev, ioc->bars,
+                       "mpt"))
+                       return -5;
+       }
+#endif
+
        /*
         * Device is reset now. It must have de-asserted the interrupt line
         * (if it was asserted) and it should be safe to register for the
@@ -2038,24 +2198,35 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
        if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
                ioc->pci_irq = -1;
                if (ioc->pcidev->irq) {
-                       if (mpt_msi_enable && !pci_enable_msi(ioc->pcidev))
+                       if (ioc->msi_enable && !pci_enable_msi(ioc->pcidev))
                                printk(MYIOC_s_INFO_FMT "PCI-MSI enabled\n",
-                                   ioc->name);
+                                       ioc->name);
+                       else
+                               ioc->msi_enable = 0;
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18))
                        rc = request_irq(ioc->pcidev->irq, mpt_interrupt,
                            IRQF_SHARED, ioc->name, ioc);
+#else
+                       rc = request_irq(ioc->pcidev->irq, mpt_interrupt,
+                           SA_SHIRQ, ioc->name, ioc);
+#endif
                        if (rc < 0) {
                                printk(MYIOC_s_ERR_FMT "Unable to allocate "
-                                   "interrupt %d!\n", ioc->name, ioc->pcidev->irq);
-                               if (mpt_msi_enable)
+                                       "interrupt %d!\n", ioc->name,
+                                       ioc->pcidev->irq);
+                               if (ioc->msi_enable)
                                        pci_disable_msi(ioc->pcidev);
-                               return -EBUSY;
+                               ret = -EBUSY;
+                               goto out;
                        }
                        irq_allocated = 1;
                        ioc->pci_irq = ioc->pcidev->irq;
                        pci_set_master(ioc->pcidev);            /* ?? */
                        pci_set_drvdata(ioc->pcidev, ioc);
-                       dprintk(ioc, printk(MYIOC_s_INFO_FMT "installed at interrupt "
-                           "%d\n", ioc->name, ioc->pcidev->irq));
+                       dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
+                           "installed at interrupt %d\n", ioc->name,
+                           ioc->pcidev->irq));
                }
        }
 
@@ -2064,18 +2235,22 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
         * init as upper addresses are needed for init.
         * If fails, continue with alt-ioc processing
         */
+       dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "PrimeIocFifos\n",
+           ioc->name));
        if ((ret == 0) && ((rc = PrimeIocFifos(ioc)) != 0))
                ret = -3;
 
        /* May need to check/upload firmware & data here!
         * If fails, continue with alt-ioc processing
         */
+       dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "SendIocInit\n",
+           ioc->name));
        if ((ret == 0) && ((rc = SendIocInit(ioc, sleepFlag)) != 0))
                ret = -4;
 // NEW!
        if (alt_ioc_ready && ((rc = PrimeIocFifos(ioc->alt_ioc)) != 0)) {
-               printk(MYIOC_s_WARN_FMT ": alt_ioc (%d) FIFO mgmt alloc!\n",
-                   ioc->alt_ioc->name, rc);
+               printk(MYIOC_s_WARN_FMT ": alt-ioc (%d) FIFO mgmt alloc WARNING!\n",
+                               ioc->alt_ioc->name, rc);
                alt_ioc_ready = 0;
                reset_alt_ioc_active = 0;
        }
@@ -2084,15 +2259,16 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
                if ((rc = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) {
                        alt_ioc_ready = 0;
                        reset_alt_ioc_active = 0;
-                       printk(MYIOC_s_WARN_FMT "alt_ioc (%d) init failure!\n",
-                           ioc->alt_ioc->name, rc);
+                       printk(MYIOC_s_WARN_FMT
+                               ": alt-ioc: (%d) init failure WARNING!\n",
+                                       ioc->alt_ioc->name, rc);
                }
        }
 
        if (reason == MPT_HOSTEVENT_IOC_BRINGUP){
                if (ioc->upload_fw) {
                        ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
-                           "firmware upload required!\n", ioc->name));
+                               "firmware upload required!\n", ioc->name));
 
                        /* Controller is not operational, cannot do upload
                         */
@@ -2110,7 +2286,7 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
                                                ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
                                                    "mpt_upload:  alt_%s has cached_fw=%p \n",
                                                    ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw));
-                                               ioc->alt_ioc->cached_fw = NULL;
+                                               ioc->cached_fw = NULL;
                                        }
                                } else {
                                        printk(MYIOC_s_WARN_FMT
@@ -2121,28 +2297,33 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
                }
        }
 
+       /*  Enable MPT base driver management of EventNotification
+        *  and EventAck handling.
+        */
+       if ((ret == 0) && (!ioc->facts.EventState)) {
+               dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "SendEventNotification\n",
+                   ioc->name));
+               ret = SendEventNotification(ioc, 1, sleepFlag); /* 1=Enable */
+       }
+
+       if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState)
+               rc = SendEventNotification(ioc->alt_ioc, 1, sleepFlag);
+
        if (ret == 0) {
                /* Enable! (reply interrupt) */
                CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
                ioc->active = 1;
        }
-
-       if (reset_alt_ioc_active && ioc->alt_ioc) {
-               /* (re)Enable alt-IOC! (reply interrupt) */
-               dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "alt_ioc reply irq re-enabled\n",
-                   ioc->alt_ioc->name));
-               CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
-               ioc->alt_ioc->active = 1;
+       if (rc == 0) {  /* alt ioc */
+               if (reset_alt_ioc_active && ioc->alt_ioc) {
+                       /* (re)Enable alt-IOC! (reply interrupt) */
+                       dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "alt-ioc reply irq re-enabled\n",
+                               ioc->alt_ioc->name));
+                       CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
+                       ioc->alt_ioc->active = 1;
+               }
        }
 
-       /*  Enable MPT base driver management of EventNotification
-        *  and EventAck handling.
-        */
-       if ((ret == 0) && (!ioc->facts.EventState))
-               (void) SendEventNotification(ioc, 1);   /* 1=Enable EventNotification */
-
-       if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState)
-               (void) SendEventNotification(ioc->alt_ioc, 1);  /* 1=Enable EventNotification */
 
        /*      Add additional "reason" check before call to GetLanConfigPages
         *      (combined with GetIoUnitPage2 call).  This prevents a somewhat
@@ -2158,8 +2339,9 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
                init_MUTEX(&ioc->raid_data.inactive_list_mutex);
                INIT_LIST_HEAD(&ioc->raid_data.inactive_list);
 
-               if (ioc->bus_type == SAS) {
+               switch (ioc->bus_type) {
 
+               case SAS:
                        /* clear persistency table */
                        if(ioc->facts.IOCExceptions &
                            MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL) {
@@ -2173,8 +2355,15 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
                         */
                        mpt_findImVolumes(ioc);
 
-               } else if (ioc->bus_type == FC) {
-                       if ((ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) &&
+                       /* Check, and possibly reset, the coalescing value
+                        */
+                       mpt_read_ioc_pg_1(ioc);
+
+                       break;
+
+               case FC:
+                       if ((ioc->pfacts[0].ProtocolFlags &
+                               MPI_PORTFACTS_PROTOCOL_LAN) &&
                            (ioc->lan_cnfg_page0.Header.PageLength == 0)) {
                                /*
                                 *  Pre-fetch the ports LAN MAC address!
@@ -2183,11 +2372,14 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
                                (void) GetLanConfigPages(ioc);
                                a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
                                dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
-                                   "LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
-                                   ioc->name, a[5], a[4], a[3], a[2], a[1], a[0]));
-
+                                       "LanAddr = %02X:%02X:%02X"
+                                       ":%02X:%02X:%02X\n",
+                                       ioc->name, a[5], a[4],
+                                       a[3], a[2], a[1], a[0]));
                        }
-               } else {
+                       break;
+
+               case SPI:
                        /* Get NVRAM and adapter maximums from SPP 0 and 2
                         */
                        mpt_GetScsiPortSettings(ioc, 0);
@@ -2206,50 +2398,24 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
                        mpt_read_ioc_pg_1(ioc);
 
                        mpt_read_ioc_pg_4(ioc);
+
+                       break;
                }
 
                GetIoUnitPage2(ioc);
                mpt_get_manufacturing_pg_0(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) {
-               rc = handlers = 0;
-               for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
-                       if ((ret == 0) && MptResetHandlers[cb_idx]) {
-                               dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
-                                   "Calling IOC post_reset handler #%d\n",
-                                   ioc->name, cb_idx));
-                               rc += mpt_signal_reset(cb_idx, ioc, MPT_IOC_POST_RESET);
-                               handlers++;
-                       }
-
-                       if (alt_ioc_ready && MptResetHandlers[cb_idx]) {
-                               drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
-                                   "Calling IOC post_reset handler #%d\n",
-                                   ioc->alt_ioc->name, cb_idx));
-                               rc += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_POST_RESET);
-                               handlers++;
-                       }
-               }
-               /* FIXME?  Examine results here? */
-       }
-
  out:
+
        if ((ret != 0) && irq_allocated) {
                free_irq(ioc->pci_irq, ioc);
-               if (mpt_msi_enable)
+               if (ioc->msi_enable)
                        pci_disable_msi(ioc->pcidev);
        }
        return ret;
 }
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *     mpt_detect_bound_ports - Search for matching PCI bus/dev_function
  *     @ioc: Pointer to MPT adapter structure
@@ -2261,7 +2427,7 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
  *
  *     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)
 {
@@ -2272,8 +2438,8 @@ mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
 
        dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PCI device %s devfn=%x/%x,"
            " searching for devfn match on %x or %x\n",
-           ioc->name, pci_name(pdev), pdev->bus->number,
-           pdev->devfn, func-1, func+1));
+               ioc->name, pci_name(pdev), pdev->bus->number,
+               pdev->devfn, func-1, func+1));
 
        peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func-1));
        if (!peer) {
@@ -2287,16 +2453,16 @@ mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
                if (_pcidev == peer) {
                        /* Paranoia checks */
                        if (ioc->alt_ioc != NULL) {
-                               printk(MYIOC_s_WARN_FMT "Oops, already bound to %s!\n",
-                                       ioc->name, ioc->alt_ioc->name);
+                               printk(MYIOC_s_WARN_FMT "Oops, already bound (%s <==> %s)!\n",
+                                       ioc->name, ioc->name, ioc->alt_ioc->name);
                                break;
                        } else if (ioc_srch->alt_ioc != NULL) {
-                               printk(MYIOC_s_WARN_FMT "Oops, already bound to %s!\n",
-                                       ioc_srch->name, ioc_srch->alt_ioc->name);
+                               printk(MYIOC_s_WARN_FMT "Oops, already bound (%s <==> %s)!\n",
+                                       ioc_srch->name, ioc_srch->name, ioc_srch->alt_ioc->name);
                                break;
                        }
-                       dprintk(ioc, printk(MYIOC_s_INFO_FMT "FOUND! binding to %s\n",
-                               ioc->name, ioc_srch->name));
+                       dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FOUND! binding %s <==> %s\n",
+                               ioc->name, ioc->name, ioc_srch->name));
                        ioc_srch->alt_ioc = ioc;
                        ioc->alt_ioc = ioc_srch;
                }
@@ -2304,11 +2470,10 @@ mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
        pci_dev_put(peer);
 }
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *     mpt_adapter_disable - Disable misbehaving MPT adapter.
  *     @ioc: Pointer to MPT adapter structure
- */
+ **/
 static void
 mpt_adapter_disable(MPT_ADAPTER *ioc)
 {
@@ -2316,24 +2481,43 @@ mpt_adapter_disable(MPT_ADAPTER *ioc)
        int ret;
 
        if (ioc->cached_fw != NULL) {
-               ddlprintk(ioc, printk(MYIOC_s_INFO_FMT
-                   "mpt_adapter_disable: Pushing FW onto adapter\n", ioc->name));
-               if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)ioc->cached_fw, NO_SLEEP)) < 0) {
-                       printk(MYIOC_s_WARN_FMT "firmware downloadboot failure (%d)!\n",
-                           ioc->name, ret);
+               ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_adapter_disable: "
+                       "Pushing FW onto adapter\n", ioc->name));
+               if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)
+                   ioc->cached_fw, CAN_SLEEP)) < 0) {
+                       printk(MYIOC_s_WARN_FMT
+                           ": firmware downloadboot failure (%d)!\n", ioc->name, ret);
                }
        }
 
+       /*
+        * Put the controller into ready state (if its not already)
+        */
+       if (mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_READY) {
+               if(!SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET,
+                   CAN_SLEEP)) {
+                       if (mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_READY)
+                               printk(MYIOC_s_ERR_FMT "%s:  IOC msg unit "
+                                   "reset failed to put ioc in ready state!\n",
+                                   ioc->name, __FUNCTION__);
+               } else
+                       printk(MYIOC_s_ERR_FMT "%s:  IOC msg unit reset "
+                           "failed!\n", ioc->name, __FUNCTION__);
+       }
+
        /* Disable adapter interrupts! */
+       synchronize_irq(ioc->pcidev->irq);
        CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
        ioc->active = 0;
+
        /* Clear any lingering interrupt */
        CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
+       CHIPREG_READ32(&ioc->chip->IntStatus);
 
        if (ioc->alloc != NULL) {
                sz = ioc->alloc_sz;
-               dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "free  @ %p, sz=%d bytes\n",
-                   ioc->name, ioc->alloc, ioc->alloc_sz));
+               dexitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "free  @ %p, sz=%d bytes\n",
+                       ioc->name, ioc->alloc, ioc->alloc_sz));
                pci_free_consistent(ioc->pcidev, sz,
                                ioc->alloc, ioc->alloc_dma);
                ioc->reply_frames = NULL;
@@ -2357,20 +2541,16 @@ mpt_adapter_disable(MPT_ADAPTER *ioc)
                ioc->alloc_total -= sz;
        }
 
-       if (ioc->cached_fw != NULL) {
-               sz = ioc->facts.FWImageSize;
-               pci_free_consistent(ioc->pcidev, sz,
-                       ioc->cached_fw, ioc->cached_fw_dma);
-               ioc->cached_fw = NULL;
-               ioc->alloc_total -= sz;
-       }
+       mpt_free_fw_memory(ioc);
 
        kfree(ioc->spi_data.nvram);
        mpt_inactive_raid_list_free(ioc);
        kfree(ioc->raid_data.pIocPg2);
        kfree(ioc->raid_data.pIocPg3);
+       kfree(ioc->raid_data.pIocPg6);
        ioc->spi_data.nvram = NULL;
        ioc->raid_data.pIocPg3 = NULL;
+       ioc->raid_data.pIocPg6 = NULL;
 
        if (ioc->spi_data.pIocPg4 != NULL) {
                sz = ioc->spi_data.IocPg4Sz;
@@ -2394,27 +2574,29 @@ mpt_adapter_disable(MPT_ADAPTER *ioc)
                if((ret = mpt_host_page_access_control(ioc,
                    MPI_DB_HPBAC_FREE_BUFFER, NO_SLEEP)) != 0) {
                        printk(MYIOC_s_ERR_FMT
-                          "host page buffers free failed (%d)!\n",
-                           ioc->name, ret);
+                          ": %s: host page buffers free failed (%d)!\n",
+                           ioc->name, __FUNCTION__, ret);
                }
-               dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "HostPageBuffer free  @ %p, sz=%d bytes\n",
+               dexitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HostPageBuffer free  @ %p, sz=%d bytes\n",
                        ioc->name, ioc->HostPageBuffer, ioc->HostPageBuffer_sz));
                pci_free_consistent(ioc->pcidev, ioc->HostPageBuffer_sz,
-                   ioc->HostPageBuffer, ioc->HostPageBuffer_dma);
+                               ioc->HostPageBuffer,
+                               ioc->HostPageBuffer_dma);
                ioc->HostPageBuffer = NULL;
                ioc->HostPageBuffer_sz = 0;
                ioc->alloc_total -= ioc->HostPageBuffer_sz;
        }
+
+       pci_set_drvdata(ioc->pcidev, NULL);
 }
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *     mpt_adapter_dispose - Free all resources associated with an MPT adapter
  *     @ioc: Pointer to MPT adapter structure
  *
  *     This routine unregisters h/w resources and frees all alloc'd memory
  *     associated with a MPT adapter structure.
- */
+ **/
 static void
 mpt_adapter_dispose(MPT_ADAPTER *ioc)
 {
@@ -2429,7 +2611,7 @@ mpt_adapter_dispose(MPT_ADAPTER *ioc)
 
        if (ioc->pci_irq != -1) {
                free_irq(ioc->pci_irq, ioc);
-               if (mpt_msi_enable)
+               if (ioc->msi_enable)
                        pci_disable_msi(ioc->pcidev);
                ioc->pci_irq = -1;
        }
@@ -2439,10 +2621,15 @@ mpt_adapter_dispose(MPT_ADAPTER *ioc)
                ioc->memmap = NULL;
        }
 
+       pci_disable_device(ioc->pcidev);
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21))
+       pci_release_selected_regions(ioc->pcidev, ioc->bars);
+#endif
+
 #if defined(CONFIG_MTRR) && 0
        if (ioc->mtrr_reg > 0) {
                mtrr_del(ioc->mtrr_reg, 0, 0);
-               dprintk(ioc, printk(MYIOC_s_INFO_FMT "MTRR region de-registered\n", ioc->name));
+               dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MTRR region de-registered\n", ioc->name));
        }
 #endif
 
@@ -2450,8 +2637,8 @@ mpt_adapter_dispose(MPT_ADAPTER *ioc)
        list_del(&ioc->list);
 
        sz_last = ioc->alloc_total;
-       dprintk(ioc, printk(MYIOC_s_INFO_FMT "free'd %d of %d bytes\n",
-           ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first));
+       dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "free'd %d of %d bytes\n",
+                       ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first));
 
        if (ioc->alt_ioc)
                ioc->alt_ioc->alt_ioc = NULL;
@@ -2459,11 +2646,10 @@ mpt_adapter_dispose(MPT_ADAPTER *ioc)
        kfree(ioc);
 }
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *     MptDisplayIocCapabilities - Disply IOC's capabilities.
  *     @ioc: Pointer to MPT adapter structure
- */
+ **/
 static void
 MptDisplayIocCapabilities(MPT_ADAPTER *ioc)
 {
@@ -2502,7 +2688,6 @@ MptDisplayIocCapabilities(MPT_ADAPTER *ioc)
        printk("}\n");
 }
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *     MakeIocReady - Get IOC to a READY state, using KickStart if needed.
  *     @ioc: Pointer to MPT_ADAPTER structure
@@ -2516,7 +2701,7 @@ MptDisplayIocCapabilities(MPT_ADAPTER *ioc)
  *             -2 - Msg Unit Reset Failed
  *             -3 - IO Unit Reset Failed
  *             -4 - IOC owned by a PEER
- */
+ **/
 static int
 MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
 {
@@ -2530,7 +2715,7 @@ MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
 
        /* Get current [raw] IOC state  */
        ioc_state = mpt_GetIocState(ioc, 0);
-       dhsprintk(ioc, printk(MYIOC_s_INFO_FMT "MakeIocReady [raw] state=%08x\n", ioc->name, ioc_state));
+       dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MakeIocReady, [raw] state=%08x\n", ioc->name, ioc_state));
 
        /*
         *      Check to see if IOC got left/stuck in doorbell handshake
@@ -2543,8 +2728,11 @@ MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
        }
 
        /* Is it already READY? */
-       if (!statefault && (ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY)
+       if (!statefault && (ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY) {
+               dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "IOC is in READY state\n",
+                   ioc->name));
                return 0;
+       }
 
        /*
         *      Check to see if IOC is in FAULT state.
@@ -2552,9 +2740,9 @@ MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
        if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
                statefault = 2;
                printk(MYIOC_s_WARN_FMT "IOC is in FAULT state!!!\n",
-                   ioc->name);
-               printk(MYIOC_s_WARN_FMT "           FAULT code = %04xh\n",
-                   ioc->name, ioc_state & MPI_DOORBELL_DATA_MASK);
+                               ioc->name);
+               printk(KERN_WARNING "           FAULT code = %04xh\n",
+                               ioc_state & MPI_DOORBELL_DATA_MASK);
        }
 
        /*
@@ -2570,7 +2758,7 @@ MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
                 * Else, fall through to KickStart case
                 */
                whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT;
-               dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
+               dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
                        "whoinit 0x%x statefault %d force %d\n",
                        ioc->name, whoinit, statefault, force));
                if (whoinit == MPI_WHOINIT_PCI_PEER)
@@ -2617,15 +2805,15 @@ MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
 
                ii++; cntdn--;
                if (!cntdn) {
-                       printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n",
-                                       ioc->name, (int)((ii+5)/HZ));
+                       printk(MYIOC_s_ERR_FMT "Wait IOC_READY state (0x%x) timeout(%d)!\n",
+                                       ioc->name, ioc_state, (int)((ii+5)/HZ));
                        return -ETIME;
                }
 
                if (sleepFlag == CAN_SLEEP) {
                        msleep(1);
                } else {
-                       mdelay (1);     /* 1 msec delay */
+                       mdelay(1);      /* 1 msec delay */
                }
 
        }
@@ -2639,7 +2827,6 @@ MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
        return hard_reset_done;
 }
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *     mpt_GetIocState - Get the current state of a MPT adapter.
  *     @ioc: Pointer to MPT_ADAPTER structure
@@ -2647,7 +2834,7 @@ MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
  *
  *     Returns all IOC Doorbell register bits if cooked==0, else just the
  *     Doorbell bits in MPI_IOC_STATE_MASK.
- */
+ **/
 u32
 mpt_GetIocState(MPT_ADAPTER *ioc, int cooked)
 {
@@ -2663,7 +2850,6 @@ mpt_GetIocState(MPT_ADAPTER *ioc, int cooked)
        return cooked ? sc : s;
 }
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *     GetIocFacts - Send IOCFacts request to MPT adapter.
  *     @ioc: Pointer to MPT_ADAPTER structure
@@ -2671,7 +2857,7 @@ mpt_GetIocState(MPT_ADAPTER *ioc, int cooked)
  *     @reason: If recovery, only update facts.
  *
  *     Returns 0 for success, non-zero for failure.
- */
+ **/
 static int
 GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
 {
@@ -2686,8 +2872,9 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
 
        /* IOC *must* NOT be in RESET state! */
        if (ioc->last_state == MPI_IOC_STATE_RESET) {
-               printk(MYIOC_s_ERR_FMT "Can't get IOCFacts NOT READY! (%08x)\n",
-                   ioc->name, ioc->last_state );
+               printk(KERN_ERR MYNAM ": ERROR - Can't get IOCFacts, %s NOT READY! (%08x)\n",
+                               ioc->name,
+                               ioc->last_state );
                return -44;
        }
 
@@ -2704,7 +2891,7 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
        get_facts.Function = MPI_FUNCTION_IOC_FACTS;
        /* Assert: All other get_facts fields are zero! */
 
-       dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+       dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
            "Sending get IocFacts request req_sz=%d reply_sz=%d\n",
            ioc->name, req_sz, reply_sz));
 
@@ -2734,6 +2921,8 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
                }
 
                facts->MsgVersion = le16_to_cpu(facts->MsgVersion);
+               if (facts->MsgVersion == MPI_VERSION_01_05)
+                       facts->HeaderVersion = le16_to_cpu(facts->HeaderVersion);
                facts->MsgContext = le32_to_cpu(facts->MsgContext);
                facts->IOCExceptions = le16_to_cpu(facts->IOCExceptions);
                facts->IOCStatus = le16_to_cpu(facts->IOCStatus);
@@ -2749,7 +2938,7 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
                 *      Old: u16{Major(4),Minor(4),SubMinor(8)}
                 *      New: u32{Major(8),Minor(8),Unit(8),Dev(8)}
                 */
-               if (facts->MsgVersion < 0x0102) {
+               if (facts->MsgVersion < MPI_VERSION_01_02) {
                        /*
                         *      Handle old FC f/w style, convert to new...
                         */
@@ -2761,9 +2950,11 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
                        facts->FWVersion.Word = le32_to_cpu(facts->FWVersion.Word);
 
                facts->ProductID = le16_to_cpu(facts->ProductID);
+
                if ((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK)
                    > MPI_FW_HEADER_PID_PROD_TARGET_SCSI)
                        ioc->ir_firmware = 1;
+
                facts->CurrentHostMfaHighAddr =
                                le32_to_cpu(facts->CurrentHostMfaHighAddr);
                facts->GlobalCredits = le16_to_cpu(facts->GlobalCredits);
@@ -2779,7 +2970,7 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
                 * to 14 in MPI-1.01.0x.
                 */
                if (facts->MsgLength >= (offsetof(IOCFactsReply_t,FWImageSize) + 7)/4 &&
-                   facts->MsgVersion > 0x0100) {
+                   facts->MsgVersion > MPI_VERSION_01_00) {
                        facts->FWImageSize = le32_to_cpu(facts->FWImageSize);
                }
 
@@ -2840,7 +3031,6 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
        return 0;
 }
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *     GetPortFacts - Send PortFacts request to MPT adapter.
  *     @ioc: Pointer to MPT_ADAPTER structure
@@ -2848,7 +3038,7 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
  *     @sleepFlag: Specifies whether the process can sleep
  *
  *     Returns 0 for success, non-zero for failure.
- */
+ **/
 static int
 GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
 {
@@ -2861,8 +3051,8 @@ GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
 
        /* IOC *must* NOT be in RESET state! */
        if (ioc->last_state == MPI_IOC_STATE_RESET) {
-               printk(MYIOC_s_ERR_FMT "Can't get PortFacts NOT READY! (%08x)\n",
-                   ioc->name, ioc->last_state );
+               printk(MYIOC_s_ERR_FMT "Can't get PortFacts, "
+                  " NOT READY! (%08x)\n", ioc->name, ioc->last_state );
                return -4;
        }
 
@@ -2880,14 +3070,14 @@ GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
        get_pfacts.PortNumber = portnum;
        /* Assert: All other get_pfacts fields are zero! */
 
-       dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending get PortFacts(%d) request\n",
-                       ioc->name, portnum));
+       dinitprintk(ioc, printk(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.
         */
        ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_pfacts,
-                               reply_sz, (u16*)pfacts, 5 /*seconds*/, sleepFlag);
+               reply_sz, (u16*)pfacts, 5 /*seconds*/, sleepFlag);
        if (ii != 0)
                return ii;
 
@@ -2904,18 +3094,8 @@ GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
        pfacts->MaxPersistentIDs = le16_to_cpu(pfacts->MaxPersistentIDs);
        pfacts->MaxLanBuckets = le16_to_cpu(pfacts->MaxLanBuckets);
 
-       switch (ioc->bus_type) {
-       case SAS:
-               max_id = pfacts->PortSCSIID;
-               break;
-       case FC:
-               max_id = pfacts->MaxDevices;
-               break;
-       case SPI:
-       default:
-               max_id = MPT_MAX_SCSI_DEVICES;
-               break;
-       }
+       max_id = (ioc->bus_type == SAS) ? pfacts->PortSCSIID :
+           pfacts->MaxDevices;
        ioc->devices_per_bus = (max_id > 255) ? 256 : max_id;
        ioc->number_of_buses = (ioc->devices_per_bus < 256) ? 1 : max_id/256;
 
@@ -2932,7 +3112,6 @@ GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
        return 0;
 }
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *     SendIocInit - Send IOCInit request to MPT adapter.
  *     @ioc: Pointer to MPT_ADAPTER structure
@@ -2941,7 +3120,7 @@ GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
  *     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, int sleepFlag)
 {
@@ -2971,7 +3150,8 @@ SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
 
        ioc_init.MaxDevices = (U8)ioc->devices_per_bus;
        ioc_init.MaxBuses = (U8)ioc->number_of_buses;
-       dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "facts.MsgVersion=%x\n",
+
+       dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "facts.MsgVersion=%x\n",
                   ioc->name, ioc->facts.MsgVersion));
        if (ioc->facts.MsgVersion >= MPI_VERSION_01_05) {
                // set MsgVersion and HeaderVersion host driver was built with
@@ -3054,7 +3234,6 @@ SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
        return r;
 }
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *     SendPortEnable - Send PortEnable request to MPT adapter port.
  *     @ioc: Pointer to MPT_ADAPTER structure
@@ -3064,7 +3243,7 @@ SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
  *     Send PortEnable to bring IOC to OPERATIONAL state.
  *
  *     Returns 0 for success, non-zero for failure.
- */
+ **/
 static int
 SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
 {
@@ -3087,7 +3266,7 @@ SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
 /*     port_enable.MsgFlags = 0;               */
 /*     port_enable.MsgContext = 0;             */
 
-       dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Port(%d)Enable (req @ %p)\n",
+       dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "Sending Port(%d)Enable (req @ %p)\n",
                        ioc->name, portnum, &port_enable));
 
        /* RAID FW may take a long time to enable
@@ -3111,45 +3290,62 @@ SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
  *
  *     If memory has already been allocated, the same (cached) value
  *     is returned.
- */
-void
+ *
+ *     Return 0 if successfull, or non-zero for failure
+ **/
+int
 mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size)
 {
-       if (ioc->cached_fw)
-               return;  /* use already allocated memory */
-       if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
+       int rc;
+
+       if (ioc->cached_fw) {
+               rc = 0;  /* use already allocated memory */
+               goto out;
+       }
+       else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
                ioc->cached_fw = ioc->alt_ioc->cached_fw;  /* use alt_ioc's memory */
                ioc->cached_fw_dma = ioc->alt_ioc->cached_fw_dma;
-               ioc->alloc_total += size;
-               ioc->alt_ioc->alloc_total -= size;
+               rc = 0;
+               goto out;
+       }
+       ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma);
+       if (!ioc->cached_fw) {
+               printk(MYIOC_s_ERR_FMT "Unable to allocate memory for the cached firmware image!\n",
+                   ioc->name);
+               rc = -1;
        } else {
-               if ( (ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma) ) )
-                       ioc->alloc_total += size;
+               dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FW Image  @ %p[%p], sz=%d[%x] bytes\n",
+                   ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, size, size));
+               ioc->alloc_total += size;
+               rc = 0;
        }
+ out:
+       return rc;
 }
+
 /**
  *     mpt_free_fw_memory - free firmware memory
  *     @ioc: Pointer to MPT_ADAPTER structure
  *
  *     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)
 {
        int sz;
 
+       if (!ioc->cached_fw)
+               return;
+
        sz = ioc->facts.FWImageSize;
-       dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "free_fw_memory: FW Image  @ %p[%p], sz=%d[%x] bytes\n",
-           ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
+       dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "free_fw_memory: FW Image  @ %p[%p], sz=%d[%x] bytes\n",
+                ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
        pci_free_consistent(ioc->pcidev, sz, ioc->cached_fw, ioc->cached_fw_dma);
+       ioc->alloc_total -= sz;
        ioc->cached_fw = NULL;
-
-       return;
 }
 
-
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *     mpt_do_upload - Construct and Send FWUpload request to MPT adapter port.
  *     @ioc: Pointer to MPT_ADAPTER structure
@@ -3162,7 +3358,7 @@ mpt_free_fw_memory(MPT_ADAPTER *ioc)
  *     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
 mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
 {
@@ -3170,26 +3366,18 @@ mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
        FWUpload_t              *prequest;
        FWUploadReply_t         *preply;
        FWUploadTCSGE_t         *ptcsge;
-       int                      sgeoffset;
        u32                      flagsLength;
-       int                      ii, sz, reply_sz;
+       int                      ii, reply_sz;
        int                      cmdStatus;
+       int                      request_size;
 
        /* If the image size is 0, we are done.
         */
-       if ((sz = ioc->facts.FWImageSize) == 0)
+       if (!ioc->facts.FWImageSize)
                return 0;
 
-       mpt_alloc_fw_memory(ioc, sz);
-
-       dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Image  @ %p[%p], sz=%d[%x] bytes\n",
-           ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
-
-       if (ioc->cached_fw == NULL) {
-               /* Major Failure.
-                */
+       if (mpt_alloc_fw_memory(ioc, ioc->facts.FWImageSize) != 0)
                return -ENOMEM;
-       }
 
        prequest = (sleepFlag == NO_SLEEP) ? kzalloc(ioc->req_sz, GFP_ATOMIC) :
            kzalloc(ioc->req_sz, GFP_KERNEL);
@@ -3207,49 +3395,47 @@ mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
 
        prequest->ImageType = MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM;
        prequest->Function = MPI_FUNCTION_FW_UPLOAD;
-
        ptcsge = (FWUploadTCSGE_t *) &prequest->SGL;
        ptcsge->DetailsLength = 12;
        ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
-       ptcsge->ImageSize = cpu_to_le32(sz);
+       ptcsge->ImageSize = cpu_to_le32(ioc->facts.FWImageSize);
        ptcsge++;
 
-       sgeoffset = sizeof(FWUpload_t) - sizeof(SGE_MPI_UNION) + sizeof(FWUploadTCSGE_t);
-
-       flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | sz;
+       flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | ioc->facts.FWImageSize;
        ioc->add_sge((char *)ptcsge, flagsLength, ioc->cached_fw_dma);
-
-       sgeoffset += sizeof(u32) + sizeof(dma_addr_t);
-       dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": Sending FW Upload (req @ %p) sgeoffset=%d \n",
-           ioc->name, prequest, sgeoffset));
+       request_size = offsetof(FWUpload_t, SGL) + sizeof(FWUploadTCSGE_t) +
+           sizeof(u32) + sizeof(dma_addr_t);
+       dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending FW Upload "
+           " (req @ %p) fw_size=%d mf_request_size=%d\n", ioc->name, prequest,
+           ioc->facts.FWImageSize, request_size));
        DBG_DUMP_FW_REQUEST_FRAME(ioc, (u32 *)prequest);
 
-       ii = mpt_handshake_req_reply_wait(ioc, sgeoffset, (u32*)prequest,
-                               reply_sz, (u16*)preply, 65 /*seconds*/, sleepFlag);
+       ii = mpt_handshake_req_reply_wait(ioc, request_size, (u32*)prequest,
+           reply_sz, (u16*)preply, 65 /*seconds*/, sleepFlag);
 
-       dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Upload completed rc=%x \n", ioc->name, ii));
+       dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FW Upload completed "
+           "rc=%x \n", ioc->name, ii));
 
        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;
-               }
+               int status;
+               status = le16_to_cpu(preply->IOCStatus) &
+                   MPI_IOCSTATUS_MASK;
+               if (status == MPI_IOCSTATUS_SUCCESS &&
+                   ioc->facts.FWImageSize ==
+                   le32_to_cpu(preply->ActualImageSize));
+                       cmdStatus = 0;
        }
-       dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "do_upload cmdStatus=%d \n",
-                       ioc->name, cmdStatus));
+       dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "do_upload cmdStatus=%d \n",
+               ioc->name, cmdStatus));
 
 
        if (cmdStatus) {
-
-               ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": fw upload failed, freeing image \n",
-                       ioc->name));
+               ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "fw upload failed, "
+                   "freeing image \n", ioc->name));
                mpt_free_fw_memory(ioc);
        }
        kfree(prequest);
@@ -3257,7 +3443,6 @@ mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
        return cmdStatus;
 }
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *     mpt_downloadboot - DownloadBoot code
  *     @ioc: Pointer to MPT_ADAPTER structure
@@ -3270,7 +3455,7 @@ mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
  *             -1 FW Image size is 0
  *             -2 No valid cached_fw Pointer
  *             <0 for fw upload failure.
- */
+ **/
 static int
 mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag)
 {
@@ -3282,10 +3467,10 @@ mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag)
        u32                      diagRwData;
        u32                      nextImage;
        u32                      load_addr;
-       u32                      ioc_state=0;
+       u32                      doorbell;
 
        ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot: fw size 0x%x (%d), FW Ptr %p\n",
-                               ioc->name, pFwHeader->ImageSize, pFwHeader->ImageSize, pFwHeader));
+           ioc->name, pFwHeader->ImageSize, pFwHeader->ImageSize, pFwHeader));
 
        CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
        CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
@@ -3297,11 +3482,10 @@ mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag)
        CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM));
 
        /* wait 1 msec */
-       if (sleepFlag == CAN_SLEEP) {
+       if (sleepFlag == CAN_SLEEP)
                msleep(1);
-       } else {
-               mdelay (1);
-       }
+       else
+               mdelay(1);
 
        diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
        CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
@@ -3314,11 +3498,10 @@ mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag)
                        break;
                }
                /* wait .1 sec */
-               if (sleepFlag == CAN_SLEEP) {
+               if (sleepFlag == CAN_SLEEP)
                        msleep (100);
-               } else {
+               else
                        mdelay (100);
-               }
        }
 
        if ( count == 30 ) {
@@ -3336,6 +3519,7 @@ mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag)
        CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
 
        /* Set the DiagRwEn and Disable ARM bits */
+       diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
        CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM));
 
        fwSize = (pFwHeader->ImageSize + 3)/4;
@@ -3349,13 +3533,12 @@ mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag)
 
        CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->LoadStartAddress);
        ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "LoadStart addr written 0x%x \n",
-               ioc->name, pFwHeader->LoadStartAddress));
+           ioc->name, pFwHeader->LoadStartAddress));
 
        ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write FW Image: 0x%x bytes @ %p\n",
-                               ioc->name, fwSize*4, ptrFw));
-       while (fwSize--) {
+           ioc->name, fwSize*4, ptrFw));
+       while (fwSize--)
                CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
-       }
 
        nextImage = pFwHeader->NextImageHeaderOffset;
        while (nextImage) {
@@ -3367,21 +3550,22 @@ mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag)
                ptrFw = (u32 *)pExtImage;
 
                ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write Ext Image: 0x%x (%d) bytes @ %p load_addr=%x\n",
-                                               ioc->name, fwSize*4, fwSize*4, ptrFw, load_addr));
+                   ioc->name, fwSize*4, fwSize*4, ptrFw, load_addr));
                CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, load_addr);
 
-               while (fwSize--) {
+               while (fwSize--)
                        CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
-               }
                nextImage = pExtImage->NextImageHeaderOffset;
        }
 
        /* Write the IopResetVectorRegAddr */
-       ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Addr=%x! \n", ioc->name,  pFwHeader->IopResetRegAddr));
+       ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Addr=%x! \n",
+           ioc->name, pFwHeader->IopResetRegAddr));
        CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->IopResetRegAddr);
 
        /* Write the IopResetVectorValue */
-       ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Value=%x! \n", ioc->name, pFwHeader->IopResetVectorValue));
+       ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Value=%x! \n",
+           ioc->name, pFwHeader->IopResetVectorValue));
        CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, pFwHeader->IopResetVectorValue);
 
        /* Clear the internal flash bad bit - autoincrementing register,
@@ -3398,75 +3582,75 @@ mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag)
                CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
                CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData);
 
-       } else /* if((ioc->bus_type == SAS) || (ioc->bus_type == FC)) */ {
-               diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
-               CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val |
-                   MPI_DIAG_CLEAR_FLASH_BAD_SIG);
-
-               /* wait 1 msec */
-               if (sleepFlag == CAN_SLEEP) {
-                       msleep (1);
-               } else {
-                       mdelay (1);
-               }
        }
 
        if (ioc->errata_flag_1064)
                pci_disable_io_access(ioc->pcidev);
 
        diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
-       ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot diag0val=%x, "
-               "turning off PREVENT_IOC_BOOT, DISABLE_ARM, RW_ENABLE\n",
-               ioc->name, diag0val));
-       diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE);
-       ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot now diag0val=%x\n",
-               ioc->name, diag0val));
+       ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "diag0val=%x, turning off"
+           " PREVENT_IOC_BOOT and DISABLE_ARM\n", ioc->name, diag0val));
+       diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM);
+       ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "diag0val=%x\n",
+           ioc->name, diag0val));
        CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
 
-       /* Write 0xFF to reset the sequencer */
-       CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
+       if (ioc->bus_type == SAS ) {
+               /* wait 1 sec */
+               if (sleepFlag == CAN_SLEEP)
+                       msleep(1000);
+               else
+                       mdelay(1000);
 
-       if (ioc->bus_type == SAS) {
-               ioc_state = mpt_GetIocState(ioc, 0);
-               if ( (GetIocFacts(ioc, sleepFlag,
-                               MPT_HOSTEVENT_IOC_BRINGUP)) != 0 ) {
-                       ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "GetIocFacts failed: IocState=%x\n",
-                                       ioc->name, ioc_state));
-                       return -EFAULT;
+               diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
+               ddlprintk(ioc, printk (MYIOC_s_DEBUG_FMT
+                   "diag0val=%x, turning off RW_ENABLE\n", ioc->name,
+                   diag0val));
+               diag0val &= ~(MPI_DIAG_RW_ENABLE);
+               ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "now diag0val=%x\n", ioc->name, diag0val));
+               CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
+
+               diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
+               if (diag0val & MPI_DIAG_FLASH_BAD_SIG) {
+                       diag0val |= MPI_DIAG_CLEAR_FLASH_BAD_SIG;
+                       CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
+                       diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
                }
+               diag0val &= ~(MPI_DIAG_DISABLE_ARM);
+               CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
+               diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
+               CHIPREG_WRITE32(&ioc->chip->DiagRwAddress, 0x3f000004);
        }
 
-       for (count=0; count<HZ*20; count++) {
-               if ((ioc_state = mpt_GetIocState(ioc, 0)) & MPI_IOC_STATE_READY) {
-                       ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
-                               "downloadboot successful! (count=%d) IocState=%x\n",
-                               ioc->name, count, ioc_state));
-                       if (ioc->bus_type == SAS) {
+       /* Write 0xFF to reset the sequencer */
+       CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
+
+       for (count = 0; count < 30; count ++) {
+               doorbell = CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_IOC_STATE_MASK;
+               if (doorbell == MPI_IOC_STATE_READY) {
+                       if (ioc->bus_type == SAS)
                                return 0;
-                       }
                        if ((SendIocInit(ioc, sleepFlag)) != 0) {
-                               ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
-                                       "downloadboot: SendIocInit failed\n",
-                                       ioc->name));
+                               ddlprintk(ioc, printk(MYIOC_s_WARN_FMT
+                                   "SendIocInit failed\n", ioc->name));
                                return -EFAULT;
                        }
                        ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
-                                       "downloadboot: SendIocInit successful\n",
-                                       ioc->name));
+                           "SendIocInit successful\n", ioc->name));
                        return 0;
                }
-               if (sleepFlag == CAN_SLEEP) {
-                       msleep (10);
-               } else {
-                       mdelay (10);
-               }
+               ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "looking for READY STATE:"
+                   " doorbell=%x count=%d\n", ioc->name, doorbell, count));
+               if (sleepFlag == CAN_SLEEP)
+                       msleep(1000);
+               else
+                       mdelay(1000);
        }
-       ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
-               "downloadboot failed! IocState=%x\n",ioc->name, ioc_state));
+       ddlprintk(ioc, printk(MYIOC_s_WARN_FMT "downloadboot failed! count=%d\n", ioc->name, count));
        return -EFAULT;
 }
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *     KickStart - Perform hard reset of MPT adapter.
  *     @ioc: Pointer to MPT_ADAPTER structure
@@ -3491,7 +3675,7 @@ mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag)
  *                  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)
 {
@@ -3499,7 +3683,7 @@ KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
        u32 ioc_state=0;
        int cnt,cntdn;
 
-       dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStarting!\n", ioc->name));
+       dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": KickStart\n", ioc->name));
        if (ioc->bus_type == SPI) {
                /* Always issue a Msg Unit Reset first. This will clear some
                 * SCSI bus hang conditions.
@@ -3517,14 +3701,15 @@ KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
        if (hard_reset_done < 0)
                return hard_reset_done;
 
-       dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset successful!\n",
-               ioc->name));
+       /* may not have worked but hard_reset_done doesn't always signal failure */
+       dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "Diagnostic reset completed!\n",
+                       ioc->name));
 
        cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 2;     /* 2 seconds */
        for (cnt=0; cnt<cntdn; cnt++) {
                ioc_state = mpt_GetIocState(ioc, 1);
                if ((ioc_state == MPI_IOC_STATE_READY) || (ioc_state == MPI_IOC_STATE_OPERATIONAL)) {
-                       dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStart successful! (cnt=%d)\n",
+                       dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "KickStart successful! (cnt=%d)\n",
                                        ioc->name, cnt));
                        return hard_reset_done;
                }
@@ -3536,11 +3721,10 @@ KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
        }
 
        dinitprintk(ioc, printk(MYIOC_s_ERR_FMT "Failed to come READY after reset! IocState=%x\n",
-               ioc->name, mpt_GetIocState(ioc, 0)));
+                       ioc->name, mpt_GetIocState(ioc, 0)));
        return -1;
 }
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *     mpt_diag_reset - Perform hard reset of the adapter.
  *     @ioc: Pointer to MPT_ADAPTER structure
@@ -3558,30 +3742,46 @@ KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
  *               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)
 {
-       MPT_ADAPTER     *iocp=NULL;
        u32 diag0val;
-       u32 doorbell;
+       u32 doorbell = 0;
        int hard_reset_done = 0;
        int count = 0;
        u32 diag1val = 0;
+       MpiFwHeader_t *cached_fw;       /* Pointer to FW */
+       u8       cb_idx;
 
        /* Clear any existing interrupts */
        CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
 
        if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) {
+
+               if (!ignore)
+                       return 0;
+
                drsprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset "
-                       "address=%p\n",  ioc->name, __FUNCTION__,
-                       &ioc->chip->Doorbell, &ioc->chip->Reset_1078));
+                   "address=%p\n",  ioc->name, __FUNCTION__, &ioc->chip->Doorbell,
+                   &ioc->chip->Reset_1078));
                CHIPREG_WRITE32(&ioc->chip->Reset_1078, 0x07);
                if (sleepFlag == CAN_SLEEP)
                        msleep(1);
                else
                        mdelay(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.
+                */
+               for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
+                       if (MptResetHandlers[cb_idx])
+                               (*(MptResetHandlers[cb_idx]))(ioc, MPT_IOC_PRE_RESET);
+               }
+
                for (count = 0; count < 60; count ++) {
                        doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
                        doorbell &= MPI_IOC_STATE_MASK;
@@ -3590,9 +3790,15 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
                                "looking for READY STATE: doorbell=%x"
                                " count=%d\n",
                                ioc->name, doorbell, count));
-                       if (doorbell == MPI_IOC_STATE_READY) {
+
+                       if (doorbell == MPI_IOC_STATE_READY)
                                return 1;
-                       }
+
+                       /*
+                        * Early out for hard fault
+                        */
+                       if (count && doorbell == MPI_IOC_STATE_FAULT)
+                               break;
 
                        /* wait 1 sec */
                        if (sleepFlag == CAN_SLEEP)
@@ -3600,16 +3806,20 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
                        else
                                mdelay(1000);
                }
+
+               if (doorbell != MPI_IOC_STATE_READY)
+                       printk(MYIOC_s_ERR_FMT "Failed to come READY after "
+                           "reset! IocState=%x", ioc->name, doorbell);
                return -1;
        }
 
        /* Use "Diagnostic reset" method! (only thing available!) */
        diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
 
-       if (ioc->debug_level & MPT_DEBUG) {
+       if (ioc->debug_level & MPT_DEBUG_RESET) {
                if (ioc->alt_ioc)
                        diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
-               dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG1: diag0=%08x, diag1=%08x\n",
+               drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG1: diag0=%08x, diag1=%08x\n",
                        ioc->name, diag0val, diag1val));
        }
 
@@ -3629,11 +3839,10 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
                        CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
 
                        /* wait 100 msec */
-                       if (sleepFlag == CAN_SLEEP) {
+                       if (sleepFlag == CAN_SLEEP)
                                msleep (100);
-                       } else {
+                       else
                                mdelay (100);
-                       }
 
                        count++;
                        if (count > 20) {
@@ -3645,14 +3854,14 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
 
                        diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
 
-                       dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
+                       drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
                                        ioc->name, diag0val));
                }
 
-               if (ioc->debug_level & MPT_DEBUG) {
+               if (ioc->debug_level & MPT_DEBUG_RESET) {
                        if (ioc->alt_ioc)
                                diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
-                       dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG2: diag0=%08x, diag1=%08x\n",
+                       drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG2: diag0=%08x, diag1=%08x\n",
                                ioc->name, diag0val, diag1val));
                }
                /*
@@ -3668,7 +3877,7 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
                 */
                CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
                hard_reset_done = 1;
-               dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset performed\n",
+               drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset performed\n",
                                ioc->name));
 
                /*
@@ -3677,57 +3886,44 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
                 * NOTE: If we're doing _IOC_BRINGUP, there can be no
                 * MptResetHandlers[] registered yet.
                 */
-               {
-                       u8       cb_idx;
-                       int      r = 0;
-
-                       for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
-                               if (MptResetHandlers[cb_idx]) {
-                                       dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
-                                               "Calling IOC pre_reset handler #%d\n",
-                                               ioc->name, cb_idx));
-                                       r += mpt_signal_reset(cb_idx, ioc, MPT_IOC_PRE_RESET);
-                                       if (ioc->alt_ioc) {
-                                               dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
-                                                       "Calling alt-%s pre_reset handler #%d\n",
-                                                       ioc->name, ioc->alt_ioc->name, cb_idx));
-                                               r += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_PRE_RESET);
-                                       }
+               for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
+                       if (MptResetHandlers[cb_idx]) {
+                               mpt_signal_reset(cb_idx, ioc, MPT_IOC_PRE_RESET);
+                               if (ioc->alt_ioc) {
+                                       mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_PRE_RESET);
                                }
                        }
-                       /* FIXME?  Examine results here? */
                }
 
                if (ioc->cached_fw)
-                       iocp = ioc;
+                       cached_fw = (MpiFwHeader_t *)ioc->cached_fw;
                else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw)
-                       iocp = ioc->alt_ioc;
-               if (iocp) {
+                       cached_fw = (MpiFwHeader_t *)ioc->alt_ioc->cached_fw;
+               else
+                       cached_fw = NULL;
+               if (cached_fw) {
                        /* 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(&iocp->chip->Diagnostic);
+                               diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
                                if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
                                        break;
                                }
 
-                               dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "cached_fw: diag0val=%x count=%d\n",
-                                       iocp->name, diag0val, count));
+                               drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "cached_fw: diag0val=%x count=%d\n",
+                                       ioc->name, diag0val, count));
                                /* wait 1 sec */
-                               if (sleepFlag == CAN_SLEEP) {
+                               if (sleepFlag == CAN_SLEEP)
                                        msleep (1000);
-                               } else {
+                               else
                                        mdelay (1000);
-                               }
                        }
-                       if ((count = mpt_downloadboot(ioc,
-                               (MpiFwHeader_t *)iocp->cached_fw, sleepFlag)) < 0) {
+                       if ((count = mpt_downloadboot(ioc, cached_fw, sleepFlag)) < 0) {
                                printk(MYIOC_s_WARN_FMT
                                        "firmware downloadboot failure (%d)!\n", ioc->name, count);
                        }
-
                } else {
                        /* Wait for FW to reload and for board
                         * to go to the READY state.
@@ -3739,25 +3935,38 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
                                doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
                                doorbell &= MPI_IOC_STATE_MASK;
 
-                               if (doorbell == MPI_IOC_STATE_READY) {
+                               drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                                   "looking for READY STATE: doorbell=%x"
+                                   " count=%d\n", ioc->name, doorbell, count));
+
+                               if (doorbell == MPI_IOC_STATE_READY)
+                                       break;
+
+                               /*
+                                * Early out for hard fault
+                                */
+                               if (count && doorbell == MPI_IOC_STATE_FAULT)
                                        break;
-                               }
 
                                /* wait 1 sec */
-                               if (sleepFlag == CAN_SLEEP) {
+                               if (sleepFlag == CAN_SLEEP)
                                        msleep (1000);
-                               } else {
+                               else
                                        mdelay (1000);
-                               }
                        }
+
+                       if (doorbell != MPI_IOC_STATE_READY)
+                               printk(MYIOC_s_ERR_FMT "Failed to come READY "
+                                   "after reset! IocState=%x", ioc->name,
+                                   doorbell);
                }
        }
 
        diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
-       if (ioc->debug_level & MPT_DEBUG) {
+       if (ioc->debug_level & MPT_DEBUG_RESET) {
                if (ioc->alt_ioc)
                        diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
-               dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG3: diag0=%08x, diag1=%08x\n",
+               drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG3: diag0=%08x, diag1=%08x\n",
                        ioc->name, diag0val, diag1val));
        }
 
@@ -3778,11 +3987,10 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
                CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
 
                /* wait 100 msec */
-               if (sleepFlag == CAN_SLEEP) {
+               if (sleepFlag == CAN_SLEEP)
                        msleep (100);
-               } else {
+               else
                        mdelay (100);
-               }
 
                count++;
                if (count > 20) {
@@ -3813,11 +4021,11 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
                return -3;
        }
 
-       if (ioc->debug_level & MPT_DEBUG) {
+       if (ioc->debug_level & MPT_DEBUG_RESET) {
                if (ioc->alt_ioc)
                        diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
-               dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG4: diag0=%08x, diag1=%08x\n",
-                       ioc->name, diag0val, diag1val));
+               drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG4: diag0=%08x, diag1=%08x\n",
+                               ioc->name, diag0val, diag1val));
        }
 
        /*
@@ -3831,7 +4039,6 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
        return hard_reset_done;
 }
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *     SendIocReset - Send IOCReset request to MPT adapter.
  *     @ioc: Pointer to MPT_ADAPTER structure
@@ -3842,7 +4049,7 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
  *     Send IOCReset request to the MPT adapter.
  *
  *     Returns 0 for success, non-zero for failure.
- */
+ **/
 static int
 SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag)
 {
@@ -3853,7 +4060,7 @@ SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag)
        drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "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, 5, sleepFlag)) < 0)
+       if ((r = WaitForDoorbellAck(ioc, 15, sleepFlag)) < 0)
                return r;
 
        /* FW ACK'd request, wait for READY state
@@ -3868,15 +4075,15 @@ SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag)
                        if (sleepFlag != CAN_SLEEP)
                                count *= 10;
 
-                       printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n",
-                           ioc->name, (int)((count+5)/HZ));
+                       printk(MYIOC_s_ERR_FMT "Wait IOC_READY state (0x%x) timeout(%d)!\n",
+                                       ioc->name, state, (int)((count+5)/HZ));
                        return -ETIME;
                }
 
                if (sleepFlag == CAN_SLEEP) {
                        msleep(1);
                } else {
-                       mdelay (1);     /* 1 msec delay */
+                       mdelay(1);      /* 1 msec delay */
                }
        }
 
@@ -3890,14 +4097,13 @@ SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag)
        return 0;
 }
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *     initChainBuffers - Allocate memory for and initialize chain buffers
  *     @ioc: Pointer to MPT_ADAPTER structure
  *
  *     Allocates memory for and initializes chain buffers,
  *     chain buffer control arrays and spinlock.
- */
+ **/
 static int
 initChainBuffers(MPT_ADAPTER *ioc)
 {
@@ -3955,8 +4161,14 @@ initChainBuffers(MPT_ADAPTER *ioc)
        dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "num_sge=%d numSGE=%d\n",
                ioc->name, num_sge, numSGE));
 
-       if ( numSGE > MPT_SCSI_SG_DEPTH )
-               numSGE = MPT_SCSI_SG_DEPTH;
+       if (ioc->bus_type == FC) {
+               if (numSGE > MPT_SCSI_FC_SG_DEPTH)
+                       numSGE = MPT_SCSI_FC_SG_DEPTH;
+       }
+       else {
+               if (numSGE > MPT_SCSI_SG_DEPTH)
+                       numSGE = MPT_SCSI_SG_DEPTH;
+       }
 
        num_chain = 1;
        while (numSGE - num_sge > 0) {
@@ -3991,7 +4203,6 @@ initChainBuffers(MPT_ADAPTER *ioc)
        return num_chain;
 }
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *     PrimeIocFifos - Initialize IOC request and reply FIFOs.
  *     @ioc: Pointer to MPT_ADAPTER structure
@@ -4001,7 +4212,7 @@ initChainBuffers(MPT_ADAPTER *ioc)
  *     reply frames.
  *
  *     Returns 0 for success, non-zero for failure.
- */
+ **/
 static int
 PrimeIocFifos(MPT_ADAPTER *ioc)
 {
@@ -4010,13 +4221,15 @@ PrimeIocFifos(MPT_ADAPTER *ioc)
        dma_addr_t alloc_dma;
        u8 *mem;
        int i, reply_sz, sz, total_size, num_chain;
-       u64     dma_mask = 0;
+       u64     dma_mask;
 
-       /*  Prime reply FIFO...  */
+       dma_mask = 0;
 
+       /*  Prime reply FIFO...  */
        if (ioc->reply_frames == NULL) {
                if ( (num_chain = initChainBuffers(ioc)) < 0)
                        return -1;
+
                /*
                 * 1078 errata workaround for the 36GB limitation
                 */
@@ -4184,6 +4397,7 @@ PrimeIocFifos(MPT_ADAPTER *ioc)
        return 0;
 
 out_fail:
+
        if (ioc->alloc != NULL) {
                sz = ioc->alloc_sz;
                pci_free_consistent(ioc->pcidev,
@@ -4210,7 +4424,6 @@ out_fail:
        return -1;
 }
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *     mpt_handshake_req_reply_wait - Send MPT request to and receive reply
  *     from IOC via doorbell handshake method.
@@ -4228,7 +4441,7 @@ out_fail:
  *     greater than 1 byte in size.
  *
  *     Returns 0 for success, non-zero for failure.
- */
+ **/
 static int
 mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req,
                int replyBytes, u16 *u16reply, int maxwait, int sleepFlag)
@@ -4322,7 +4535,6 @@ mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req,
        return -failcnt;
 }
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *     WaitForDoorbellAck - Wait for IOC doorbell handshake acknowledge
  *     @ioc: Pointer to MPT_ADAPTER structure
@@ -4334,7 +4546,7 @@ mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req,
  *     bit in its IntStatus register being clear.
  *
  *     Returns a negative value on failure, else wait loop count.
- */
+ **/
 static int
 WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
 {
@@ -4373,7 +4585,6 @@ WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
        return -1;
 }
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *     WaitForDoorbellInt - Wait for IOC to set its doorbell interrupt bit
  *     @ioc: Pointer to MPT_ADAPTER structure
@@ -4384,7 +4595,7 @@ WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
  *     (MPI_HIS_DOORBELL_INTERRUPT) to be set in the IntStatus register.
  *
  *     Returns a negative value on failure, else wait loop count.
- */
+ **/
 static int
 WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
 {
@@ -4395,18 +4606,18 @@ WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
        cntdn = 1000 * howlong;
        if (sleepFlag == CAN_SLEEP) {
                while (--cntdn) {
+                       msleep(1);
                        intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
                        if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
                                break;
-                       msleep(1);
                        count++;
                }
        } else {
                while (--cntdn) {
+                       udelay (1000);
                        intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
                        if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
                                break;
-                       udelay (1000);
                        count++;
                }
        }
@@ -4422,7 +4633,6 @@ WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
        return -1;
 }
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *     WaitForDoorbellReply - Wait for and capture an IOC handshake reply.
  *     @ioc: Pointer to MPT_ADAPTER structure
@@ -4434,7 +4644,7 @@ WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
  *     of 128 bytes of reply data.
  *
  *     Returns a negative value on failure, else size of reply in WORDS.
- */
+ **/
 static int
 WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
 {
@@ -4508,7 +4718,6 @@ WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
        return u16cnt/2;
 }
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *     GetLanConfigPages - Fetch LANConfig pages.
  *     @ioc: Pointer to MPT_ADAPTER structure
@@ -4518,7 +4727,7 @@ WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
  *             -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)
 {
@@ -4619,7 +4828,6 @@ GetLanConfigPages(MPT_ADAPTER *ioc)
        return rc;
 }
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *     mptbase_sas_persist_operation - Perform operation on SAS Persistent Table
  *     @ioc: Pointer to MPT_ADAPTER structure
@@ -4632,9 +4840,7 @@ GetLanConfigPages(MPT_ADAPTER *ioc)
  *     NOTE: Don't use not this function during interrupt time.
  *
  *     Returns 0 for success, non-zero error
- */
-
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+ **/
 int
 mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)
 {
@@ -4642,7 +4848,14 @@ mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)
        SasIoUnitControlReply_t         *sasIoUnitCntrReply;
        MPT_FRAME_HDR                   *mf = NULL;
        MPIHeader_t                     *mpi_hdr;
+       int                             ret = 0;
+       unsigned long                   timeleft;
+
+       mutex_lock(&ioc->mptbase_cmds.mutex);
 
+       /* init the internal cmd struct */
+       memset(ioc->mptbase_cmds.reply, 0 , MPT_DEFAULT_FRAME_SIZE);
+       INITIALIZE_MGMT_STATUS(ioc->mptbase_cmds.status)
 
        /* insure garbage is not sent to fw */
        switch(persist_opcode) {
@@ -4652,8 +4865,8 @@ mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)
                break;
 
        default:
-               return -1;
-               break;
+               ret = -1;
+               goto out;
        }
 
        printk("%s: persist_opcode=%x\n",__FUNCTION__, persist_opcode);
@@ -4662,7 +4875,8 @@ mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)
         */
        if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
                printk("%s: no msg frames!\n",__FUNCTION__);
-               return -1;
+               ret = -1;
+               goto out;
         }
 
        mpi_hdr = (MPIHeader_t *) mf;
@@ -4672,31 +4886,44 @@ mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)
        sasIoUnitCntrReq->MsgContext = mpi_hdr->MsgContext;
        sasIoUnitCntrReq->Operation = persist_opcode;
 
-       init_timer(&ioc->persist_timer);
-       ioc->persist_timer.data = (unsigned long) ioc;
-       ioc->persist_timer.function = mpt_timer_expired;
-       ioc->persist_timer.expires = jiffies + HZ*10 /* 10 sec */;
-       ioc->persist_wait_done=0;
-       add_timer(&ioc->persist_timer);
        mpt_put_msg_frame(mpt_base_index, ioc, mf);
-       wait_event(mpt_waitq, ioc->persist_wait_done);
+       timeleft = wait_for_completion_timeout(&ioc->mptbase_cmds.done, 10*HZ);
+       if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
+               ret = -ETIME;
+               printk("%s: failed\n", __FUNCTION__);
+               if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
+                       goto out;
+               if (!timeleft) {
+                       printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
+                           ioc->name, __FUNCTION__);
+                       if (mpt_SoftResetHandler(ioc, CAN_SLEEP) != 0)
+                               mpt_HardResetHandler(ioc, CAN_SLEEP);
+                       mpt_free_msg_frame(ioc, mf);
+               }
+               goto out;
+       }
+
+       if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
+               ret = -1;
+               goto out;
+       }
 
        sasIoUnitCntrReply =
-           (SasIoUnitControlReply_t *)ioc->persist_reply_frame;
+           (SasIoUnitControlReply_t *)ioc->mptbase_cmds.reply;
        if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) {
-               printk("%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
-                   __FUNCTION__,
-                   sasIoUnitCntrReply->IOCStatus,
-                   sasIoUnitCntrReply->IOCLogInfo);
-               return -1;
-       }
+               printk("%s: IOCStatus=0x%X IOCLogInfo=0x%X\n", __FUNCTION__,
+                   sasIoUnitCntrReply->IOCStatus, sasIoUnitCntrReply->IOCLogInfo);
+               printk("%s: failed\n",__FUNCTION__);
+               ret = -1;
+       } else
+               printk("%s: success\n",__FUNCTION__);
+ out:
 
-       printk("%s: success\n",__FUNCTION__);
-       return 0;
+       CLEAR_MGMT_STATUS(ioc->mptbase_cmds.status)
+       mutex_unlock(&ioc->mptbase_cmds.mutex);
+       return ret;
 }
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-
 static void
 mptbase_raid_process_event_data(MPT_ADAPTER *ioc,
     MpiEventDataRaid_t * pRaidEventData)
@@ -4827,7 +5054,6 @@ mptbase_raid_process_event_data(MPT_ADAPTER *ioc,
        }
 }
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *     GetIoUnitPage2 - Retrieve BIOS version and boot order information.
  *     @ioc: Pointer to MPT_ADAPTER structure
@@ -4837,7 +5063,7 @@ mptbase_raid_process_event_data(MPT_ADAPTER *ioc,
  *             -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)
 {
@@ -4885,7 +5111,6 @@ GetIoUnitPage2(MPT_ADAPTER *ioc)
        return rc;
 }
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *     mpt_GetScsiPortSettings - read SCSI Port Page 0 and 2
  *     @ioc: Pointer to a Adapter Strucutre
@@ -4905,7 +5130,7 @@ GetIoUnitPage2(MPT_ADAPTER *ioc)
  *             Both valid
  *             Return 0
  *     CHECK - what type of locking mechanisms should be used????
- */
+ **/
 static int
 mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
 {
@@ -4965,8 +5190,8 @@ mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
                                ioc->spi_data.busType = MPT_HOST_BUS_UNKNOWN;
                                rc = 1;
                                ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
-                                       "Unable to read PortPage0 minSyncFactor=%x\n",
-                                       ioc->name, ioc->spi_data.minSyncFactor));
+                                   "Unable to read PortPage0 minSyncFactor=%x\n",
+                                   ioc->name, ioc->spi_data.minSyncFactor));
                        } else {
                                /* Save the Port Page 0 data
                                 */
@@ -4976,8 +5201,7 @@ mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
 
                                if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) {
                                        ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS;
-                                       ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
-                                               "noQas due to Capabilities=%x\n",
+                                       ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "noQas due to Capabilities=%x\n",
                                                ioc->name, pPP0->Capabilities));
                                }
                                ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0;
@@ -4986,8 +5210,7 @@ mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
                                        ioc->spi_data.maxSyncOffset = (u8) (data >> 16);
                                        data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK;
                                        ioc->spi_data.minSyncFactor = (u8) (data >> 8);
-                                       ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
-                                               "PortPage0 minSyncFactor=%x\n",
+                                       ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PortPage0 minSyncFactor=%x\n",
                                                ioc->name, ioc->spi_data.minSyncFactor));
                                } else {
                                        ioc->spi_data.maxSyncOffset = 0;
@@ -5003,8 +5226,7 @@ mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
 
                                        if (ioc->spi_data.minSyncFactor < MPT_ULTRA) {
                                                ioc->spi_data.minSyncFactor = MPT_ULTRA;
-                                               ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
-                                                       "HVD or SE detected, minSyncFactor=%x\n",
+                                               ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HVD or SE detected, minSyncFactor=%x\n",
                                                        ioc->name, ioc->spi_data.minSyncFactor));
                                        }
                                }
@@ -5109,7 +5331,6 @@ mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
        return rc;
 }
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *     mpt_readScsiDevicePageHeaders - save version and length of SDP1
  *     @ioc: Pointer to a Adapter Strucutre
@@ -5117,7 +5338,7 @@ mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
  *
  *     Return: -EFAULT if read of config page header fails
  *             or 0 if success.
- */
+ **/
 static int
 mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum)
 {
@@ -5160,9 +5381,73 @@ mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum)
        return 0;
 }
 
+static void
+mpt_read_ioc_pg_6(MPT_ADAPTER *ioc)
+{
+       CONFIGPARMS              cfg;
+       ConfigPageHeader_t       header;
+       IOCPage6_t              *pIoc6=NULL;
+       dma_addr_t               ioc6_dma;
+       int                      iocpage6sz;
+       void                    *mem;
+
+       /* Free the old page
+        */
+       if (ioc->raid_data.pIocPg6) {
+               kfree(ioc->raid_data.pIocPg6);
+               ioc->raid_data.pIocPg6 = NULL;
+       }
+
+       /* There is at least one physical disk.
+        * Read and save IOC Page 3
+        */
+       header.PageVersion = 0;
+       header.PageLength = 0;
+       header.PageNumber = 6;
+       header.PageType = MPI_CONFIG_PAGETYPE_IOC;
+       cfg.cfghdr.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 out;
+
+       if (header.PageLength == 0)
+               goto out;
+
+       /* Read Header good, alloc memory
+        */
+       iocpage6sz = header.PageLength * 4;
+       pIoc6 = pci_alloc_consistent(ioc->pcidev, iocpage6sz, &ioc6_dma);
+       if (!pIoc6)
+               goto out;
+
+       /* Read the Page and save the data
+        * into malloc'd memory.
+        */
+       cfg.physAddr = ioc6_dma;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+       if (mpt_config(ioc, &cfg) != 0)
+               goto out;
+
+       mem = kmalloc(iocpage6sz, GFP_ATOMIC);
+       if (!mem)
+               goto out;
+
+       memcpy(mem, pIoc6, iocpage6sz);
+       ioc->raid_data.pIocPg6 = mem;
+
+ out:
+       if (pIoc6)
+               pci_free_consistent(ioc->pcidev, iocpage6sz, pIoc6, ioc6_dma);
+}
+
 /**
- * mpt_inactive_raid_list_free - This clears this link list.
- * @ioc : pointer to per adapter structure
+  * mpt_inactive_raid_list_free - This clears this link list.
+  * @ioc : pointer to per adapter structure
+  *
  **/
 static void
 mpt_inactive_raid_list_free(MPT_ADAPTER *ioc)
@@ -5182,11 +5467,13 @@ mpt_inactive_raid_list_free(MPT_ADAPTER *ioc)
 }
 
 /**
- * mpt_inactive_raid_volumes - sets up link list of phy_disk_nums for devices belonging in an inactive volume
- *
- * @ioc : pointer to per adapter structure
- * @channel : volume channel
- * @id : volume target id
+  * mpt_inactive_raid_volumes - sets up link list of phy_disk_nums
+  * for devices belonging in an inactive volume
+  *
+  * @ioc : pointer to per adapter structure
+  * @channel : volume channel
+  * @id : volume target id
+  *
  **/
 static void
 mpt_inactive_raid_volumes(MPT_ADAPTER *ioc, u8 channel, u8 id)
@@ -5195,10 +5482,12 @@ mpt_inactive_raid_volumes(MPT_ADAPTER *ioc, u8 channel, u8 id)
        ConfigPageHeader_t              hdr;
        dma_addr_t                      dma_handle;
        pRaidVolumePage0_t              buffer = NULL;
-       int                             i;
+       int                             i, j;
        RaidPhysDiskPage0_t             phys_disk;
+       RaidPhysDiskPage1_t             *phys_disk_1;
        struct inactive_raid_component_info *component_info;
        int                             handle_inactive_volumes;
+       int                             num_paths, device_is_online;
 
        memset(&cfg, 0 , sizeof(CONFIGPARMS));
        memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
@@ -5243,8 +5532,31 @@ mpt_inactive_raid_volumes(MPT_ADAPTER *ioc, u8 channel, u8 id)
                    buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
                        continue;
 
+               if (phys_disk.PhysDiskStatus.State !=
+                   MPI_PHYSDISK0_STATUS_ONLINE)
+                       continue;
+
+               /* check to see if device is online by checking phys_disk_pg1 */
+               device_is_online = 0;
+               num_paths = mpt_raid_phys_disk_get_num_paths(ioc,
+                   buffer->PhysDisk[i].PhysDiskNum);
+               if (num_paths < 2)
+                       continue;
+               phys_disk_1 = kzalloc(offsetof(RaidPhysDiskPage1_t,Path) +
+                  (num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL);
+               if (!phys_disk_1)
+                       continue;
+               mpt_raid_phys_disk_pg1(ioc, buffer->PhysDisk[i].PhysDiskNum,
+                   phys_disk_1);
+               for (j = 0; j < num_paths && !device_is_online; j++)
+                       if (!phys_disk_1->Path[j].Flags)
+                               device_is_online = 1;
+               kfree(phys_disk_1);
+               if (!device_is_online)
+                       continue;
+
                if ((component_info = kmalloc(sizeof (*component_info),
-                GFP_KERNEL)) == NULL)
+                   GFP_KERNEL)) == NULL)
                        continue;
 
                component_info->volumeID = id;
@@ -5288,6 +5600,7 @@ mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num, pRaidPhysDiskPage0_t
        memset(&cfg, 0 , sizeof(CONFIGPARMS));
        memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
 
+       hdr.PageVersion = MPI_RAIDPHYSDISKPAGE0_PAGEVERSION;
        hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
        cfg.cfghdr.hdr = &hdr;
        cfg.physAddr = -1;
@@ -5333,6 +5646,181 @@ mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num, pRaidPhysDiskPage0_t
        return rc;
 }
 
+/**
+ *     mpt_raid_phys_disk_get_num_paths - returns number paths associated to this phys_num
+ *     @ioc: Pointer to a Adapter Structure
+ *     @phys_disk_num: io unit unique phys disk num generated by the ioc
+ *
+ *     Return:
+ *     returns number paths
+ **/
+int
+mpt_raid_phys_disk_get_num_paths(MPT_ADAPTER *ioc, u8 phys_disk_num)
+{
+       CONFIGPARMS                     cfg;
+       ConfigPageHeader_t              hdr;
+       dma_addr_t                      dma_handle;
+       pRaidPhysDiskPage1_t            buffer = NULL;
+       int                             rc;
+
+       memset(&cfg, 0 , sizeof(CONFIGPARMS));
+       memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
+
+       hdr.PageVersion = MPI_RAIDPHYSDISKPAGE1_PAGEVERSION;
+       hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
+       hdr.PageNumber = 1;
+       cfg.cfghdr.hdr = &hdr;
+       cfg.physAddr = -1;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+
+       if (mpt_config(ioc, &cfg) != 0) {
+               rc = 0;
+               goto out;
+       }
+
+       if (!hdr.PageLength) {
+               rc = 0;
+               goto out;
+       }
+
+       buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
+           &dma_handle);
+
+       if (!buffer) {
+               rc = 0;
+               goto out;
+       }
+
+       cfg.physAddr = dma_handle;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+       cfg.pageAddr = phys_disk_num;
+
+       if (mpt_config(ioc, &cfg) != 0) {
+               rc = 0;
+               goto out;
+       }
+
+       rc = buffer->NumPhysDiskPaths;
+ out:
+
+       if (buffer)
+               pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
+                   dma_handle);
+
+       return rc;
+}
+
+/**
+ *     mpt_raid_phys_disk_pg1 - returns phys disk page 1
+ *     @ioc: Pointer to a Adapter Structure
+ *     @phys_disk_num: io unit unique phys disk num generated by the ioc
+ *     @phys_disk: requested payload data returned
+ *
+ *     Return:
+ *     0 on success
+ *     -EFAULT if read of config page header fails or data pointer not NULL
+ *     -ENOMEM if pci_alloc failed
+ **/
+int
+mpt_raid_phys_disk_pg1(MPT_ADAPTER *ioc, u8 phys_disk_num, RaidPhysDiskPage1_t *phys_disk)
+{
+       CONFIGPARMS                     cfg;
+       ConfigPageHeader_t              hdr;
+       dma_addr_t                      dma_handle;
+       pRaidPhysDiskPage1_t            buffer = NULL;
+       int                             rc;
+       int                             i;
+       __le64                          sas_address;
+
+       memset(&cfg, 0 , sizeof(CONFIGPARMS));
+       memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
+       rc = 0;
+
+       hdr.PageVersion = MPI_RAIDPHYSDISKPAGE1_PAGEVERSION;
+       hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
+       hdr.PageNumber = 1;
+       cfg.cfghdr.hdr = &hdr;
+       cfg.physAddr = -1;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+
+       if (mpt_config(ioc, &cfg) != 0) {
+               rc = -EFAULT;
+               goto out;
+       }
+
+       if (!hdr.PageLength) {
+               rc = -EFAULT;
+               goto out;
+       }
+
+       buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
+           &dma_handle);
+
+       if (!buffer) {
+               rc = -ENOMEM;
+               goto out;
+       }
+
+       cfg.physAddr = dma_handle;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+       cfg.pageAddr = phys_disk_num;
+
+       if (mpt_config(ioc, &cfg) != 0) {
+               rc = -EFAULT;
+               goto out;
+       }
+
+       phys_disk->NumPhysDiskPaths = buffer->NumPhysDiskPaths;
+       phys_disk->PhysDiskNum = phys_disk_num;
+       for (i = 0; i < phys_disk->NumPhysDiskPaths; i++) {
+               phys_disk->Path[i].PhysDiskID = buffer->Path[i].PhysDiskID;
+               phys_disk->Path[i].PhysDiskBus = buffer->Path[i].PhysDiskBus;
+               phys_disk->Path[i].OwnerIdentifier = buffer->Path[i].OwnerIdentifier;
+               phys_disk->Path[i].Flags = le16_to_cpu(buffer->Path[i].Flags);
+               memcpy(&sas_address, &buffer->Path[i].WWID, sizeof(__le64));
+               sas_address = le64_to_cpu(sas_address);
+               memcpy(&phys_disk->Path[i].WWID, &sas_address, sizeof(__le64));
+               memcpy(&sas_address, &buffer->Path[i].OwnerWWID, sizeof(__le64));
+               sas_address = le64_to_cpu(sas_address);
+               memcpy(&phys_disk->Path[i].OwnerWWID, &sas_address, sizeof(__le64));
+       }
+
+ out:
+
+       if (buffer)
+               pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
+                   dma_handle);
+
+       return rc;
+}
+
+/**
+ *     mpt_sort_ioc_pg2 - compare function for sorting volumes
+ *     in ascending order
+ *     @a: ioc_pg2 raid volume page
+ *     @b: ioc_pg2 raid volume page
+ *
+ *     Return:
+ *     0 same, 1 (a is bigger), -1 (b is bigger)
+ **/
+static int
+mpt_sort_ioc_pg2(const void *a, const void *b)
+{
+       ConfigPageIoc2RaidVol_t * volume_a = (ConfigPageIoc2RaidVol_t *)a;
+       ConfigPageIoc2RaidVol_t * volume_b = (ConfigPageIoc2RaidVol_t *)b;
+
+       if (volume_a->VolumeBus == volume_b->VolumeBus) {
+               if (volume_a->VolumeID == volume_b->VolumeID)
+                       return 0;
+               if (volume_a->VolumeID < volume_b->VolumeID)
+                       return -1;
+               return 1;
+       }
+       if (volume_a->VolumeBus < volume_b->VolumeBus)
+               return -1;
+       return 1;
+}
+
 /**
  *     mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes
  *     @ioc: Pointer to a Adapter Strucutre
@@ -5396,16 +5884,22 @@ mpt_findImVolumes(MPT_ADAPTER *ioc)
        if (!mem)
                goto out;
 
+       /*
+        * sort volumes in ascending order
+        */
+       sort(pIoc2->RaidVolume, pIoc2->NumActiveVolumes,
+           sizeof(ConfigPageIoc2RaidVol_t), mpt_sort_ioc_pg2, NULL);
        memcpy(mem, (u8 *)pIoc2, iocpage2sz);
        ioc->raid_data.pIocPg2 = (IOCPage2_t *) mem;
 
-       mpt_read_ioc_pg_3(ioc);
-
        for (i = 0; i < pIoc2->NumActiveVolumes ; i++)
                mpt_inactive_raid_volumes(ioc,
                    pIoc2->RaidVolume[i].VolumeBus,
                    pIoc2->RaidVolume[i].VolumeID);
 
+       mpt_read_ioc_pg_3(ioc);
+       mpt_read_ioc_pg_6(ioc);
+
  out:
        pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma);
 
@@ -5565,6 +6059,9 @@ mpt_read_ioc_pg_1(MPT_ADAPTER *ioc)
        cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
        if (mpt_config(ioc, &cfg) == 0) {
 
+#if defined(CPQ_CIM)
+               ioc->pci_slot_number = pIoc1->PCISlotNum;
+#endif
                tmp = le32_to_cpu(pIoc1->Flags) & MPI_IOCPAGE1_REPLY_COALESCING;
                if (tmp == MPI_IOCPAGE1_REPLY_COALESCING) {
                        tmp = le32_to_cpu(pIoc1->CoalescingTimeout);
@@ -5585,19 +6082,16 @@ mpt_read_ioc_pg_1(MPT_ADAPTER *ioc)
 
                                        cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM;
                                        if (mpt_config(ioc, &cfg) == 0) {
-                                               dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
-                                                               "Reset NVRAM Coalescing Timeout to = %d\n",
+                                               dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Reset NVRAM Coalescing Timeout to = %d\n",
                                                                ioc->name, MPT_COALESCING_TIMEOUT));
                                        } else {
-                                               dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
-                                                               "Reset NVRAM Coalescing Timeout Failed\n",
-                                                               ioc->name));
+                                               dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Reset NVRAM Coalescing Timeout Failed\n",
+                                                                       ioc->name));
                                        }
 
                                } else {
-                                       dprintk(ioc, printk(MYIOC_s_WARN_FMT
-                                               "Reset of Current Coalescing Timeout Failed!\n",
-                                               ioc->name));
+                                       dprintk(ioc, printk(MYIOC_s_WARN_FMT "Reset of Current Coalescing Timeout Failed!\n",
+                                                               ioc->name));
                                }
                        }
 
@@ -5654,43 +6148,39 @@ mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc)
                pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, pbuf, buf_dma);
 }
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *     SendEventNotification - Send EventNotification (on or off) request to adapter
  *     @ioc: Pointer to MPT_ADAPTER structure
  *     @EvSwitch: Event switch flags
- */
+ *     @sleepFlag: Specifies whether the process can sleep
+ **/
 static int
-SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch)
+SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch, int sleepFlag)
 {
-       EventNotification_t     *evnp;
-
-       evnp = (EventNotification_t *) mpt_get_msg_frame(mpt_base_index, ioc);
-       if (evnp == NULL) {
-               devtverboseprintk(ioc, printk(MYIOC_s_WARN_FMT "Unable to allocate event request frame!\n",
-                               ioc->name));
-               return 0;
-       }
-       memset(evnp, 0, sizeof(*evnp));
+       EventNotification_t     evn;
+       MPIDefaultReply_t       reply_buf;
 
-       devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending EventNotification (%d) request %p\n", ioc->name, EvSwitch, evnp));
+       memset(&evn, 0, sizeof(EventNotification_t));
+       memset(&reply_buf, 0, sizeof(MPIDefaultReply_t));
 
-       evnp->Function = MPI_FUNCTION_EVENT_NOTIFICATION;
-       evnp->ChainOffset = 0;
-       evnp->MsgFlags = 0;
-       evnp->Switch = EvSwitch;
+       evn.Function = MPI_FUNCTION_EVENT_NOTIFICATION;
+       evn.Switch = EvSwitch;
+       evn.MsgContext = cpu_to_le32(mpt_base_index << 16);
 
-       mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)evnp);
+       devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+           "Sending EventNotification (%d) request %p\n",
+           ioc->name, EvSwitch, &evn));
 
-       return 0;
+       return mpt_handshake_req_reply_wait(ioc, sizeof(EventNotification_t),
+           (u32*)&evn, sizeof(MPIDefaultReply_t), (u16*)&reply_buf, 30,
+           sleepFlag);
 }
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *     SendEventAck - Send EventAck request to MPT adapter.
  *     @ioc: Pointer to MPT_ADAPTER structure
  *     @evnp: Pointer to original EventNotification request
- */
+ **/
 static int
 SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp)
 {
@@ -5717,7 +6207,6 @@ SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp)
        return 0;
 }
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *     mpt_config - Generic function to issue config message
  *     @ioc:   Pointer to an adapter structure
@@ -5730,35 +6219,62 @@ SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp)
  *     -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;
+       ConfigReply_t   *pReply;
        ConfigExtendedPageHeader_t  *pExtHdr = NULL;
        MPT_FRAME_HDR   *mf;
-       unsigned long    flags;
-       int              ii, rc;
+       int              ii;
        int              flagsLength;
-       int              in_isr;
+       long             timeout;
+       int              ret;
+       u8               page_type = 0, extend_page;
+       unsigned long    timeleft;
+       unsigned long    flags;
+       u8               issue_hard_reset = 0;
+       u8               retry_count = 0;
 
-       /*      Prevent calling wait_event() (below), if caller happens
-        *      to be in ISR context, because that is fatal!
-        */
-       in_isr = in_interrupt();
-       if (in_isr) {
-               dcprintk(ioc, printk(MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",
-                               ioc->name));
+       if (in_interrupt())
                return -EPERM;
+
+       /* don't send a config page during diag reset */
+       spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
+       if (ioc->ioc_reset_in_progress) {
+               dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "%s: busy with host reset\n", ioc->name, __FUNCTION__));
+               spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
+               return -EBUSY;
+       }
+       spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
+
+       /* don't send if no chance of success */
+       if (!ioc->active ||
+           mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_OPERATIONAL) {
+               dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "%s: ioc not operational, %d, %xh\n",
+                   ioc->name, __FUNCTION__, ioc->active,
+                   mpt_GetIocState(ioc, 0)));
+               return -EFAULT;
        }
 
+ retry_config:
+       mutex_lock(&ioc->mptbase_cmds.mutex);
+       /* init the internal cmd struct */
+       memset(ioc->mptbase_cmds.reply, 0 , MPT_DEFAULT_FRAME_SIZE);
+       INITIALIZE_MGMT_STATUS(ioc->mptbase_cmds.status)
+
        /* Get and Populate a free Frame
         */
        if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
-               dcprintk(ioc, printk(MYIOC_s_WARN_FMT "mpt_config: no msg frames!\n",
-                               ioc->name));
-               return -EAGAIN;
+               dcprintk(ioc, printk(MYIOC_s_WARN_FMT
+               "mpt_config: no msg frames!\n", ioc->name));
+               ret = -EAGAIN;
+               goto out;
        }
+
        pReq = (Config_t *)mf;
        pReq->Action = pCfg->action;
        pReq->Reserved = 0;
@@ -5784,7 +6300,9 @@ mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
                pReq->ExtPageType = pExtHdr->ExtPageType;
                pReq->Header.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
 
-               /* Page Length must be treated as a reserved field for the extended header. */
+               /* Page Length must be treated as a reserved field for the
+                * extended header.
+                */
                pReq->Header.PageLength = 0;
        }
 
@@ -5797,126 +6315,126 @@ mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
        else
                flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
 
-       if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
+       if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) ==
+           MPI_CONFIG_PAGETYPE_EXTENDED) {
                flagsLength |= pExtHdr->ExtPageLength * 4;
-
-               dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Config request type %d, page %d and action %d\n",
-                       ioc->name, pReq->ExtPageType, pReq->Header.PageNumber, pReq->Action));
-       }
-       else {
+               page_type = pReq->ExtPageType;
+               extend_page = 1;
+       } else {
                flagsLength |= pCfg->cfghdr.hdr->PageLength * 4;
-
-               dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Config request type %d, page %d and action %d\n",
-                       ioc->name, pReq->Header.PageType, pReq->Header.PageNumber, pReq->Action));
+               page_type = pReq->Header.PageType;
+               extend_page = 0;
        }
 
-       ioc->add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr);
-
-       /* 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;
+       dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+           "Sending Config request type 0x%x, page 0x%x and action %d\n",
+           ioc->name, page_type, pReq->Header.PageNumber, pReq->Action));
 
-       /* Add to end of Q, set timer and then issue this command */
-       spin_lock_irqsave(&ioc->FreeQlock, flags);
-       list_add_tail(&pCfg->linkage, &ioc->configQ);
-       spin_unlock_irqrestore(&ioc->FreeQlock, flags);
-
-       add_timer(&pCfg->timer);
+       ioc->add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr);
+       timeout = (pCfg->timeout < 15) ? HZ*15 : HZ*pCfg->timeout;
        mpt_put_msg_frame(mpt_base_index, ioc, mf);
-       wait_event(mpt_waitq, pCfg->wait_done);
-
-       /* mf has been freed - do not access */
-
-       rc = pCfg->status;
+       timeleft = wait_for_completion_timeout(&ioc->mptbase_cmds.done, timeout);
+       if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
+               ret = -ETIME;
+               dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "Failed Sending Config request type 0x%x, page 0x%x,"
+                   " action %d, status %xh, time left %ld\n\n",
+                       ioc->name, page_type, pReq->Header.PageNumber,
+                       pReq->Action, ioc->mptbase_cmds.status, timeleft));
+               if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
+                       goto out;
+               if (!timeleft)
+                       issue_hard_reset = 1;
+               goto out;
+       }
 
-       return rc;
-}
+       if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
+               ret = -1;
+               goto out;
+       }
+       pReply = (ConfigReply_t *)ioc->mptbase_cmds.reply;
+       ret = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
+       if (ret == MPI_IOCSTATUS_SUCCESS) {
+               if (extend_page) {
+                       pCfg->cfghdr.ehdr->ExtPageLength =
+                           le16_to_cpu(pReply->ExtPageLength);
+                       pCfg->cfghdr.ehdr->ExtPageType =
+                           pReply->ExtPageType;
+               }
+               pCfg->cfghdr.hdr->PageVersion = pReply->Header.PageVersion;
+               pCfg->cfghdr.hdr->PageLength = pReply->Header.PageLength;
+               pCfg->cfghdr.hdr->PageNumber = pReply->Header.PageNumber;
+               pCfg->cfghdr.hdr->PageType = pReply->Header.PageType;
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/**
- *     mpt_timer_expired - Callback 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;
+       }
 
-       dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_timer_expired! \n", ioc->name));
+       if (retry_count)
+               printk(MYIOC_s_INFO_FMT "Retry completed ret=0x%x timeleft=%ld\n",
+                   ioc->name, ret, timeleft);
 
-       /* Perform a FW reload */
-       if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0)
-               printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", ioc->name);
+       dcprintk(ioc, printk(KERN_DEBUG "IOCStatus=%04xh, IOCLogInfo=%08xh\n",
+            ret, le32_to_cpu(pReply->IOCLogInfo)));
 
-       /* No more processing.
-        * Hard reset clean-up will wake up
-        * process and free all resources.
-        */
-       dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_timer_expired complete!\n", ioc->name));
+ out:
 
-       return;
+       CLEAR_MGMT_STATUS(ioc->mptbase_cmds.status)
+       mutex_unlock(&ioc->mptbase_cmds.mutex);
+       if (issue_hard_reset) {
+               issue_hard_reset = 0;
+               printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
+                   ioc->name, __FUNCTION__);
+               if (mpt_SoftResetHandler(ioc, CAN_SLEEP) != 0)
+                       mpt_HardResetHandler(ioc, CAN_SLEEP);
+               mpt_free_msg_frame(ioc, mf);
+               /* attempt one retry for a timed out command */
+               if (!retry_count) {
+                       printk(MYIOC_s_INFO_FMT
+                           "Attempting Retry Config request type 0x%x, page 0x%x,"
+                           " action %d\n", ioc->name, page_type,
+                           pCfg->cfghdr.hdr->PageNumber, pCfg->action);
+                       retry_count++;
+                       goto retry_config;
+               }
+       }
+       return ret;
 }
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *     mpt_ioc_reset - Base cleanup for hard reset
  *     @ioc: Pointer to the adapter structure
  *     @reset_phase: Indicates pre- or post-reset functionality
  *
  *     Remark: Frees resources with internally generated commands.
- */
+ **/
 static int
 mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
 {
-       CONFIGPARMS *pCfg;
-       unsigned long flags;
-
-       dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
-           ": IOC %s_reset routed to MPT base driver!\n",
-           ioc->name, reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
-           reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
-
-       if (reset_phase == MPT_IOC_SETUP_RESET) {
-               ;
-       } else 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);
-               list_for_each_entry(pCfg, &ioc->configQ, linkage)
-                       del_timer(&pCfg->timer);
-               spin_unlock_irqrestore(&ioc->FreeQlock, flags);
-
-       } else {
-               CONFIGPARMS *pNext;
-
-               /* Search the configQ for internal commands.
-                * Flush the Q, and wake up all suspended threads.
-                */
-               spin_lock_irqsave(&ioc->FreeQlock, flags);
-               list_for_each_entry_safe(pCfg, pNext, &ioc->configQ, linkage) {
-                       list_del(&pCfg->linkage);
-
-                       pCfg->status = MPT_CONFIG_ERROR;
-                       pCfg->wait_done = 1;
-                       wake_up(&mpt_waitq);
+       switch(reset_phase) {
+       case MPT_IOC_SETUP_RESET:
+               dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __FUNCTION__));
+               ioc->taskmgmt_quiesce_io = 1;
+               break;
+       case MPT_IOC_PRE_RESET:
+               dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "%s: MPT_IOC_PRE_RESET\n", ioc->name, __FUNCTION__));
+               break;
+       case MPT_IOC_POST_RESET:
+               dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "%s: MPT_IOC_POST_RESET\n",  ioc->name, __FUNCTION__));
+/* wake up mptbase_cmds */
+               if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_PENDING) {
+                       ioc->mptbase_cmds.status |= MPT_MGMT_STATUS_DID_IOCRESET;
+                       complete(&ioc->mptbase_cmds.done);
                }
-               spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+/* wake up taskmgmt_cmds */
+               if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) {
+                       ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_DID_IOCRESET;
+                       complete(&ioc->taskmgmt_cmds.done);
+               }
+               break;
+       default:
+               break;
        }
 
        return 1;               /* currently means nothing really */
@@ -5924,16 +6442,11 @@ mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
 
 
 #ifdef CONFIG_PROC_FS          /* { */
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*
- *     procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff...
- */
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *     procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries.
  *
  *     Returns 0 for success, non-zero for failure.
- */
+ **/
 static int
 procmpt_create(void)
 {
@@ -5954,12 +6467,11 @@ procmpt_create(void)
        return 0;
 }
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *     procmpt_destroy - Tear down %MPT_PROCFS_MPTBASEDIR entries.
  *
  *     Returns 0 for success, non-zero for failure.
- */
+ **/
 static void
 procmpt_destroy(void)
 {
@@ -5968,7 +6480,6 @@ procmpt_destroy(void)
        remove_proc_entry(MPT_PROCFS_MPTBASEDIR, NULL);
 }
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *     procmpt_summary_read - Handle read request of a summary file
  *     @buf: Pointer to area to write information
@@ -5980,7 +6491,7 @@ procmpt_destroy(void)
  *
  *     Handles read request from /proc/mpt/summary or /proc/mpt/iocN/summary.
  *     Returns number of characters written to process performing the read.
- */
+ **/
 static int
 procmpt_summary_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
 {
@@ -6012,7 +6523,6 @@ procmpt_summary_read(char *buf, char **start, off_t offset, int request, int *eo
        MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
 }
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *     procmpt_version_read - Handle read request from /proc/mpt/version.
  *     @buf: Pointer to area to write information
@@ -6023,7 +6533,7 @@ procmpt_summary_read(char *buf, char **start, off_t offset, int request, int *eo
  *     @data: Pointer
  *
  *     Returns number of characters written to process performing the read.
- */
+ **/
 static int
 procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
 {
@@ -6068,7 +6578,6 @@ procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eo
        MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
 }
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *     procmpt_iocinfo_read - Handle read request from /proc/mpt/iocN/info.
  *     @buf: Pointer to area to write information
@@ -6079,7 +6588,7 @@ procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eo
  *     @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)
 {
@@ -6165,7 +6674,6 @@ procmpt_iocinfo_read(char *buf, char **start, off_t offset, int request, int *eo
 
 #endif         /* CONFIG_PROC_FS } */
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 static void
 mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc)
 {
@@ -6181,7 +6689,6 @@ mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc)
        }
 }
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *     mpt_print_ioc_summary - Write ASCII summary of IOC to a buffer.
  *     @ioc: Pointer to MPT_ADAPTER structure
@@ -6192,7 +6699,7 @@ mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc)
  *
  *     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)
 {
@@ -6233,6 +6740,217 @@ mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int sh
 /*
  *     Reset Handling
  */
+
+/**
+ *     mpt_set_taskmgmt_in_progress_flag - set flags associated with task managment
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *
+ *     Returns 0 for SUCCESS or -1 if FAILED.
+ *
+ *     If -1 is return, then it was not possible to set the flags
+ **/
+int
+mpt_set_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc)
+{
+       unsigned long    flags;
+       int              retval;
+
+       spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
+       if (ioc->ioc_reset_in_progress || ioc->taskmgmt_in_progress ||
+           (ioc->alt_ioc && ioc->alt_ioc->taskmgmt_in_progress)) {
+               retval = -1;
+               spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
+               goto out;
+       }
+       retval = 0;
+       ioc->taskmgmt_in_progress = 1;
+       ioc->taskmgmt_quiesce_io = 1;
+       if (ioc->alt_ioc) {
+               ioc->alt_ioc->taskmgmt_in_progress = 1;
+               ioc->alt_ioc->taskmgmt_quiesce_io = 1;
+       }
+       spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
+
+ out:
+       return retval;
+}
+
+/**
+ *     mpt_clear_taskmgmt_in_progress_flag - clear flags associated with task managment
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *
+ **/
+void
+mpt_clear_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc)
+{
+       unsigned long    flags;
+
+       spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
+       ioc->taskmgmt_in_progress = 0;
+       ioc->taskmgmt_quiesce_io = 0;
+       if (ioc->alt_ioc) {
+               ioc->alt_ioc->taskmgmt_in_progress = 0;
+               ioc->alt_ioc->taskmgmt_quiesce_io = 0;
+       }
+       spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
+}
+
+/**
+ *     mpt_halt_firmware - Halts the firmware if it is operational and panic
+ *     the kernel
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *
+ **/
+void
+mpt_halt_firmware(MPT_ADAPTER *ioc)
+{
+       u32      ioc_raw_state;
+       
+       ioc_raw_state = mpt_GetIocState(ioc, 0);
+       
+       if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
+               printk(MYIOC_s_ERR_FMT "IOC is in FAULT state (%04xh)!!!\n",
+                       ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK);
+               if(mpt_fwfault_debug == 2) 
+                       for(;;);
+               else
+                       panic("%s: IOC Fault (%04xh)!!!\n",ioc->name,
+                               ioc_raw_state & MPI_DOORBELL_DATA_MASK);
+       } else {
+               CHIPREG_WRITE32(&ioc->chip->Doorbell, 0xC0FFEE00);
+               if(mpt_fwfault_debug == 2) {
+                       printk("%s: Firmware is halted due to command timeout\n" 
+                                       ,ioc->name);
+                       for(;;);
+               }
+               else
+                       panic("%s: Firmware is halted due to command timeout\n",
+                                       ioc->name);
+       }
+}
+
+/**
+ *     mpt_SoftResetHandler - Issues a less expensive reset
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @sleepFlag: Indicates if sleep or schedule must be called.
+
+ *
+ *     Returns 0 for SUCCESS or -1 if FAILED.
+ *
+ *     Message Unit Reset - instructs the IOC to reset the Reply Post and
+ *     Free FIFO's. All the Message Frames on Reply Free FIFO are discarded.
+ *     All posted buffers are freed, and event notification is turned off.
+ *     IOC doesnt reply to any outstanding request. This will transfer IOC
+ *     to READY state.
+ **/
+int
+mpt_SoftResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
+{
+       int              rc;
+       int              ii;
+       u8               cb_idx;
+       unsigned long    flags;
+       u32              ioc_state;
+       unsigned long    time_count;
+
+       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SoftResetHandler Entered!\n", ioc->name));
+
+       ioc_state = mpt_GetIocState(ioc, 0) & MPI_IOC_STATE_MASK;
+
+       if(mpt_fwfault_debug)
+               mpt_halt_firmware(ioc);
+
+       if (ioc_state == MPI_IOC_STATE_FAULT || ioc_state == MPI_IOC_STATE_RESET) {
+               dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "skipping, either in FAULT or RESET state!\n", ioc->name));
+               return -1;
+       }
+
+       spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
+       if (ioc->ioc_reset_in_progress) {
+               spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
+               return -1;
+       }
+       ioc->ioc_reset_in_progress = 1;
+       spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
+
+       rc = -1;
+
+       for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
+               if (MptResetHandlers[cb_idx])
+                       mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET);
+       }
+
+       for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
+               if (MptResetHandlers[cb_idx])
+                       mpt_signal_reset(cb_idx, ioc, MPT_IOC_PRE_RESET);
+       }
+
+       /* Disable reply interrupts (also blocks FreeQ) */
+       CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
+       ioc->active = 0;
+       time_count = jiffies;
+       if ((rc = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET,
+           sleepFlag)) != 0)
+               goto out;
+       ioc_state = mpt_GetIocState(ioc, 0) & MPI_IOC_STATE_MASK;
+       if (ioc_state != MPI_IOC_STATE_READY)
+               goto out;
+
+       for (ii = 0; ii < 5; ii++) {
+               /* Get IOC facts! Allow 5 retries */
+               if ((rc = GetIocFacts(ioc, sleepFlag,
+                           MPT_HOSTEVENT_IOC_RECOVER)) == 0)
+                       break;
+               if (sleepFlag == CAN_SLEEP) {
+                       msleep(100);
+               } else {
+                       mdelay(100);
+               }
+       }
+       if (ii == 5)
+               goto out;
+
+       if ((rc = PrimeIocFifos(ioc)) != 0)
+               goto out;
+
+       if ((rc = SendIocInit(ioc, sleepFlag)) != 0)
+               goto out;
+
+       if ((rc = SendEventNotification(ioc, 1, sleepFlag)) != 0)
+               goto out;
+
+       if (ioc->hard_resets < -1)
+               ioc->hard_resets++;
+
+       /*
+        * At this point, we know soft reset succeeded.
+        */
+
+       ioc->active = 1;
+       CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
+
+ out:
+       spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
+       ioc->ioc_reset_in_progress = 0;
+       ioc->taskmgmt_quiesce_io = 0;
+       ioc->taskmgmt_in_progress = 0;
+       spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
+
+       if (ioc->active) {      /* otherwise, hard reset coming */
+               for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
+                       if (MptResetHandlers[cb_idx])
+                               mpt_signal_reset(cb_idx, ioc, MPT_IOC_POST_RESET);
+               }
+       }
+
+       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SoftResetHandler: completed (%d seconds): %s\n",
+           ioc->name, jiffies_to_msecs(jiffies - time_count)/1000,
+           ((rc == 0) ? "SUCCESS" : "FAILED")));
+
+       return rc;
+}
+
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *     mpt_HardResetHandler - Generic reset handler
@@ -6249,12 +6967,14 @@ mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int sh
  *     FW reload/initialization failed.
  *
  *     Returns 0 for SUCCESS or -1 if FAILED.
- */
+ **/
 int
 mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
 {
-       int              rc;
+       int      rc;
+       u8       cb_idx;
        unsigned long    flags;
+       unsigned long    time_count;
 
        dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler Entered!\n", ioc->name));
 #ifdef MFCNT
@@ -6262,67 +6982,82 @@ mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
        printk("MF count 0x%x !\n", ioc->mfcnt);
 #endif
 
+       if(mpt_fwfault_debug)
+               mpt_halt_firmware(ioc);
+
        /* 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);
+       spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
+       if (ioc->ioc_reset_in_progress) {
+               spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
                return 0;
-       } else {
-               ioc->diagPending = 1;
        }
-       spin_unlock_irqrestore(&ioc->diagLock, flags);
+       ioc->ioc_reset_in_progress = 1;
+       if (ioc->alt_ioc)
+           ioc->alt_ioc->ioc_reset_in_progress = 1;
+       spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
 
-       /* FIXME: If do_ioc_recovery fails, repeat....
-        */
 
        /* The SCSI driver needs to adjust timeouts on all current
         * commands prior to the diagnostic reset being issued.
         * Prevents timeouts occurring during a diagnostic reset...very bad.
         * For all other protocol drivers, this is a no-op.
         */
-       {
-               u8       cb_idx;
-               int      r = 0;
-
-               for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
-                       if (MptResetHandlers[cb_idx]) {
-                               dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling IOC reset_setup handler #%d\n",
-                                               ioc->name, cb_idx));
-                               r += mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET);
-                               if (ioc->alt_ioc) {
-                                       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling alt-%s setup reset handler #%d\n",
-                                                       ioc->name, ioc->alt_ioc->name, cb_idx));
-                                       r += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_SETUP_RESET);
-                               }
-                       }
+       for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
+               if (MptResetHandlers[cb_idx]) {
+                       mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET);
+                       if (ioc->alt_ioc)
+                               mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_SETUP_RESET);
                }
        }
 
+       time_count = jiffies;
        if ((rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag)) != 0) {
-               printk(MYIOC_s_WARN_FMT "Cannot recover rc = %d!\n", ioc->name, rc);
+               printk(KERN_WARNING MYNAM ": WARNING - (%d) Cannot recover %s\n",
+                       rc, ioc->name);
+       } else {
+               if (ioc->hard_resets < -1)
+                       ioc->hard_resets++;
        }
-       ioc->reload_fw = 0;
-       if (ioc->alt_ioc)
-               ioc->alt_ioc->reload_fw = 0;
 
-       spin_lock_irqsave(&ioc->diagLock, flags);
-       ioc->diagPending = 0;
-       if (ioc->alt_ioc)
-               ioc->alt_ioc->diagPending = 0;
-       spin_unlock_irqrestore(&ioc->diagLock, flags);
+       spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
+       ioc->ioc_reset_in_progress = 0;
+       ioc->taskmgmt_quiesce_io = 0;
+       ioc->taskmgmt_in_progress = 0;
+       if (ioc->alt_ioc) {
+           ioc->alt_ioc->ioc_reset_in_progress = 0;
+           ioc->alt_ioc->taskmgmt_quiesce_io = 0;
+           ioc->alt_ioc->taskmgmt_in_progress = 0;
+       }
+       spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
 
-       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler rc = %d!\n", ioc->name, rc));
+       for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
+               if (MptResetHandlers[cb_idx]) {
+                       mpt_signal_reset(cb_idx, ioc, MPT_IOC_POST_RESET);
+                       if (ioc->alt_ioc)
+                               mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_POST_RESET);
+               }
+       }
 
+       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler: completed (%d seconds): %s\n",
+           ioc->name, jiffies_to_msecs(jiffies - time_count)/1000,
+           ((rc == 0) ? "SUCCESS" : "FAILED")));
        return rc;
 }
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+#ifdef CONFIG_FUSION_LOGGING
 static void
-EventDescriptionStr(u8 event, u32 evData0, char *evStr)
+mpt_display_event_info(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply)
 {
        char *ds = NULL;
+       u32 evData0;
+       int ii;
+       u8 event;
+       char *evStr = ioc->evStr;
+
+       event = le32_to_cpu(pEventReply->Event) & 0xFF;
+       evData0 = le32_to_cpu(pEventReply->Data[0]);
 
        switch(event) {
        case MPI_EVENT_NONE:
@@ -6356,9 +7091,9 @@ EventDescriptionStr(u8 event, u32 evData0, char *evStr)
                if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP)
                        ds = "Loop State(LIP) Change";
                else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE)
-                       ds = "Loop State(LPE) Change";          /* ??? */
+                       ds = "Loop State(LPE) Change";
                else
-                       ds = "Loop State(LPB) Change";          /* ??? */
+                       ds = "Loop State(LPB) Change";
                break;
        case MPI_EVENT_LOGOUT:
                ds = "Logout";
@@ -6474,6 +7209,11 @@ EventDescriptionStr(u8 event, u32 evData0, char *evStr)
                            "SAS Device Status Change: Internal Query "
                            "Task : id=%d channel=%d", id, channel);
                        break;
+               case MPI_EVENT_SAS_DEV_STAT_RC_ASYNC_NOTIFICATION:
+                       snprintf(evStr, EVENT_DESCR_STR_SZ,
+                           "SAS Device Status Change: Async Notification "
+                           "Task : id=%d channel=%d", id, channel);
+                       break;
                default:
                        snprintf(evStr, EVENT_DESCR_STR_SZ,
                            "SAS Device Status Change: Unknown: "
@@ -6558,28 +7298,65 @@ EventDescriptionStr(u8 event, u32 evData0, char *evStr)
        }
        case MPI_EVENT_IR2:
        {
+               u8 id = (u8)(evData0);
+               u8 channel = (u8)(evData0 >> 8);
+               u8 phys_num = (u8)(evData0 >> 24);
                u8 ReasonCode = (u8)(evData0 >> 16);
+
                switch (ReasonCode) {
                case MPI_EVENT_IR2_RC_LD_STATE_CHANGED:
-                       ds = "IR2: LD State Changed";
+                       snprintf(evStr, EVENT_DESCR_STR_SZ,
+                           "IR2: LD State Changed: "
+                           "id=%d channel=%d phys_num=%d",
+                           id, channel, phys_num);
                        break;
                case MPI_EVENT_IR2_RC_PD_STATE_CHANGED:
-                       ds = "IR2: PD State Changed";
+                       snprintf(evStr, EVENT_DESCR_STR_SZ,
+                           "IR2: PD State Changed "
+                           "id=%d channel=%d phys_num=%d",
+                           id, channel, phys_num);
                        break;
                case MPI_EVENT_IR2_RC_BAD_BLOCK_TABLE_FULL:
-                       ds = "IR2: Bad Block Table Full";
+                       snprintf(evStr, EVENT_DESCR_STR_SZ,
+                           "IR2: Bad Block Table Full: "
+                           "id=%d channel=%d phys_num=%d",
+                           id, channel, phys_num);
                        break;
                case MPI_EVENT_IR2_RC_PD_INSERTED:
-                       ds = "IR2: PD Inserted";
+                       snprintf(evStr, EVENT_DESCR_STR_SZ,
+                           "IR2: PD Inserted: "
+                           "id=%d channel=%d phys_num=%d",
+                           id, channel, phys_num);
                        break;
                case MPI_EVENT_IR2_RC_PD_REMOVED:
-                       ds = "IR2: PD Removed";
+                       snprintf(evStr, EVENT_DESCR_STR_SZ,
+                           "IR2: PD Removed: "
+                           "id=%d channel=%d phys_num=%d",
+                           id, channel, phys_num);
                        break;
                case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
-                       ds = "IR2: Foreign CFG Detected";
+                       snprintf(evStr, EVENT_DESCR_STR_SZ,
+                           "IR2: Foreign CFG Detected: "
+                           "id=%d channel=%d phys_num=%d",
+                           id, channel, phys_num);
                        break;
                case MPI_EVENT_IR2_RC_REBUILD_MEDIUM_ERROR:
-                       ds = "IR2: Rebuild Medium Error";
+                       snprintf(evStr, EVENT_DESCR_STR_SZ,
+                           "IR2: Rebuild Medium Error: "
+                           "id=%d channel=%d phys_num=%d",
+                           id, channel, phys_num);
+                       break;
+               case MPI_EVENT_IR2_RC_DUAL_PORT_ADDED:
+                       snprintf(evStr, EVENT_DESCR_STR_SZ,
+                           "IR2: Dual Port Added: "
+                           "id=%d channel=%d phys_num=%d",
+                           id, channel, phys_num);
+                       break;
+               case MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED:
+                       snprintf(evStr, EVENT_DESCR_STR_SZ,
+                           "IR2: Dual Port Removed: "
+                           "id=%d channel=%d phys_num=%d",
+                           id, channel, phys_num);
                        break;
                default:
                        ds = "IR2";
@@ -6603,25 +7380,46 @@ EventDescriptionStr(u8 event, u32 evData0, char *evStr)
        {
                u8 phy_num = (u8)(evData0);
                u8 port_num = (u8)(evData0 >> 8);
-               u8 port_width = (u8)(evData0 >> 16);
+               u8 num_phys = (u8)(evData0 >> 16);
                u8 primative = (u8)(evData0 >> 24);
+               char *primative_str = NULL;
+
+               switch (primative) {
+               case MPI_EVENT_PRIMITIVE_CHANGE:
+                       primative_str = "change";
+                       break;
+               case MPI_EVENT_PRIMITIVE_EXPANDER:
+                       primative_str = "expander";
+                       break;
+               case MPI_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT:
+                       primative_str = "asyn event";
+                       break;
+               default:
+                       primative_str = "reserved";
+                       break;
+               }
                snprintf(evStr, EVENT_DESCR_STR_SZ,
-                   "SAS Broadcase Primative: phy=%d port=%d "
-                   "width=%d primative=0x%02x",
-                   phy_num, port_num, port_width, primative);
+                   "SAS Broadcast Primative: phy=%d port=%d "
+                   "num_phys=%d primative=%s (0x%02x)",
+                   phy_num, port_num, num_phys, primative_str, primative);
                break;
        }
 
        case MPI_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE:
        {
                u8 reason = (u8)(evData0);
-               u8 port_num = (u8)(evData0 >> 8);
-               u16 handle = le16_to_cpu(evData0 >> 16);
 
-               snprintf(evStr, EVENT_DESCR_STR_SZ,
-                   "SAS Initiator Device Status Change: reason=0x%02x "
-                   "port=%d handle=0x%04x",
-                   reason, port_num, handle);
+               switch (reason) {
+               case MPI_EVENT_SAS_INIT_RC_ADDED:
+                       ds = "SAS Initiator Status Change: Added";
+                       break;
+               case MPI_EVENT_SAS_INIT_RC_REMOVED:
+                       ds = "SAS Initiator Status Change: Deleted";
+                       break;
+               default:
+                       ds = "SAS Initiator Status Change";
+                       break;
+               }
                break;
        }
 
@@ -6669,6 +7467,24 @@ EventDescriptionStr(u8 event, u32 evData0, char *evStr)
                break;
        }
 
+       case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE:
+       {
+               u8 reason = (u8)(evData0);
+
+               switch (reason) {
+               case MPI_EVENT_SAS_EXP_RC_ADDED:
+                       ds = "Expander Status Change: Added";
+                       break;
+               case MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING:
+                       ds = "Expander Status Change: Deleted";
+                       break;
+               default:
+                       ds = "Expander Status Change";
+                       break;
+               }
+               break;
+       }
+
        /*
         *  MPT base "custom" events may be added here...
         */
@@ -6678,9 +7494,21 @@ EventDescriptionStr(u8 event, u32 evData0, char *evStr)
        }
        if (ds)
                strncpy(evStr, ds, EVENT_DESCR_STR_SZ);
+
+
+       devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+           "MPT event:(%02Xh) : %s\n",
+           ioc->name, event, evStr));
+
+       devtverboseprintk(ioc, printk(KERN_DEBUG MYNAM
+           ": Event data:\n"));
+       for (ii = 0; ii < le16_to_cpu(pEventReply->EventDataLength); ii++)
+               devtverboseprintk(ioc, printk(" %08x",
+                   le32_to_cpu(pEventReply->Data[ii])));
+       devtverboseprintk(ioc, printk(KERN_DEBUG "\n"));
 }
+#endif
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *     ProcessEventNotification - Route EventNotificationReply to all event handlers
  *     @ioc: Pointer to MPT_ADAPTER structure
@@ -6690,43 +7518,30 @@ EventDescriptionStr(u8 event, u32 evData0, char *evStr)
  *     Routes a received EventNotificationReply to all currently registered
  *     event handlers.
  *     Returns sum of event handlers return values.
- */
+ **/
 static int
 ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply, int *evHandlers)
 {
        u16 evDataLen;
        u32 evData0 = 0;
-//     u32 evCtx;
        int ii;
        u8 cb_idx;
        int r = 0;
        int handlers = 0;
-       char evStr[EVENT_DESCR_STR_SZ];
        u8 event;
 
+
        /*
         *  Do platform normalization of values
         */
        event = le32_to_cpu(pEventReply->Event) & 0xFF;
-//     evCtx = le32_to_cpu(pEventReply->EventContext);
        evDataLen = le16_to_cpu(pEventReply->EventDataLength);
-       if (evDataLen) {
+       if (evDataLen)
                evData0 = le32_to_cpu(pEventReply->Data[0]);
-       }
-
-       EventDescriptionStr(event, evData0, evStr);
-       devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MPT event:(%02Xh) : %s\n",
-                       ioc->name,
-                       event,
-                       evStr));
 
 #ifdef CONFIG_FUSION_LOGGING
-       devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
-           ": Event data:\n", ioc->name));
-       for (ii = 0; ii < evDataLen; ii++)
-               devtverboseprintk(ioc, printk(" %08x",
-                   le32_to_cpu(pEventReply->Data[ii])));
-       devtverboseprintk(ioc, printk("\n"));
+       if (evDataLen)
+               mpt_display_event_info(ioc, pEventReply);
 #endif
 
        /*
@@ -6781,8 +7596,8 @@ ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply
         */
        for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
                if (MptEvHandlers[cb_idx]) {
-                       devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Routing Event to event handler #%d\n",
-                                       ioc->name, cb_idx));
+                       devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT 
+                           "Routing Event to event handler #%d\n", ioc->name, cb_idx));
                        r += (*(MptEvHandlers[cb_idx]))(ioc, pEventReply);
                        handlers++;
                }
@@ -6849,7 +7664,6 @@ mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info)
                        ioc->name, log_info, desc, (log_info & 0xFFFFFF));
 }
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *     mpt_spi_log_info - Log information returned from SCSI Parallel IOC.
  *     @ioc: Pointer to MPT_ADAPTER structure
@@ -6857,7 +7671,7 @@ mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info)
  *     @log_info: U32 LogInfo word from the IOC
  *
  *     Refer to lsi/sp_log.h.
- */
+ **/
 static void
 mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info)
 {
@@ -6867,8 +7681,6 @@ mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info)
        switch (info) {
        case 0x00010000:
                desc = "bug! MID not found";
-               if (ioc->reload_fw == 0)
-                       ioc->reload_fw++;
                break;
 
        case 0x00020000:
@@ -7063,7 +7875,6 @@ mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info)
                "Compatibility Error: IME Size Limited to < 2TB", /* 3Dh */
        };
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *     mpt_sas_log_info - Log information returned from SAS IOC.
  *     @ioc: Pointer to MPT_ADAPTER structure
@@ -7143,7 +7954,6 @@ union loginfo_type {
                        sas_loginfo.dw.code, sas_loginfo.dw.subcode);
 }
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *     mpt_iocstatus_info_config - IOCSTATUS information for config pages
  *     @ioc: Pointer to MPT_ADAPTER structure
@@ -7445,8 +8255,7 @@ mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
        if (!desc)
                return;
 
-       dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s\n",
-           ioc->name, status, desc));
+       dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s\n", ioc->name, status, desc));
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -7475,19 +8284,24 @@ EXPORT_SYMBOL(mpt_verify_adapter);
 EXPORT_SYMBOL(mpt_GetIocState);
 EXPORT_SYMBOL(mpt_print_ioc_summary);
 EXPORT_SYMBOL(mpt_HardResetHandler);
+EXPORT_SYMBOL(mpt_SoftResetHandler);
 EXPORT_SYMBOL(mpt_config);
 EXPORT_SYMBOL(mpt_findImVolumes);
 EXPORT_SYMBOL(mpt_alloc_fw_memory);
 EXPORT_SYMBOL(mpt_free_fw_memory);
 EXPORT_SYMBOL(mptbase_sas_persist_operation);
 EXPORT_SYMBOL(mpt_raid_phys_disk_pg0);
+EXPORT_SYMBOL(mpt_raid_phys_disk_pg1);
+EXPORT_SYMBOL(mpt_raid_phys_disk_get_num_paths);
+EXPORT_SYMBOL(mpt_set_taskmgmt_in_progress_flag);
+EXPORT_SYMBOL(mpt_clear_taskmgmt_in_progress_flag);
+EXPORT_SYMBOL(mpt_halt_firmware);
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *     fusion_init - Fusion MPT base driver initialization routine.
  *
  *     Returns 0 for success, non-zero for failure.
- */
+ **/
 static int __init
 fusion_init(void)
 {
@@ -7506,7 +8320,7 @@ fusion_init(void)
        /*  Register ourselves (mptbase) in order to facilitate
         *  EventNotification handling.
         */
-       mpt_base_index = mpt_register(mpt_base_reply, MPTBASE_DRIVER);
+       mpt_base_index = mpt_register(mptbase_reply, MPTBASE_DRIVER);
 
        /* Register for hard reset handling callbacks.
         */
@@ -7518,17 +8332,15 @@ fusion_init(void)
        return 0;
 }
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *     fusion_exit - Perform driver unload cleanup.
  *
  *     This routine frees all resources associated with each MPT adapter
  *     and removes all %MPT_PROCFS_MPTBASEDIR entries.
- */
+ **/
 static void __exit
 fusion_exit(void)
 {
-
        mpt_reset_deregister(mpt_base_index);
 
 #ifdef CONFIG_PROC_FS
index d6d7c6f6c7d6d544986d7dcee43b6dbb28b509f2..fd31bb0b73bc6caaa2d01312879ac6fbce6b04e7 100644 (file)
@@ -49,9 +49,6 @@
 #define MPTBASE_H_INCLUDED
 /*{-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 
-#include <linux/kernel.h>
-#include <linux/pci.h>
-
 #include "lsi/mpi_type.h"
 #include "lsi/mpi.h"           /* Fusion MPI(nterface) basic defs */
 #include "lsi/mpi_ioc.h"       /* Fusion MPT IOC(ontroller) defs */
 #define COPYRIGHT      "Copyright (c) 1999-2007 " MODULEAUTHOR
 #endif
 
-#define MPT_LINUX_VERSION_COMMON       "3.04.05"
-#define MPT_LINUX_PACKAGE_NAME         "@(#)mptlinux-3.04.05"
+#define MPT_LINUX_VERSION_COMMON       "4.00.38.02"
+#define MPT_LINUX_PACKAGE_NAME         "@(#)mptlinux-4.00.38.02"
 #define WHAT_MAGIC_STRING              "@" "(" "#" ")"
+#define MPT_LINUX_MAJOR_VERSION                4
+#define MPT_LINUX_MINOR_VERSION                00
+#define MPT_LINUX_BUILD_VERSION                38
+#define MPT_LINUX_RELEASE_VERSION      02
 
 #define show_mptmod_ver(s,ver)  \
        printk(KERN_INFO "%s %s\n", s, ver);
@@ -86,6 +87,8 @@
 /*
  *  Fusion MPT(linux) driver configurable stuff...
  */
+#define MPT_POLLING_INTERVAL           1000    /* in milliseconds */
+
 #define MPT_MAX_ADAPTERS               18
 #define MPT_MAX_PROTOCOL_DRIVERS       16
 #define MPT_MAX_BUS                    1       /* Do not change */
 
 #define MPT_COALESCING_TIMEOUT         0x10
 
-#define MPT_DMA_35BIT_MASK             0x00000007ffffffffULL
+#define MPT_DMA_35BIT_MASK  0x00000007ffffffffULL
 
 /*
  * SCSI transfer rate defines.
 #define MPT_SCSI_SG_DEPTH      40
 #endif
 
+#ifdef  CONFIG_FUSION_MAX_FC_SGE
+#if     CONFIG_FUSION_MAX_FC_SGE  < 16
+#define MPT_SCSI_FC_SG_DEPTH   16
+#elif   CONFIG_FUSION_MAX_FC_SGE  > 256
+#define MPT_SCSI_FC_SG_DEPTH   256
+#else
+#define MPT_SCSI_FC_SG_DEPTH   CONFIG_FUSION_MAX_FC_SGE
+#endif
+#else
+#define MPT_SCSI_FC_SG_DEPTH   40
+#endif
+
 /* debug print string length used for events and iocstatus */
-# define EVENT_DESCR_STR_SZ             100
+# define EVENT_DESCR_STR_SZ            100
+
 
 #ifdef __KERNEL__      /* { */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -223,7 +239,6 @@ typedef struct _ATTO_CONFIG_PAGE_SCSI_PORT_2
 } fATTO_CONFIG_PAGE_SCSI_PORT_2, MPI_POINTER PTR_ATTO_CONFIG_PAGE_SCSI_PORT_2,
   ATTO_SCSIPortPage2_t, MPI_POINTER pATTO_SCSIPortPage2_t;
 
-
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
  *  MPT protocol driver defs...
@@ -371,8 +386,8 @@ typedef struct _VirtTarget {
        struct scsi_target      *starget;
        u8                       tflags;
        u8                       ioc_id;
-       u8                       id;
-       u8                       channel;
+       u8                       id;            /* logical target id */
+       u8                       channel;       /* logical channel number */
        u8                       minSyncFactor; /* 0xFF is async */
        u8                       maxOffset;     /* 0 if async */
        u8                       maxWidth;      /* 0 if narrow, 1 if wide */
@@ -380,7 +395,7 @@ typedef struct _VirtTarget {
        u8                       raidVolume;    /* set, if RAID Volume */
        u8                       type;          /* byte 0 of Inquiry data */
        u8                       deleted;       /* target in process of being removed */
-       u32                      num_luns;
+       int                      num_luns;
 } VirtTarget;
 
 typedef struct _VirtDevice {
@@ -426,42 +441,33 @@ do { \
 } 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 */
+#define MPT_MGMT_STATUS_RF_VALID       0x01    /* The Reply Frame is VALID */
+#define MPT_MGMT_STATUS_COMMAND_GOOD   0x02    /* Command Status GOOD */
+#define MPT_MGMT_STATUS_PENDING                0x04    /* command is pending */
+#define MPT_MGMT_STATUS_DID_IOCRESET   0x08    /* IOC Reset occurred on the current*/
+#define MPT_MGMT_STATUS_SENSE_VALID    0x10    /* valid sense info */
+#define MPT_MGMT_STATUS_TIMER_ACTIVE   0x20    /* obsolete */
+#define MPT_MGMT_STATUS_FREE_MF                0x40    /* free the mf from complete routine */
 
-typedef struct _MPT_IOCTL {
-       struct _MPT_ADAPTER     *ioc;
-       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                       id;            /* target for reset */
-       struct mutex             ioctl_mutex;
-} MPT_IOCTL;
 
-#define MPT_SAS_MGMT_STATUS_RF_VALID   0x02    /* The Reply Frame is VALID */
-#define MPT_SAS_MGMT_STATUS_COMMAND_GOOD       0x10    /* Command Status GOOD */
-#define MPT_SAS_MGMT_STATUS_TM_FAILED  0x40    /* User TM request failed */
+#define INITIALIZE_MGMT_STATUS(status) \
+       status = MPT_MGMT_STATUS_PENDING;
+#define CLEAR_MGMT_STATUS(status) \
+       status = 0;
+#define CLEAR_MGMT_PENDING_STATUS(status) \
+       status &= ~MPT_MGMT_STATUS_PENDING;
+#define SET_MGMT_MSG_CONTEXT(msg_context, value) \
+       msg_context = value;
 
-typedef struct _MPT_SAS_MGMT {
+typedef struct _MPT_MGMT {
        struct mutex             mutex;
        struct completion        done;
        u8                       reply[MPT_DEFAULT_FRAME_SIZE]; /* reply frame data */
+       u8                       sense[MPT_SENSE_BUFFER_ALLOC];
        u8                       status;        /* current command status */
-}MPT_SAS_MGMT;
+       int                      completion_code;
+       u32                      msg_context;
+}MPT_MGMT;
 
 /*
  *  Event Structure and define
@@ -533,6 +539,7 @@ struct inactive_raid_component_info {
 typedef        struct _RaidCfgData {
        IOCPage2_t      *pIocPg2;               /* table of Raid Volumes */
        IOCPage3_t      *pIocPg3;               /* table of physical disks */
+       IOCPage6_t      *pIocPg6;               /* table of IR static data */
        struct semaphore        inactive_list_mutex;
        struct list_head        inactive_list; /* link list for physical
                                                disk that belong in
@@ -563,7 +570,7 @@ struct mptfc_rport_info
        u8              flags;
 };
 
-typedef void (*MPT_ADD_SGE)(char *addr, u32 flagslength, dma_addr_t dma_addr);
+typedef void (*MPT_ADD_SGE)(char *pAddr, u32 flagslength, dma_addr_t dma_addr);
 
 /*
  *  Adapter Structure - pci_dev specific. Maximum: MPT_MAX_ADAPTERS
@@ -574,6 +581,9 @@ typedef struct _MPT_ADAPTER
        int                      pci_irq;       /* This irq           */
        char                     name[MPT_NAME_LENGTH]; /* "iocN"             */
        char                     prod_name[MPT_NAME_LENGTH];    /* "LSIFC9x9"         */
+#ifdef CONFIG_FUSION_LOGGING
+       char                     evStr[EVENT_DESCR_STR_SZ]; /* used in mpt_display_event_info */
+#endif
        char                     board_name[16];
        char                     board_assembly[16];
        char                     board_tracer[16];
@@ -585,8 +595,8 @@ typedef struct _MPT_ADAPTER
        SYSIF_REGS __iomem      *chip;          /* == c8817000 (mmap) */
        SYSIF_REGS __iomem      *pio_chip;      /* Programmed IO (downloadboot) */
        u8                       bus_type;
-       u32                      mem_phys;      /* == f4020000 (mmap) */
-       u32                      pio_mem_phys;  /* Programmed IO (downloadboot) */
+       unsigned long            mem_phys;      /* == f4020000 (mmap) */
+       unsigned long            pio_mem_phys;  /* Programmed IO (downloadboot) */
        int                      mem_size;      /* mmap memory size */
        int                      number_of_buses;
        int                      devices_per_bus;
@@ -601,8 +611,7 @@ typedef struct _MPT_ADAPTER
        int                      reply_depth;   /* Num Allocated reply frames */
        int                      reply_sz;      /* Reply frame size */
        int                      num_chain;     /* Number of chain buffers */
-       MPT_ADD_SGE              add_sge;
-       u64                      dma_mask;
+       MPT_ADD_SGE              add_sge;       /* Pointer to add_sge function */
                /* Pool of buffers for chaining. ReqToChain
                 * and ChainToChain track index of chain buffers.
                 * ChainBuffer (DMA) virt/phys addresses.
@@ -631,29 +640,29 @@ typedef struct _MPT_ADAPTER
        dma_addr_t               sense_buf_pool_dma;
        u32                      sense_buf_low_dma;
        u8                      *HostPageBuffer; /* SAS - host page buffer support */
-       u32                     HostPageBuffer_sz;
-       dma_addr_t              HostPageBuffer_dma;
+       u32                      HostPageBuffer_sz;
+       dma_addr_t               HostPageBuffer_dma;
        int                      mtrr_reg;
        struct pci_dev          *pcidev;        /* struct pci_dev pointer */
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21))
+       int                     bars;   /* bitmask of BAR's that must be configured */
+#endif
+       int                      msi_enable;
        u8                      __iomem *memmap;        /* mmap address */
        struct Scsi_Host        *sh;            /* Scsi Host pointer */
-       SpiCfgData              spi_data;       /* Scsi config. data */
-       RaidCfgData             raid_data;      /* Raid config. data */
-       SasCfgData              sas_data;       /* Sas config. data */
-       FcCfgData               fc_data;        /* Fc config. data */
-       MPT_IOCTL               *ioctl;         /* ioctl data pointer */
+       SpiCfgData               spi_data;      /* Scsi config. data */
+       RaidCfgData              raid_data;     /* Raid config. data */
+       SasCfgData               sas_data;      /* Sas config. data */
+       FcCfgData                fc_data;       /* Fc config. data */
        struct proc_dir_entry   *ioc_dentry;
        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 */
        u8                      *cached_fw;     /* Pointer to FW */
-       dma_addr_t              cached_fw_dma;
-       struct list_head         configQ;       /* linked list of config. requests */
+       dma_addr_t               cached_fw_dma;
        int                      hs_reply_idx;
 #ifndef MFCNT
        u32                      pad0;
@@ -666,13 +675,16 @@ typedef struct _MPT_ADAPTER
        IOCFactsReply_t          facts;
        PortFactsReply_t         pfacts[2];
        FCPortPage0_t            fc_port_page0[2];
-       struct timer_list        persist_timer; /* persist table timer */
-       int                      persist_wait_done; /* persist completion flag */
-       u8                       persist_reply_frame[MPT_DEFAULT_FRAME_SIZE]; /* persist reply */
        LANPage0_t               lan_cnfg_page0;
        LANPage1_t               lan_cnfg_page1;
+#if defined(CPQ_CIM)
+       u32                      csmi_change_count;     /* count to track all IR
+                                       events for CSMI */
+       u8                       pci_slot_number; /* ioc page 1 - pci slot number */
+#endif
 
        u8                       ir_firmware; /* =1 if IR firmware detected */
+
        /*
         * Description: errata_flag_1064
         * If a PCIX read occurs within 1 or 2 cycles after the chip receives
@@ -683,14 +695,10 @@ typedef struct _MPT_ADAPTER
        int                      aen_event_read_flag; /* flag to indicate event log was read*/
        u8                       FirstWhoInit;
        u8                       upload_fw;     /* If set, do a fw upload */
-       u8                       reload_fw;     /* Force a FW Reload on next reset */
        u8                       NBShiftFactor;  /* NB Shift Factor based on Block Size (Facts)  */
-       u8                       pad1[4];
        u8                       DoneCtx;
        u8                       TaskCtx;
        u8                       InternalCtx;
-       spinlock_t               initializing_hba_lock;
-       int                      initializing_hba_lock_flag;
        struct list_head         list;
        struct net_device       *netdev;
        struct list_head         sas_topology;
@@ -698,11 +706,35 @@ typedef struct _MPT_ADAPTER
        struct mutex             sas_discovery_mutex;
        u8                       sas_discovery_runtime;
        u8                       sas_discovery_ignore_events;
-       u16                      handle;
+       u8                       sas_discovery_quiesce_io;
+       u8                       disable_hotplug_remove;
+       struct mptsas_portinfo  *hba_port_info; /* port_info object for the host */
+#if defined(CPQ_CIM)
+       struct list_head         sas_device_info_list;
+       struct semaphore         sas_device_info_mutex;
+#endif
        int                      sas_index; /* index refrencing */
-       MPT_SAS_MGMT             sas_mgmt;
+       MPT_MGMT                 sas_mgmt;
+       MPT_MGMT                 internal_cmds;
+       MPT_MGMT                 mptbase_cmds; /* for sending config pages */
+       MPT_MGMT                 taskmgmt_cmds;
+       MPT_MGMT                 ioctl_cmds;            /* ioctl data pointer */
+       spinlock_t               taskmgmt_lock; /* diagnostic reset lock */
+       int                      taskmgmt_in_progress;
+       u8                       taskmgmt_quiesce_io;
+       u8                       ioc_reset_in_progress;
+#if defined(CPQ_CIM)
+       u8                       num_ports;
+#endif
        struct work_struct       sas_persist_task;
 
+       char                     reset_work_q_name[KOBJ_NAME_LEN];
+       struct workqueue_struct *reset_work_q;
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19))
+       struct delayed_work      fault_reset_work;
+#else
+       struct work_struct       fault_reset_work;
+#endif
        struct work_struct       fc_setup_reset_work;
        struct list_head         fc_rports;
        struct work_struct       fc_lsc_work;
@@ -711,8 +743,25 @@ typedef struct _MPT_ADAPTER
        struct work_struct       fc_rescan_work;
        char                     fc_rescan_work_q_name[KOBJ_NAME_LEN];
        struct workqueue_struct *fc_rescan_work_q;
+       unsigned long             hard_resets;          /* driver forced bus resets count */
+       unsigned long             soft_resets;          /* fw/external bus resets count */
+       unsigned long             timeouts;             /* cmd timeouts */
        struct scsi_cmnd        **ScsiLookup;
        spinlock_t                scsi_lookup_lock;
+       int                       sdev_queue_depth;     /* sdev queue depth */
+       u64                       dma_mask;
+       u32                       broadcast_aen_busy;
+#if defined(DIAG_BUFFER_SUPPORT)
+       u8                      *DiagBuffer[MPI_DIAG_BUF_TYPE_COUNT];
+       u32                     DataSize[MPI_DIAG_BUF_TYPE_COUNT];
+       u32                     DiagBuffer_sz[MPI_DIAG_BUF_TYPE_COUNT];
+       dma_addr_t              DiagBuffer_dma[MPI_DIAG_BUF_TYPE_COUNT];
+       u8                      TraceLevel[MPI_DIAG_BUF_TYPE_COUNT];
+       u8                      DiagBuffer_Status[MPI_DIAG_BUF_TYPE_COUNT];
+       u32                     UniqueId[MPI_DIAG_BUF_TYPE_COUNT];
+       u32                     ExtendedType[MPI_DIAG_BUF_TYPE_COUNT];
+       u32                     ProductSpecific[MPI_DIAG_BUF_TYPE_COUNT][4];
+#endif
 } MPT_ADAPTER;
 
 /*
@@ -774,26 +823,10 @@ typedef struct _mpt_sge {
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 
-#define SCSI_STD_SENSE_BYTES    18
-#define SCSI_STD_INQUIRY_BYTES  36
-#define SCSI_MAX_INQUIRY_BYTES  96
-
 /*
  * 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)
@@ -809,13 +842,6 @@ typedef struct _MPT_LOCAL_REPLY {
 #define MPT_NVRAM_WIDE_DISABLE         (0x00100000)
 #define MPT_NVRAM_BOOT_CHOICE          (0x00200000)
 
-/* 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)
-
 typedef enum {
        FC,
        SPI,
@@ -824,63 +850,28 @@ typedef enum {
 
 typedef struct _MPT_SCSI_HOST {
        MPT_ADAPTER              *ioc;
-       int                       port;
-       u32                       pad0;
-       MPT_LOCAL_REPLY          *pLocal;               /* used for internal commands */
-       struct timer_list         timer;
-               /* Pool of memory for holding SCpnts before doing
-                * OS callbacks. freeQ is the free pool.
-                */
-       u8                        tmPending;
-       u8                        resetPending;
-       u8                        negoNvram;            /* DV disabled, nego NVRAM */
-       u8                        pad1;
-       u8                        tmState;
-       u8                        rsvd[2];
-       MPT_FRAME_HDR            *cmdPtr;               /* Ptr to nonOS request */
-       struct scsi_cmnd         *abortSCpnt;
-       MPT_LOCAL_REPLY           localReply;           /* internal cmd reply struct */
-       unsigned long             hard_resets;          /* driver forced bus resets count */
-       unsigned long             soft_resets;          /* fw/external bus resets count */
-       unsigned long             timeouts;             /* cmd timeouts */
        ushort                    sel_timeout[MPT_MAX_FC_DEVICES];
        char                      *info_kbuf;
-       wait_queue_head_t         scandv_waitq;
-       int                       scandv_wait_done;
        long                      last_queue_full;
-       u16                       tm_iocstatus;
        u16                       spi_pending;
        struct list_head          target_reset_list;
 } MPT_SCSI_HOST;
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*
- *     More Dynamic Multi-Pathing stuff...
- */
-
-/* Forward decl, a strange C thing, to prevent gcc compiler warnings */
-struct scsi_cmnd;
-
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
  * Generic structure passed to the base mpt_config function.
  */
 typedef struct _x_config_parms {
-       struct list_head         linkage;       /* linked list */
-       struct timer_list        timer;         /* timer function for this request  */
        union {
                ConfigExtendedPageHeader_t      *ehdr;
                ConfigPageHeader_t      *hdr;
        } cfghdr;
        dma_addr_t               physAddr;
-       int                      wait_done;     /* wait for this request */
        u32                      pageAddr;      /* properly formatted */
+       u16                      status;
        u8                       action;
        u8                       dir;
        u8                       timeout;       /* seconds */
-       u8                       pad1;
-       u16                      status;
-       u16                      pad2;
 } CONFIGPARMS;
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -910,23 +901,32 @@ extern int         mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp);
 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 int      mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag);
+extern int      mpt_SoftResetHandler(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);
+extern int      mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size);
 extern void     mpt_free_fw_memory(MPT_ADAPTER *ioc);
 extern int      mpt_findImVolumes(MPT_ADAPTER *ioc);
 extern int      mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode);
 extern int      mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num, pRaidPhysDiskPage0_t phys_disk);
+extern int      mpt_raid_phys_disk_pg1(MPT_ADAPTER *ioc, u8 phys_disk_num, pRaidPhysDiskPage1_t phys_disk);
+extern int      mpt_raid_phys_disk_get_num_paths(MPT_ADAPTER *ioc, u8 phys_disk_num);
+
+extern int      mpt_set_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc);
+extern void     mpt_clear_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc);
+extern void     mpt_halt_firmware(MPT_ADAPTER *ioc);
 
 /*
  *  Public data decl's...
  */
 extern struct list_head          ioc_list;
 extern struct proc_dir_entry   *mpt_proc_root_dir;
+extern int mpt_debug_level;
+extern int mpt_fwfault_debug;
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 #endif         /* } __KERNEL__ */
 
-#if defined(__alpha__) || defined(__sparc_v9__) || defined(__ia64__) || defined(__x86_64__) || defined(__powerpc__)
+#if defined(__alpha__) || defined(__sparc_v9__) || defined(__ia64__) || defined(__x86_64__) || defined(__powerpc64__)
 #define CAST_U32_TO_PTR(x)     ((void *)(u64)x)
 #define CAST_PTR_TO_U32(x)     ((u32)(u64)x)
 #else
index 7e5ec0df0ca75dd01f09a17376f21d93e23eaf4f..6b8038ee691b25902403936721c7cb6b496a78b4 100644 (file)
@@ -45,6 +45,7 @@
 */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 
+#include <linux/version.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/errno.h>
 #include "mptbase.h"
 #include "mptctl.h"
 
+#if defined(CPQ_CIM)
+#include "mptsas.h"
+#include "csmi/csmisas.h"
+#endif // CPQ_CIM
+
+#if defined(DIAG_BUFFER_SUPPORT)
+#include "rejected_ioctls/diag_buffer.h"
+#endif
+
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 #define my_NAME                "Fusion MPT misc device (ioctl) driver"
 #define my_VERSION     MPT_LINUX_VERSION_COMMON
@@ -84,6 +94,7 @@ MODULE_VERSION(my_VERSION);
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 
 static u8 mptctl_id = MPT_MAX_PROTOCOL_DRIVERS;
+static u8 mptctl_taskmgmt_id = MPT_MAX_PROTOCOL_DRIVERS;
 
 static DECLARE_WAIT_QUEUE_HEAD ( mptctl_wait );
 
@@ -112,6 +123,42 @@ static int mptctl_do_reset(unsigned long arg);
 static int mptctl_hp_hostinfo(unsigned long arg, unsigned int cmd);
 static int mptctl_hp_targetinfo(unsigned long arg);
 
+#if defined(CPQ_CIM)
+/* csmisas proto's*/
+static int csmisas_get_driver_info(unsigned long arg);
+static int csmisas_get_cntlr_status(unsigned long arg);
+static int csmisas_get_cntlr_config(unsigned long arg);
+static int csmisas_get_phy_info(unsigned long arg);
+static int csmisas_get_scsi_address(unsigned long arg);
+static int csmisas_get_link_errors(unsigned long arg);
+static int csmisas_smp_passthru(unsigned long arg);
+static int csmisas_firmware_download(unsigned long arg);
+static int csmisas_get_raid_info(unsigned long arg);
+static int csmisas_get_raid_config(unsigned long arg);
+static int csmisas_get_raid_features(unsigned long arg);
+static int csmisas_set_raid_control(unsigned long arg);
+static int csmisas_get_raid_element(unsigned long arg);
+static int csmisas_set_raid_operation(unsigned long arg);
+static int csmisas_set_phy_info(unsigned long arg);
+static int csmisas_ssp_passthru(unsigned long arg);
+static int csmisas_stp_passthru(unsigned long arg);
+static int csmisas_get_sata_signature(unsigned long arg);
+static int csmisas_get_device_address(unsigned long arg);
+static int csmisas_task_managment(unsigned long arg);
+static int csmisas_phy_control(unsigned long arg);
+static int csmisas_get_connector_info(unsigned long arg);
+static int csmisas_get_location(unsigned long arg);
+#endif // CPQ_CIM
+
+#if defined(DIAG_BUFFER_SUPPORT)
+/* diag_buffer proto's */
+static int mptctl_register_diag_buffer(unsigned long arg);
+static int mptctl_release_diag_buffer(unsigned long arg);
+static int mptctl_unregister_diag_buffer(unsigned long arg);
+static int mptctl_query_diag_buffer(unsigned long arg);
+static int mptctl_read_diag_buffer(unsigned long arg);
+#endif // DIAG_BUFFER_SUPPORT
+
 static int  mptctl_probe(struct pci_dev *, const struct pci_device_id *);
 static void mptctl_remove(struct pci_dev *);
 
@@ -127,10 +174,6 @@ 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_timeout_expired (MPT_IOCTL *ioctl);
-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
@@ -183,10 +226,10 @@ mptctl_syscall_down(MPT_ADAPTER *ioc, int nonblock)
        int rc = 0;
 
        if (nonblock) {
-               if (!mutex_trylock(&ioc->ioctl->ioctl_mutex))
+               if (!mutex_trylock(&ioc->ioctl_cmds.mutex))
                        rc = -EAGAIN;
        } else {
-               if (mutex_lock_interruptible(&ioc->ioctl->ioctl_mutex))
+               if (mutex_lock_interruptible(&ioc->ioctl_cmds.mutex))
                        rc = -ERESTARTSYS;
        }
        return rc;
@@ -202,131 +245,104 @@ mptctl_syscall_down(MPT_ADAPTER *ioc, int nonblock)
 static int
 mptctl_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply)
 {
-       char *sense_data;
-       int sz, req_index;
-       u16 iocStatus;
-       u8 cmd;
-
-       if (req)
-                cmd = req->u.hdr.Function;
-       else
-               return 1;
-       dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\tcompleting mpi function (0x%02X), req=%p, "
-           "reply=%p\n", ioc->name,  req->u.hdr.Function, req, reply));
-
-       if (ioc->ioctl) {
+       char    *sense_data;
+       int     req_index;
+       int     sz;
 
-               if (reply==NULL) {
+       if (!req)
+               return 0;
 
-                       dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_reply() NULL Reply "
-                               "Function=%x!\n", ioc->name, cmd));
+       dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "completing mpi function "
+           "(0x%02X), req=%p, reply=%p\n", ioc->name,  req->u.hdr.Function,
+           req, reply));
 
-                       ioc->ioctl->status |= MPT_IOCTL_STATUS_COMMAND_GOOD;
-                       ioc->ioctl->reset &= ~MPTCTL_RESET_OK;
+       /*
+        * Handling continuation of the same reply. Processing the first
+        * reply, and eating the other replys that come later.
+        */
+       if (ioc->ioctl_cmds.msg_context != req->u.hdr.MsgContext)
+               goto out_continuation;
 
-                       /* We are done, issue wake up
-                       */
-                       ioc->ioctl->wait_done = 1;
-                       wake_up (&mptctl_wait);
-                       return 1;
+       ioc->ioctl_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
 
-               }
-
-               /* Copy the reply frame (which much exist
-                * for non-SCSI I/O) to the IOC structure.
-                */
-               memcpy(ioc->ioctl->ReplyFrame, reply,
-                       min(ioc->reply_sz, 4*reply->u.reply.MsgLength));
-               ioc->ioctl->status |= MPT_IOCTL_STATUS_RF_VALID;
+       if (!reply)
+               goto out;
 
-               /* Set the command status to GOOD if IOC Status is GOOD
-                * OR if SCSI I/O cmd and data underrun or recovered error.
-                */
-               iocStatus = le16_to_cpu(reply->u.reply.IOCStatus) & MPI_IOCSTATUS_MASK;
-               if (iocStatus  == MPI_IOCSTATUS_SUCCESS)
-                       ioc->ioctl->status |= MPT_IOCTL_STATUS_COMMAND_GOOD;
-
-               if (iocStatus || reply->u.reply.IOCLogInfo)
-                       dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\tiocstatus (0x%04X), "
-                               "loginfo (0x%08X)\n", ioc->name,
-                               iocStatus,
-                               le32_to_cpu(reply->u.reply.IOCLogInfo)));
-
-               if ((cmd == MPI_FUNCTION_SCSI_IO_REQUEST) ||
-                       (cmd == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) {
-
-                       if (reply->u.sreply.SCSIStatus || reply->u.sreply.SCSIState)
-                               dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
-                                       "\tscsi_status (0x%02x), scsi_state (0x%02x), "
-                                       "tag = (0x%04x), transfer_count (0x%08x)\n", ioc->name,
-                                       reply->u.sreply.SCSIStatus,
-                                       reply->u.sreply.SCSIState,
-                                       le16_to_cpu(reply->u.sreply.TaskTag),
-                                       le32_to_cpu(reply->u.sreply.TransferCount)));
-
-                       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;
-                       }
-               }
+       ioc->ioctl_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
+       sz = min(ioc->reply_sz, 4*reply->u.reply.MsgLength);
+       memcpy(ioc->ioctl_cmds.reply, reply, sz);
 
-               /* Copy the sense data - if present
-                */
-               if ((cmd == MPI_FUNCTION_SCSI_IO_REQUEST) &&
-                       (reply->u.sreply.SCSIState &
-                        MPI_SCSI_STATE_AUTOSENSE_VALID)){
+       if (reply->u.reply.IOCStatus || reply->u.reply.IOCLogInfo)
+               dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "iocstatus (0x%04X), loginfo (0x%08X)\n", ioc->name,
+                   le16_to_cpu(reply->u.reply.IOCStatus),
+                   le32_to_cpu(reply->u.reply.IOCLogInfo)));
+
+       if ((req->u.hdr.Function == MPI_FUNCTION_SCSI_IO_REQUEST) ||
+               (req->u.hdr.Function == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) {
+
+               if (reply->u.sreply.SCSIStatus || reply->u.sreply.SCSIState)
+                       dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                       "scsi_status (0x%02x), scsi_state (0x%02x), "
+                       "tag = (0x%04x), transfer_count (0x%08x)\n", ioc->name,
+                       reply->u.sreply.SCSIStatus,
+                       reply->u.sreply.SCSIState,
+                       le16_to_cpu(reply->u.sreply.TaskTag),
+                       le32_to_cpu(reply->u.sreply.TransferCount)));
+
+               if (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 +
+                       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;
+                       memcpy(ioc->ioctl_cmds.sense, sense_data, sz);
+                       ioc->ioctl_cmds.status |= MPT_MGMT_STATUS_SENSE_VALID;
                }
+       }
 
-               if (cmd == MPI_FUNCTION_SCSI_TASK_MGMT)
-                       mptctl_free_tm_flags(ioc);
-
-               /* We are done, issue wake up
-                */
-               ioc->ioctl->wait_done = 1;
-               wake_up (&mptctl_wait);
+ out:
+       /* We are done, issue wake up
+        */
+       if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_PENDING) {
+               if (req->u.hdr.Function == MPI_FUNCTION_SCSI_TASK_MGMT)
+                       mpt_clear_taskmgmt_in_progress_flag(ioc);
+               ioc->ioctl_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
+               complete(&ioc->ioctl_cmds.done);
        }
+
+ out_continuation:
+       if (reply && (reply->u.reply.MsgFlags &
+           MPI_MSGFLAGS_CONTINUATION_REPLY))
+               return 0;
        return 1;
 }
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/* mptctl_timeout_expired
- *
- * Expecting an interrupt, however timed out.
- *
- */
-static void mptctl_timeout_expired (MPT_IOCTL *ioctl)
+static int
+mptctl_taskmgmt_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
 {
-       int rc = 1;
+       if (!mf)
+               return 0;
 
-       dctlprintk(ioctl->ioc, printk(MYIOC_s_DEBUG_FMT ": Timeout Expired! Host %d\n",
-                               ioctl->ioc->name, ioctl->ioc->id));
-       if (ioctl == NULL)
-               return;
+       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt completed (mf=%p, mr=%p)\n",
+           ioc->name, mf, mr));
 
-       ioctl->wait_done = 0;
-       if (ioctl->reset & MPTCTL_RESET_OK)
-               rc = mptctl_bus_reset(ioctl);
+       ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
 
-       if (rc) {
-               /* Issue a reset for this device.
-                * The IOC is not responding.
-                */
-               dctlprintk(ioctl->ioc, printk(MYIOC_s_DEBUG_FMT "Calling HardReset! \n",
-                        ioctl->ioc->name));
-               mpt_HardResetHandler(ioctl->ioc, CAN_SLEEP);
-       }
-       return;
+       if (!mr)
+               goto out;
 
+       ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
+       memcpy(ioc->taskmgmt_cmds.reply, mr,
+           min(MPT_DEFAULT_FRAME_SIZE, 4 * mr->u.reply.MsgLength));
+ out:
+       if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) {
+               mpt_clear_taskmgmt_in_progress_flag(ioc);
+               ioc->taskmgmt_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
+               complete(&ioc->taskmgmt_cmds.done);
+               return 1;
+       }
+       return 0;
 }
 
 /* mptctl_bus_reset
@@ -334,132 +350,181 @@ static void mptctl_timeout_expired (MPT_IOCTL *ioctl)
  * Bus reset code.
  *
  */
-static int mptctl_bus_reset(MPT_IOCTL *ioctl)
+static int
+mptctl_bus_reset(MPT_ADAPTER *ioc, u8 function)
 {
        MPT_FRAME_HDR   *mf;
        SCSITaskMgmt_t  *pScsiTm;
-       MPT_SCSI_HOST   *hd;
+       SCSITaskMgmtReply_t *pScsiTmReply;
        int              ii;
-       int              retval=0;
-
-
-       ioctl->reset &= ~MPTCTL_RESET_OK;
-
-       if (ioctl->ioc->sh == NULL)
+       int              retval;
+       unsigned long    timeout;
+       unsigned long    time_count;
+       u16              iocstatus;
+
+       /* bus reset is only good for SCSI IO, RAID PASSTHRU */
+       if (!(function == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH) ||
+           (function == MPI_FUNCTION_SCSI_IO_REQUEST)) {
+               dtmprintk(ioc, printk(MYIOC_s_WARN_FMT "TaskMgmt, not SCSI_IO!!\n",
+                               ioc->name));
                return -EPERM;
+       }
 
-       hd = shost_priv(ioctl->ioc->sh);
-       if (hd == NULL)
+       mutex_lock(&ioc->taskmgmt_cmds.mutex);
+       if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) {
+               mutex_unlock(&ioc->taskmgmt_cmds.mutex);
                return -EPERM;
+       }
 
-       /* Single threading ....
-        */
-       if (mptctl_set_tm_flags(hd) != 0)
-               return -EPERM;
+       retval = 0;
 
        /* Send request
         */
-       if ((mf = mpt_get_msg_frame(mptctl_id, ioctl->ioc)) == NULL) {
-               dtmprintk(ioctl->ioc, printk(MYIOC_s_DEBUG_FMT "IssueTaskMgmt, no msg frames!!\n",
-                               ioctl->ioc->name));
-
-               mptctl_free_tm_flags(ioctl->ioc);
-               return -ENOMEM;
+       if ((mf = mpt_get_msg_frame(mptctl_taskmgmt_id, ioc)) == NULL) {
+               dtmprintk(ioc, printk(MYIOC_s_WARN_FMT "TaskMgmt, no msg frames!!\n",
+                               ioc->name));
+               mpt_clear_taskmgmt_in_progress_flag(ioc);
+               retval = -ENOMEM;
+               goto mptctl_bus_reset_done;
        }
 
-       dtmprintk(ioctl->ioc, printk(MYIOC_s_DEBUG_FMT "IssueTaskMgmt request @ %p\n",
-                       ioctl->ioc->name, mf));
+       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request (mf=%p)\n",
+               ioc->name, mf));
 
        pScsiTm = (SCSITaskMgmt_t *) mf;
-       pScsiTm->TargetID = ioctl->id;
-       pScsiTm->Bus = hd->port;        /* 0 */
-       pScsiTm->ChainOffset = 0;
+       memset(pScsiTm, 0, sizeof(SCSITaskMgmt_t));
        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;
-
+       pScsiTm->TargetID = 0;
+       pScsiTm->Bus = 0;
+       pScsiTm->ChainOffset = 0;
+       pScsiTm->Reserved = 0;
+       pScsiTm->Reserved1 = 0;
+       pScsiTm->TaskMsgContext = 0;
        for (ii= 0; ii < 8; ii++)
                pScsiTm->LUN[ii] = 0;
-
        for (ii=0; ii < 7; ii++)
                pScsiTm->Reserved2[ii] = 0;
 
-       pScsiTm->TaskMsgContext = 0;
-       dtmprintk(ioctl->ioc, printk(MYIOC_s_DEBUG_FMT
-               "mptctl_bus_reset: issued.\n", ioctl->ioc->name));
-
-       DBG_DUMP_TM_REQUEST_FRAME(ioctl->ioc, (u32 *)mf);
+       switch (ioc->bus_type) {
+               case FC:
+                       timeout = 40;
+                       break;
+               case SAS:
+                       timeout = 30;
+                       break;
+               case SPI:
+               default:
+                       timeout = 2;
+                       break;
+       }
 
-       ioctl->wait_done=0;
+       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt type=%d timeout=%ld\n",
+           ioc->name, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS, timeout));
 
-       if ((ioctl->ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q) &&
-           (ioctl->ioc->facts.MsgVersion >= MPI_VERSION_01_05))
-               mpt_put_msg_frame_hi_pri(mptctl_id, ioctl->ioc, mf);
+       INITIALIZE_MGMT_STATUS(ioc->taskmgmt_cmds.status)
+       CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status)
+       time_count = jiffies;
+       if ((ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q) &&
+           (ioc->facts.MsgVersion >= MPI_VERSION_01_05))
+               mpt_put_msg_frame_hi_pri(mptctl_taskmgmt_id, ioc, mf);
        else {
-               retval = mpt_send_handshake_request(mptctl_id, ioctl->ioc,
-                       sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP);
+               retval = mpt_send_handshake_request(mptctl_taskmgmt_id, ioc,
+                   sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP);
                if (retval != 0) {
-                       dfailprintk(ioctl->ioc, printk(MYIOC_s_ERR_FMT "_send_handshake FAILED!"
-                               " (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd,
-                               hd->ioc, mf));
+                       dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "TaskMgmt send_handshake FAILED!"
+                               " (ioc %p, mf %p, rc=%d) \n", ioc->name,
+                               ioc, mf, retval));
+                       mpt_clear_taskmgmt_in_progress_flag(ioc);
                        goto mptctl_bus_reset_done;
                }
        }
 
        /* Now wait for the command to complete */
-       ii = wait_event_timeout(mptctl_wait,
-            ioctl->wait_done == 1,
-            HZ*5 /* 5 second timeout */);
+       ii = wait_for_completion_timeout(&ioc->taskmgmt_cmds.done, timeout*HZ);
+       if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
+               dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "TaskMgmt failed\n", ioc->name));
+               mpt_free_msg_frame(ioc, mf);
+               mpt_clear_taskmgmt_in_progress_flag(ioc);
+               if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
+                       retval = 0;
+               else
+                       retval = -1; /* return failure */
+               goto mptctl_bus_reset_done;
+       }
 
-       if(ii <=0 && (ioctl->wait_done != 1 ))  {
-               mpt_free_msg_frame(hd->ioc, mf);
-               ioctl->wait_done = 0;
+       if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
+               dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "TaskMgmt failed\n", ioc->name));
+               retval = -1; /* return failure */
+               goto mptctl_bus_reset_done;
+       }
+
+       pScsiTmReply = (SCSITaskMgmtReply_t *) ioc->taskmgmt_cmds.reply;
+       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+           "TaskMgmt fw_channel = %d, fw_id = %d, task_type=0x%02X, "
+           "iocstatus=0x%04X\n\tloginfo=0x%08X, response_code=0x%02X, "
+           "term_cmnds=%d\n", ioc->name, pScsiTmReply->Bus,
+           pScsiTmReply->TargetID, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
+           le16_to_cpu(pScsiTmReply->IOCStatus),
+           le32_to_cpu(pScsiTmReply->IOCLogInfo),
+           pScsiTmReply->ResponseCode,
+           le32_to_cpu(pScsiTmReply->TerminationCount)));
+
+       iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK;
+
+       if (iocstatus == MPI_IOCSTATUS_SCSI_TASK_TERMINATED ||
+          iocstatus == MPI_IOCSTATUS_SCSI_IOC_TERMINATED ||
+          iocstatus == MPI_IOCSTATUS_SUCCESS)
+               retval = 0;
+       else {
+               dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "TaskMgmt failed\n", ioc->name));
                retval = -1; /* return failure */
        }
 
-mptctl_bus_reset_done:
 
-       mptctl_free_tm_flags(ioctl->ioc);
+ mptctl_bus_reset_done:
+       mutex_unlock(&ioc->taskmgmt_cmds.mutex);
+       CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status)
        return retval;
 }
 
-static int
-mptctl_set_tm_flags(MPT_SCSI_HOST *hd) {
-       unsigned long flags;
-
-       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);
-       } else {
-               spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
-               return -EBUSY;
-       }
-
-       return 0;
-}
-
 static void
-mptctl_free_tm_flags(MPT_ADAPTER *ioc)
+mptctl_timeout_expired(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
 {
-       MPT_SCSI_HOST * hd;
        unsigned long flags;
 
-       hd = shost_priv(ioc->sh);
-       if (hd == NULL)
+       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": %s\n",
+               ioc->name, __FUNCTION__));
+
+       if(mpt_fwfault_debug)
+               mpt_halt_firmware(ioc);
+       
+       spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
+       if (ioc->ioc_reset_in_progress) {
+               spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
+               CLEAR_MGMT_PENDING_STATUS(ioc->ioctl_cmds.status)
+               mpt_free_msg_frame(ioc, mf);
                return;
+       }
+       spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
 
-       spin_lock_irqsave(&ioc->FreeQlock, flags);
 
-       hd->tmState = TM_STATE_NONE;
-       hd->tmPending = 0;
-       spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+       if (!mptctl_bus_reset(ioc, mf->u.hdr.Function))
+               return;
 
-       return;
+       /* Issue a reset for this device.
+        * The IOC is not responding.
+        */
+       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling HardReset! \n",
+                ioc->name));
+       CLEAR_MGMT_PENDING_STATUS(ioc->ioctl_cmds.status)
+       if (mpt_SoftResetHandler(ioc, CAN_SLEEP) != 0)
+               mpt_HardResetHandler(ioc, CAN_SLEEP);
+       mpt_free_msg_frame(ioc, mf);
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -472,22 +537,23 @@ mptctl_free_tm_flags(MPT_ADAPTER *ioc)
 static int
 mptctl_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
 {
-       MPT_IOCTL *ioctl = ioc->ioctl;
-       dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOC %s_reset routed to IOCTL driver!\n", ioc->name,
-               reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
-               reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
-
-       if(ioctl == NULL)
-               return 1;
-
        switch(reset_phase) {
        case MPT_IOC_SETUP_RESET:
-               ioctl->status |= MPT_IOCTL_STATUS_DID_IOCRESET;
+               dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __FUNCTION__));
+               break;
+       case MPT_IOC_PRE_RESET:
+               dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "%s: MPT_IOC_PRE_RESET\n", ioc->name, __FUNCTION__));
                break;
        case MPT_IOC_POST_RESET:
-               ioctl->status &= ~MPT_IOCTL_STATUS_DID_IOCRESET;
+               dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "%s: MPT_IOC_POST_RESET\n", ioc->name, __FUNCTION__));
+               if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_PENDING) {
+                       ioc->ioctl_cmds.status |= MPT_MGMT_STATUS_DID_IOCRESET;
+                       complete(&ioc->ioctl_cmds.done);
+               }
                break;
-       case MPT_IOC_PRE_RESET:
        default:
                break;
        }
@@ -578,6 +644,7 @@ __mptctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        int ret;
        MPT_ADAPTER *iocp = NULL;
 
+
        if (copy_from_user(&khdr, uhdr, sizeof(khdr))) {
                printk(KERN_ERR MYNAM "%s::mptctl_ioctl() @%d - "
                                "Unable to copy mpt_ioctl_header data @ %p\n",
@@ -592,17 +659,12 @@ __mptctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        iocnumX = khdr.iocnum & 0xFF;
        if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) ||
            (iocp == NULL)) {
+               if (mpt_debug_level & MPT_DEBUG_IOCTL)
                printk(KERN_DEBUG MYNAM "%s::mptctl_ioctl() @%d - ioc%d not found!\n",
                                __FILE__, __LINE__, iocnumX);
                return -ENODEV;
        }
 
-       if (!iocp->active) {
-               printk(KERN_DEBUG MYNAM "%s::mptctl_ioctl() @%d - Controller disabled.\n",
-                               __FILE__, __LINE__);
-               return -EFAULT;
-       }
-
        /* Handle those commands that are just returning
         * information stored in the driver.
         * These commands should never time out and are unaffected
@@ -622,6 +684,25 @@ __mptctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                return mptctl_eventreport(arg);
        } else if (cmd == MPTFWREPLACE) {
                return mptctl_replace_fw(arg);
+#if defined(DIAG_BUFFER_SUPPORT)
+/* diag_buffer static data calls*/
+       } else if (cmd == MPTDIAGQUERY) {
+               return mptctl_query_diag_buffer(arg);
+       } else if (cmd == MPTDIAGUNREGISTER) {
+               return mptctl_unregister_diag_buffer(arg);
+#endif
+
+#if defined(CPQ_CIM)
+/* csmisas static data calls*/
+       } else if (cmd == CC_CSMI_SAS_GET_DRIVER_INFO) {
+               return csmisas_get_driver_info(arg);
+       } else if (cmd == CC_CSMI_SAS_GET_CNTLR_STATUS) {
+               return csmisas_get_cntlr_status(arg);
+       } else if (cmd == CC_CSMI_SAS_GET_SCSI_ADDRESS) {
+               return csmisas_get_scsi_address(arg);
+       } else if (cmd == CC_CSMI_SAS_GET_DEVICE_ADDRESS){
+               return csmisas_get_device_address(arg);
+#endif // CPQ_CIM
        }
 
        /* All of these commands require an interrupt or
@@ -630,6 +711,8 @@ __mptctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        if ((ret = mptctl_syscall_down(iocp, nonblock)) != 0)
                return ret;
 
+//     dctlprintk(iocp, printk(MYIOC_s_DEBUG_FMT ": mptctl_ioctl()\n", iocp->name));
+
        if (cmd == MPTFWDOWNLOAD)
                ret = mptctl_fw_download(arg);
        else if (cmd == MPTCOMMAND)
@@ -640,10 +723,61 @@ __mptctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                ret = mptctl_hp_hostinfo(arg, _IOC_SIZE(cmd));
        else if (cmd == HP_GETTARGETINFO)
                ret = mptctl_hp_targetinfo(arg);
+#if defined(CPQ_CIM)
+/* csmisas requiring fw calls*/
+       else if (cmd == CC_CSMI_SAS_GET_CNTLR_CONFIG)
+               ret = csmisas_get_cntlr_config(arg);
+       else if (cmd == CC_CSMI_SAS_GET_PHY_INFO)
+               ret = csmisas_get_phy_info(arg);
+       else if (cmd == CC_CSMI_SAS_GET_SATA_SIGNATURE)
+               ret = csmisas_get_sata_signature(arg);
+       else if (cmd == CC_CSMI_SAS_GET_LINK_ERRORS)
+               ret = csmisas_get_link_errors(arg);
+       else if (cmd == CC_CSMI_SAS_SMP_PASSTHRU)
+               ret = csmisas_smp_passthru(arg);
+       else if (cmd == CC_CSMI_SAS_SSP_PASSTHRU)
+               ret = csmisas_ssp_passthru(arg);
+       else if (cmd == CC_CSMI_SAS_FIRMWARE_DOWNLOAD)
+               ret = csmisas_firmware_download(arg);
+       else if (cmd == CC_CSMI_SAS_GET_RAID_INFO)
+               ret = csmisas_get_raid_info(arg);
+       else if (cmd == CC_CSMI_SAS_GET_RAID_CONFIG)
+               ret = csmisas_get_raid_config(arg);
+       else if (cmd == CC_CSMI_SAS_GET_RAID_FEATURES)
+               ret = csmisas_get_raid_features(arg);
+       else if (cmd == CC_CSMI_SAS_SET_RAID_CONTROL)
+               ret = csmisas_set_raid_control(arg);
+       else if (cmd == CC_CSMI_SAS_GET_RAID_ELEMENT)
+               ret = csmisas_get_raid_element(arg);
+       else if (cmd == CC_CSMI_SAS_SET_RAID_OPERATION)
+               ret = csmisas_set_raid_operation(arg);
+       else if (cmd == CC_CSMI_SAS_SET_PHY_INFO)
+               ret = csmisas_set_phy_info(arg);
+       else if (cmd == CC_CSMI_SAS_STP_PASSTHRU)
+               ret = csmisas_stp_passthru(arg);
+       else if (cmd == CC_CSMI_SAS_TASK_MANAGEMENT)
+               ret = csmisas_task_managment(arg);
+       else if (cmd == CC_CSMI_SAS_PHY_CONTROL)
+               ret = csmisas_phy_control(arg);
+       else if (cmd == CC_CSMI_SAS_GET_CONNECTOR_INFO)
+               ret = csmisas_get_connector_info(arg);
+       else if (cmd == CC_CSMI_SAS_GET_LOCATION)
+               ret = csmisas_get_location(arg);
+#endif // CPQ_CIM
+
+#if defined(DIAG_BUFFER_SUPPORT)
+/* diag_buffer requiring fw calls*/
+       else if (cmd == MPTDIAGREGISTER)
+               ret = mptctl_register_diag_buffer(arg);
+       else if (cmd == MPTDIAGRELEASE)
+               ret = mptctl_release_diag_buffer(arg);
+       else if (cmd == MPTDIAGREADBUFFER)
+               ret = mptctl_read_diag_buffer(arg);
+#endif // DIAG_BUFFER_SUPPORT
        else
                ret = -EINVAL;
 
-       mutex_unlock(&iocp->ioctl->ioctl_mutex);
+       mutex_unlock(&iocp->ioctl_cmds.mutex);
 
        return ret;
 }
@@ -672,6 +806,7 @@ static int mptctl_do_reset(unsigned long arg)
        }
 
        if (mpt_verify_adapter(krinfo.hdr.iocnum, &iocp) < 0) {
+               if (mpt_debug_level & MPT_DEBUG_IOCTL)
                printk(KERN_DEBUG MYNAM "%s@%d::mptctl_do_reset - ioc%d not found!\n",
                                __FILE__, __LINE__, krinfo.hdr.iocnum);
                return -ENODEV; /* (-6) No such device or address */
@@ -759,10 +894,11 @@ mptctl_do_fw_download(int ioc, char __user *ufwbuf, size_t fwlen)
        int                      sge_offset = 0;
        u16                      iocstat;
        pFWDownloadReply_t       ReplyMsg = NULL;
+       unsigned long            timeleft;
 
        if (mpt_verify_adapter(ioc, &iocp) < 0) {
-               printk(KERN_DEBUG MYNAM "ioctl_fwdl - ioc%d not found!\n",
-                                ioc);
+               if (mpt_debug_level & MPT_DEBUG_IOCTL)
+               printk(KERN_DEBUG MYNAM "ioctl_fwdl - ioc%d not found!\n", ioc);
                return -ENODEV; /* (-6) No such device or address */
        } else {
 
@@ -846,7 +982,7 @@ mptctl_do_fw_download(int ioc, char __user *ufwbuf, size_t fwlen)
                        / (sizeof(dma_addr_t) + sizeof(u32));
        if (numfrags > maxfrags) {
                ret = -EMLINK;
-               goto fwdl_out;
+               goto fwdl_out;
        }
 
        dctlprintk(iocp, printk(MYIOC_s_DEBUG_FMT "DbG: sgl buffer = %p, sgfrags = %d\n",
@@ -875,8 +1011,8 @@ mptctl_do_fw_download(int ioc, char __user *ufwbuf, size_t fwlen)
                        n++;
                        if (copy_from_user(bl->kptr, ufwbuf+fw_bytes_copied, bl->len)) {
                                printk(MYIOC_s_ERR_FMT "%s@%d::_ioctl_fwdl - "
-                                       "Unable to copy f/w buffer hunk#%d @ %p\n",
-                                       iocp->name, __FILE__, __LINE__, n, ufwbuf);
+                                   "Unable to copy f/w buffer hunk#%d @ %p\n",
+                                   iocp->name, __FILE__, __LINE__, n, ufwbuf);
                                goto fwdl_out;
                        }
                        fw_bytes_copied += bl->len;
@@ -892,16 +1028,27 @@ mptctl_do_fw_download(int ioc, char __user *ufwbuf, size_t fwlen)
         * Finally, perform firmware download.
         */
        ReplyMsg = NULL;
+       SET_MGMT_MSG_CONTEXT(iocp->ioctl_cmds.msg_context, dlmsg->MsgContext);
+       INITIALIZE_MGMT_STATUS(iocp->ioctl_cmds.status)
        mpt_put_msg_frame(mptctl_id, iocp, mf);
 
        /* Now wait for the command to complete */
-       ret = wait_event_timeout(mptctl_wait,
-            iocp->ioctl->wait_done == 1,
-            HZ*60);
+       timeleft = wait_for_completion_timeout(&iocp->ioctl_cmds.done, HZ*60);
+       if (!(iocp->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
+               ret = -ETIME;
+               printk(MYIOC_s_WARN_FMT "%s: failed\n", iocp->name, __FUNCTION__);
+               if (iocp->ioctl_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) {
+                       mpt_free_msg_frame(iocp, mf);
+                       goto fwdl_out;
+               }
+               if (!timeleft)
+                       mptctl_timeout_expired(iocp, mf);
+               goto fwdl_out;
+       }
 
-       if(ret <=0 && (iocp->ioctl->wait_done != 1 )) {
-       /* Now we need to reset the board */
-               mptctl_timeout_expired(iocp->ioctl);
+       if (!(iocp->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
+               printk(MYIOC_s_WARN_FMT "%s: failed\n", iocp->name, __FUNCTION__);
+               mpt_free_msg_frame(iocp, mf);
                ret = -ENODATA;
                goto fwdl_out;
        }
@@ -909,31 +1056,34 @@ mptctl_do_fw_download(int ioc, char __user *ufwbuf, size_t fwlen)
        if (sgl)
                kfree_sgl(sgl, sgl_dma, buflist, iocp);
 
-       ReplyMsg = (pFWDownloadReply_t)iocp->ioctl->ReplyFrame;
+       ReplyMsg = (pFWDownloadReply_t)iocp->ioctl_cmds.reply;
        iocstat = le16_to_cpu(ReplyMsg->IOCStatus) & MPI_IOCSTATUS_MASK;
        if (iocstat == MPI_IOCSTATUS_SUCCESS) {
-               printk(MYIOC_s_INFO_FMT "F/W update successfull!\n", iocp->name);
+               printk(MYIOC_s_INFO_FMT ": F/W update successfully sent!\n", iocp->name);
                return 0;
        } else if (iocstat == MPI_IOCSTATUS_INVALID_FUNCTION) {
-               printk(MYIOC_s_WARN_FMT "Hmmm...  F/W download not supported!?!\n",
-                       iocp->name);
+               printk(MYIOC_s_WARN_FMT "Hmmm...  doesn't support F/W download?\n",
+                   iocp->name);
                printk(MYIOC_s_WARN_FMT "(time to go bang on somebodies door)\n",
-                       iocp->name);
+                   iocp->name);
                return -EBADRQC;
        } else if (iocstat == MPI_IOCSTATUS_BUSY) {
                printk(MYIOC_s_WARN_FMT "IOC_BUSY!\n", iocp->name);
                printk(MYIOC_s_WARN_FMT "(try again later?)\n", iocp->name);
                return -EBUSY;
        } else {
-               printk(MYIOC_s_WARN_FMT "ioctl_fwdl() returned [bad] status = %04xh\n",
-                       iocp->name, iocstat);
+               printk(MYIOC_s_WARN_FMT "returned [bad] status = %04xh\n",
+                   iocp->name, iocstat);
                printk(MYIOC_s_WARN_FMT "(bad VooDoo)\n", iocp->name);
                return -ENOMSG;
        }
        return 0;
 
 fwdl_out:
-        kfree_sgl(sgl, sgl_dma, buflist, iocp);
+
+       CLEAR_MGMT_STATUS(iocp->ioctl_cmds.status);
+       SET_MGMT_MSG_CONTEXT(iocp->ioctl_cmds.msg_context, 0);
+       kfree_sgl(sgl, sgl_dma, buflist, iocp);
        return ret;
 }
 
@@ -1015,9 +1165,9 @@ kbuf_alloc_2_sgl(int bytes, u32 sgdir, int sge_offset, int *frags,
                        alloc_sz = alloc_sz / 2;
                        if (alloc_sz == 0) {
                                printk(MYIOC_s_WARN_FMT "-SG: No can do - "
-                                   "not enough memory!   :-(\n", ioc->name);
+                                   "not enough memory! :-(\n", ioc->name);
                                printk(MYIOC_s_WARN_FMT "-SG: (freeing %d frags)\n",
-                                       ioc->name, numfrags);
+                                   ioc->name, numfrags);
                                goto free_and_fail;
                        }
                        continue;
@@ -1040,8 +1190,8 @@ kbuf_alloc_2_sgl(int bytes, u32 sgdir, int sge_offset, int *frags,
 
                /* Need to chain? */
                if (fragcnt == sg_spill) {
-                       printk(MYIOC_s_WARN_FMT
-                           "-SG: No can do - " "Chain required!   :-(\n", ioc->name);
+                       printk(MYIOC_s_WARN_FMT "-SG: No can do - "
+                           "Chain required! :-(\n", ioc->name);
                        printk(MYIOC_s_WARN_FMT "(freeing %d frags)\n", ioc->name, numfrags);
                        goto free_and_fail;
                }
@@ -1050,9 +1200,9 @@ kbuf_alloc_2_sgl(int bytes, u32 sgdir, int sge_offset, int *frags,
                if (numfrags*8 > MAX_SGL_BYTES){
                        /* GRRRRR... */
                        printk(MYIOC_s_WARN_FMT "-SG: No can do - "
-                               "too many SG frags!   :-(\n", ioc->name);
+                           "too many SG frags! :-(\n", ioc->name);
                        printk(MYIOC_s_WARN_FMT "-SG: (freeing %d frags)\n",
-                               ioc->name, numfrags);
+                           ioc->name, numfrags);
                        goto free_and_fail;
                }
        }
@@ -1209,6 +1359,7 @@ mptctl_getiocinfo (unsigned long arg, unsigned int data_size)
 
        if (((iocnum = mpt_verify_adapter(karg->hdr.iocnum, &ioc)) < 0) ||
            (ioc == NULL)) {
+               if (mpt_debug_level & MPT_DEBUG_IOCTL)
                printk(KERN_DEBUG MYNAM "%s::mptctl_getiocinfo() @%d - ioc%d not found!\n",
                                __FILE__, __LINE__, iocnum);
                kfree(karg);
@@ -1218,8 +1369,8 @@ mptctl_getiocinfo (unsigned long arg, unsigned int data_size)
        /* Verify the data transfer size is correct. */
        if (karg->hdr.maxDataSize != data_size) {
                printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_getiocinfo - "
-                       "Structure size mismatch. Command not completed.\n",
-                       ioc->name, __FILE__, __LINE__);
+                   "Structure size mismatch. Command not completed.\n",
+                   ioc->name, __FILE__, __LINE__);
                kfree(karg);
                return -EFAULT;
        }
@@ -1271,6 +1422,8 @@ mptctl_getiocinfo (unsigned long arg, unsigned int data_size)
        if (ioc->sh) {
                shost_for_each_device(sdev, ioc->sh) {
                        vdevice = sdev->hostdata;
+                       if (vdevice == NULL || vdevice->vtarget == NULL)
+                               continue;
                        if (vdevice->vtarget->tflags &
                            MPT_TARGET_FLAGS_RAID_COMPONENT)
                                continue;
@@ -1342,6 +1495,7 @@ mptctl_gettargetinfo (unsigned long arg)
 
        if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
            (ioc == NULL)) {
+               if (mpt_debug_level & MPT_DEBUG_IOCTL)
                printk(KERN_DEBUG MYNAM "%s::mptctl_gettargetinfo() @%d - ioc%d not found!\n",
                                __FILE__, __LINE__, iocnum);
                return -ENODEV;
@@ -1358,8 +1512,8 @@ mptctl_gettargetinfo (unsigned long arg)
        port = karg.hdr.port;
 
        if (maxWordsLeft <= 0) {
-               printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_gettargetinfo() - no memory available!\n",
-                       ioc->name, __FILE__, __LINE__);
+               printk(MYIOC_s_ERR_FMT "%s::mptctl_gettargetinfo() @%d - no memory available!\n",
+                   ioc->name, __FILE__, __LINE__);
                return -ENOMEM;
        }
 
@@ -1379,8 +1533,8 @@ mptctl_gettargetinfo (unsigned long arg)
         */
        pmem = kzalloc(numBytes, GFP_KERNEL);
        if (!pmem) {
-               printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_gettargetinfo() - no memory available!\n",
-                       ioc->name, __FILE__, __LINE__);
+               printk(MYIOC_s_ERR_FMT "%s::mptctl_gettargetinfo() @%d - no memory available!\n",
+                   ioc->name, __FILE__, __LINE__);
                return -ENOMEM;
        }
        pdata =  (int *) pmem;
@@ -1392,6 +1546,8 @@ mptctl_gettargetinfo (unsigned long arg)
                        if (!maxWordsLeft)
                                continue;
                        vdevice = sdev->hostdata;
+                       if (vdevice == NULL || vdevice->vtarget == NULL)
+                               continue;
                        if (vdevice->vtarget->tflags &
                            MPT_TARGET_FLAGS_RAID_COMPONENT)
                                continue;
@@ -1456,6 +1612,7 @@ mptctl_readtest (unsigned long arg)
 
        if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
            (ioc == NULL)) {
+               if (mpt_debug_level & MPT_DEBUG_IOCTL)
                printk(KERN_DEBUG MYNAM "%s::mptctl_readtest() @%d - ioc%d not found!\n",
                                __FILE__, __LINE__, iocnum);
                return -ENODEV;
@@ -1517,6 +1674,7 @@ mptctl_eventquery (unsigned long arg)
 
        if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
            (ioc == NULL)) {
+               if (mpt_debug_level & MPT_DEBUG_IOCTL)
                printk(KERN_DEBUG MYNAM "%s::mptctl_eventquery() @%d - ioc%d not found!\n",
                                __FILE__, __LINE__, iocnum);
                return -ENODEV;
@@ -1556,6 +1714,7 @@ mptctl_eventenable (unsigned long arg)
 
        if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
            (ioc == NULL)) {
+               if (mpt_debug_level & MPT_DEBUG_IOCTL)
                printk(KERN_DEBUG MYNAM "%s::mptctl_eventenable() @%d - ioc%d not found!\n",
                                __FILE__, __LINE__, iocnum);
                return -ENODEV;
@@ -1569,8 +1728,7 @@ mptctl_eventenable (unsigned long arg)
                int sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS);
                ioc->events = kzalloc(sz, GFP_KERNEL);
                if (!ioc->events) {
-                       printk(MYIOC_s_ERR_FMT
-                           ": ERROR - Insufficient memory to add adapter!\n",
+                       printk(MYIOC_s_ERR_FMT "Insufficient memory to add adapter!\n",
                            ioc->name);
                        return -ENOMEM;
                }
@@ -1605,13 +1763,14 @@ mptctl_eventreport (unsigned long arg)
 
        if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
            (ioc == NULL)) {
+               if (mpt_debug_level & MPT_DEBUG_IOCTL)
                printk(KERN_DEBUG MYNAM "%s::mptctl_eventreport() @%d - ioc%d not found!\n",
                                __FILE__, __LINE__, iocnum);
                return -ENODEV;
        }
+
        dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_eventreport called.\n",
            ioc->name));
-
        numBytes = karg.hdr.maxDataSize - sizeof(mpt_ioctl_header);
        maxEvents = numBytes/sizeof(MPT_IOCTL_EVENTS);
 
@@ -1659,6 +1818,7 @@ mptctl_replace_fw (unsigned long arg)
 
        if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
            (ioc == NULL)) {
+               if (mpt_debug_level & MPT_DEBUG_IOCTL)
                printk(KERN_DEBUG MYNAM "%s::mptctl_replace_fw() @%d - ioc%d not found!\n",
                                __FILE__, __LINE__, iocnum);
                return -ENODEV;
@@ -1690,8 +1850,8 @@ mptctl_replace_fw (unsigned long arg)
         */
        if (copy_from_user(ioc->cached_fw, uarg->newImage, newFwSize)) {
                printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_replace_fw - "
-                               "Unable to read in mpt_ioctl_replace_fw image "
-                               "@ %p\n", ioc->name, __FILE__, __LINE__, uarg);
+                       "Unable to read in mpt_ioctl_replace_fw image "
+                       "@ %p\n", ioc->name, __FILE__, __LINE__, uarg);
                mpt_free_fw_memory(ioc);
                return -EFAULT;
        }
@@ -1733,6 +1893,7 @@ mptctl_mpt_command (unsigned long arg)
 
        if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
            (ioc == NULL)) {
+               if (mpt_debug_level & MPT_DEBUG_IOCTL)
                printk(KERN_DEBUG MYNAM "%s::mptctl_mpt_command() @%d - ioc%d not found!\n",
                                __FILE__, __LINE__, iocnum);
                return -ENODEV;
@@ -1771,8 +1932,11 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
        int             sz, rc = 0;
        int             msgContext;
        u16             req_idx;
-       ulong           timeout;
+       unsigned long   timeout;
+       unsigned long   timeleft;
        struct scsi_device *sdev;
+       unsigned long    flags;
+       u8               function;
 
        /* bufIn and bufOut are used for user to kernel space transfers
         */
@@ -1781,20 +1945,20 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
 
        if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
            (ioc == NULL)) {
+               if (mpt_debug_level & MPT_DEBUG_IOCTL)
                printk(KERN_DEBUG MYNAM "%s::mptctl_do_mpt_command() @%d - ioc%d not found!\n",
                                __FILE__, __LINE__, iocnum);
                return -ENODEV;
        }
-       if (!ioc->ioctl) {
-               printk(KERN_ERR MYNAM "%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) {
+
+       spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
+       if (ioc->ioc_reset_in_progress) {
+               spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
                printk(KERN_ERR MYNAM "%s@%d::mptctl_do_mpt_command - "
-                       "Busy with IOC Reset \n", __FILE__, __LINE__);
+                       "Busy with diagnostic reset\n", __FILE__, __LINE__);
                return -EBUSY;
        }
+       spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
 
        /* Verify that the final request frame will not be too large.
         */
@@ -1828,18 +1992,19 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
                printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
                        "Unable to read MF from mpt_ioctl_command struct @ %p\n",
                        ioc->name, __FILE__, __LINE__, mfPtr);
+               function = -1;
                rc = -EFAULT;
                goto done_free_mem;
        }
        hdr->MsgContext = cpu_to_le32(msgContext);
-
+       function = hdr->Function;
 
        /* Verify that this request is allowed.
         */
        dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "sending mpi function (0x%02X), req=%p\n",
-           ioc->name, hdr->Function, mf));
+           ioc->name, function, mf));
 
-       switch (hdr->Function) {
+       switch (function) {
        case MPI_FUNCTION_IOC_FACTS:
        case MPI_FUNCTION_PORT_FACTS:
                karg.dataOutSize  = karg.dataInSize = 0;
@@ -1916,6 +2081,8 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
                                struct scsi_target *starget = scsi_target(sdev);
                                VirtTarget *vtarget = starget->hostdata;
 
+                               if (vtarget == NULL)
+                                       continue;
                                if ((pScsiReq->TargetID == vtarget->id) &&
                                    (pScsiReq->Bus == vtarget->channel) &&
                                    (vtarget->tflags & MPT_TARGET_FLAGS_Q_YES))
@@ -1936,9 +2103,6 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
                        pScsiReq->Control = cpu_to_le32(scsidir | qtag);
                        pScsiReq->DataLength = cpu_to_le32(dataSize);
 
-                       ioc->ioctl->reset = MPTCTL_RESET_OK;
-                       ioc->ioctl->id = pScsiReq->TargetID;
-
                } else {
                        printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
                                "SCSI driver is not loaded. \n",
@@ -1951,7 +2115,7 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
        case MPI_FUNCTION_SMP_PASSTHROUGH:
                /* Check mf->PassthruFlags to determine if
                 * transfer is ImmediateMode or not.
-                * Immediate mode returns data in the ReplyFrame.
+                * Immediate mode returns data in the reply.
                 * Else, we are sending request and response data
                 * in two SGLs at the end of the mf.
                 */
@@ -2015,8 +2179,6 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
                        pScsiReq->Control = cpu_to_le32(scsidir | qtag);
                        pScsiReq->DataLength = cpu_to_le32(dataSize);
 
-                       ioc->ioctl->reset = MPTCTL_RESET_OK;
-                       ioc->ioctl->id = pScsiReq->TargetID;
                } else {
                        printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
                                "SCSI driver is not loaded. \n",
@@ -2027,20 +2189,15 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
                break;
 
        case MPI_FUNCTION_SCSI_TASK_MGMT:
-               {
-                       MPT_SCSI_HOST *hd = NULL;
-                       if ((ioc->sh == NULL) || ((hd = shost_priv(ioc->sh)) == NULL)) {
-                               printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
-                                       "SCSI driver not loaded or SCSI host not found. \n",
-                                       ioc->name, __FILE__, __LINE__);
-                               rc = -EFAULT;
-                               goto done_free_mem;
-                       } else if (mptctl_set_tm_flags(hd) != 0) {
-                               rc = -EPERM;
-                               goto done_free_mem;
-                       }
-               }
+       {
+               SCSITaskMgmt_t  *pScsiTm;
+               pScsiTm = (SCSITaskMgmt_t *)mf;
+               dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\tTaskType=0x%x MsgFlags=0x%x "
+                   "TaskMsgContext=0x%x id=%d channel=%d\n", ioc->name, pScsiTm->TaskType,
+                   le32_to_cpu(pScsiTm->TaskMsgContext), pScsiTm->MsgFlags,
+                   pScsiTm->TargetID, pScsiTm->Bus));
                break;
+       }
 
        case MPI_FUNCTION_IOC_INIT:
                {
@@ -2058,6 +2215,11 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
                                sense_high= 0;
                        }
 
+                       if (!pInit->MaxDevices && !pInit->MaxBuses) {
+                               pInit->MaxDevices = ioc->facts.MaxDevices;
+                               pInit->MaxBuses = ioc->facts.MaxBuses;
+                       }
+
                        if ((pInit->Flags != 0) || (pInit->MaxDevices != ioc->facts.MaxDevices) ||
                                (pInit->MaxBuses != ioc->facts.MaxBuses) ||
                                (pInit->ReplyFrameSize != cpu_to_le16(ioc->reply_sz)) ||
@@ -2098,7 +2260,7 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
 
                printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
                        "Illegal request (function 0x%x) \n",
-                       ioc->name, __FILE__, __LINE__, hdr->Function);
+                       ioc->name, __FILE__, __LINE__, function);
                rc = -EFAULT;
                goto done_free_mem;
        }
@@ -2185,8 +2347,15 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
                ioc->add_sge(psge, flagsLength, (dma_addr_t) -1);
        }
 
-       ioc->ioctl->wait_done = 0;
-       if (hdr->Function == MPI_FUNCTION_SCSI_TASK_MGMT) {
+       SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context, hdr->MsgContext);
+       INITIALIZE_MGMT_STATUS(ioc->ioctl_cmds.status)
+       if (function == MPI_FUNCTION_SCSI_TASK_MGMT) {
+
+               mutex_lock(&ioc->taskmgmt_cmds.mutex);
+               if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) {
+                       mutex_unlock(&ioc->taskmgmt_cmds.mutex);
+                       goto done_free_mem;
+               }
 
                DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)mf);
 
@@ -2194,53 +2363,57 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
                    (ioc->facts.MsgVersion >= MPI_VERSION_01_05))
                        mpt_put_msg_frame_hi_pri(mptctl_id, ioc, mf);
                else {
-                       rc =mpt_send_handshake_request(mptctl_id, ioc,
-                               sizeof(SCSITaskMgmt_t), (u32*)mf, CAN_SLEEP);
+                       rc = mpt_send_handshake_request(mptctl_id, ioc,
+                           sizeof(SCSITaskMgmt_t), (u32*)mf, CAN_SLEEP);
                        if (rc != 0) {
                                dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
-                                   "_send_handshake FAILED! (ioc %p, mf %p)\n",
+                                   "send_handshake FAILED! (ioc %p, mf %p)\n",
                                    ioc->name, ioc, mf));
-                               mptctl_free_tm_flags(ioc);
+                               mpt_clear_taskmgmt_in_progress_flag(ioc);
                                rc = -ENODATA;
+                               mutex_unlock(&ioc->taskmgmt_cmds.mutex);
                                goto done_free_mem;
                        }
                }
-
        } else
                mpt_put_msg_frame(mptctl_id, ioc, mf);
 
        /* Now wait for the command to complete */
        timeout = (karg.timeout > 0) ? karg.timeout : MPT_IOCTL_DEFAULT_TIMEOUT;
-       timeout = wait_event_timeout(mptctl_wait,
-            ioc->ioctl->wait_done == 1,
-            HZ*timeout);
-
-       if(timeout <=0 && (ioc->ioctl->wait_done != 1 )) {
-       /* Now we need to reset the board */
-
-               if (hdr->Function == MPI_FUNCTION_SCSI_TASK_MGMT)
-                       mptctl_free_tm_flags(ioc);
-
-               mptctl_timeout_expired(ioc->ioctl);
-               rc = -ENODATA;
+       timeleft = wait_for_completion_timeout(&ioc->ioctl_cmds.done, HZ*timeout);
+       if (!(ioc->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
+               rc = -ETIME;
+               dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "%s: TIMED OUT!\n",
+                   ioc->name, __FUNCTION__));
+               if (function == MPI_FUNCTION_SCSI_TASK_MGMT)
+                       mutex_unlock(&ioc->taskmgmt_cmds.mutex);
+               if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) {
+                       goto done_free_mem;
+               }
+               if (!timeleft) {
+                       mptctl_timeout_expired(ioc, mf);
+                       mf = NULL;
+               }
                goto done_free_mem;
        }
 
+       if (function == MPI_FUNCTION_SCSI_TASK_MGMT)
+               mutex_unlock(&ioc->taskmgmt_cmds.mutex);
+
        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 (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID) {
                if (karg.maxReplyBytes < ioc->reply_sz) {
-                        sz = min(karg.maxReplyBytes, 4*ioc->ioctl->ReplyFrame[2]);
+                        sz = min(karg.maxReplyBytes, 4*ioc->ioctl_cmds.reply[2]);
                } else {
-                        sz = min(ioc->reply_sz, 4*ioc->ioctl->ReplyFrame[2]);
+                        sz = min(ioc->reply_sz, 4*ioc->ioctl_cmds.reply[2]);
                }
-
                if (sz > 0) {
                        if (copy_to_user(karg.replyFrameBufPtr,
-                                &ioc->ioctl->ReplyFrame, sz)){
+                                ioc->ioctl_cmds.reply, sz)){
                                 printk(MYIOC_s_ERR_FMT
                                     "%s@%d::mptctl_do_mpt_command - "
                                 "Unable to write out reply frame %p\n",
@@ -2253,10 +2426,10 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
 
        /* If valid sense data, copy to user.
         */
-       if (ioc->ioctl->status & MPT_IOCTL_STATUS_SENSE_VALID) {
+       if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_SENSE_VALID) {
                sz = min(karg.maxSenseBytes, MPT_SENSE_BUFFER_SIZE);
                if (sz > 0) {
-                       if (copy_to_user(karg.senseDataPtr, ioc->ioctl->sense, sz)) {
+                       if (copy_to_user(karg.senseDataPtr, ioc->ioctl_cmds.sense, sz)) {
                                printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
                                "Unable to write sense data to user %p\n",
                                ioc->name, __FILE__, __LINE__,
@@ -2270,9 +2443,8 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
        /* 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 ((ioc->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD) &&
+               (karg.dataInSize > 0) && (bufIn.kptr)) {
                if (copy_to_user(karg.dataInBufPtr,
                                 bufIn.kptr, karg.dataInSize)) {
                        printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
@@ -2285,9 +2457,8 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
 
 done_free_mem:
 
-       ioc->ioctl->status &= ~(MPT_IOCTL_STATUS_COMMAND_GOOD |
-               MPT_IOCTL_STATUS_SENSE_VALID |
-               MPT_IOCTL_STATUS_RF_VALID );
+       CLEAR_MGMT_STATUS(ioc->ioctl_cmds.status)
+       SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context, 0);
 
        /* Free the allocated memory.
         */
@@ -2327,16 +2498,17 @@ mptctl_hp_hostinfo(unsigned long arg, unsigned int data_size)
        hp_host_info_t  __user *uarg = (void __user *) arg;
        MPT_ADAPTER             *ioc;
        struct pci_dev          *pdev;
-       char                    *pbuf=NULL;
+       char                    *pbuf=NULL;
        dma_addr_t              buf_dma;
        hp_host_info_t          karg;
-       CONFIGPARMS             cfg;
-       ConfigPageHeader_t      hdr;
        int                     iocnum;
-       int                     rc, cim_rev;
+       int                     cim_rev;
        ToolboxIstwiReadWriteRequest_t  *IstwiRWRequest;
        MPT_FRAME_HDR           *mf = NULL;
        MPIHeader_t             *mpi_hdr;
+       unsigned long           timeleft;
+       int                     retval;
+       u32                     MsgContext;
 
        /* Reset long to int. Should affect IA64 and SPARC only
         */
@@ -2356,13 +2528,14 @@ mptctl_hp_hostinfo(unsigned long arg, unsigned int data_size)
 
        if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
            (ioc == NULL)) {
+               if (mpt_debug_level & MPT_DEBUG_IOCTL)
                printk(KERN_DEBUG MYNAM "%s::mptctl_hp_hostinfo() @%d - ioc%d not found!\n",
                                __FILE__, __LINE__, iocnum);
                return -ENODEV;
        }
+
        dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": mptctl_hp_hostinfo called.\n",
            ioc->name));
-
        /* Fill in the data and return the structure to the calling
         * program
         */
@@ -2402,42 +2575,9 @@ mptctl_hp_hostinfo(unsigned long arg, unsigned int data_size)
        karg.fw_version[10] = (ioc->facts.FWVersion.Struct.Dev % 10 ) + '0';
        karg.fw_version[11] = '\0';
 
-       /* 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.cfghdr.hdr = &hdr;
-       cfg.physAddr = -1;
-       cfg.pageAddr = 0;
-       cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
-       cfg.dir = 0;    /* read */
-       cfg.timeout = 10;
-
-       strncpy(karg.serial_number, " ", 24);
-       if (mpt_config(ioc, &cfg) == 0) {
-               if (cfg.cfghdr.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;
-                                       if (strlen(pdata->BoardTracerNumber) > 1) {
-                                               strncpy(karg.serial_number,                                                                         pdata->BoardTracerNumber, 24);
-                                               karg.serial_number[24-1]='\0';
-                                       }
-                               }
-                               pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, pbuf, buf_dma);
-                               pbuf = NULL;
-                       }
-               }
-       }
-       rc = mpt_GetIocState(ioc, 1);
-       switch (rc) {
+       strncpy(karg.serial_number, ioc->board_tracer, 16);
+
+       switch (mpt_GetIocState(ioc, 1)) {
        case MPI_IOC_STATE_OPERATIONAL:
                karg.ioc_status =  HP_STATUS_OK;
                break;
@@ -2464,12 +2604,12 @@ mptctl_hp_hostinfo(unsigned long arg, unsigned int data_size)
        karg.soft_resets = 0;
        karg.timeouts = 0;
        if (ioc->sh != NULL) {
-               MPT_SCSI_HOST *hd =  shost_priv(ioc->sh);
+               MPT_SCSI_HOST *hd =  (MPT_SCSI_HOST *)ioc->sh->hostdata;
 
                if (hd && (cim_rev == 1)) {
-                       karg.hard_resets = hd->hard_resets;
-                       karg.soft_resets = hd->soft_resets;
-                       karg.timeouts = hd->timeouts;
+                       karg.hard_resets = ioc->hard_resets;
+                       karg.soft_resets = ioc->soft_resets;
+                       karg.timeouts = ioc->timeouts;
                }
        }
 
@@ -2479,15 +2619,17 @@ mptctl_hp_hostinfo(unsigned long arg, unsigned int data_size)
        if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL) {
                dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n",
                    ioc->name,__FUNCTION__));
+               retval = -ENOMEM;
                goto out;
        }
 
        IstwiRWRequest = (ToolboxIstwiReadWriteRequest_t *)mf;
        mpi_hdr = (MPIHeader_t *) mf;
+       MsgContext = mpi_hdr->MsgContext;
        memset(IstwiRWRequest,0,sizeof(ToolboxIstwiReadWriteRequest_t));
        IstwiRWRequest->Function = MPI_FUNCTION_TOOLBOX;
        IstwiRWRequest->Tool = MPI_TOOLBOX_ISTWI_READ_WRITE_TOOL;
-       IstwiRWRequest->MsgContext = mpi_hdr->MsgContext;
+       IstwiRWRequest->MsgContext = MsgContext;
        IstwiRWRequest->Flags = MPI_TB_ISTWI_FLAGS_READ;
        IstwiRWRequest->NumAddressBytes = 0x01;
        IstwiRWRequest->DataLength = cpu_to_le16(0x04);
@@ -2497,28 +2639,30 @@ mptctl_hp_hostinfo(unsigned long arg, unsigned int data_size)
                IstwiRWRequest->DeviceAddr = 0xB0;
 
        pbuf = pci_alloc_consistent(ioc->pcidev, 4, &buf_dma);
-       if (!pbuf)
+       if (!pbuf) {
+               retval = -ENOMEM;
                goto out;
-       ioc->add_sge((char *)&IstwiRWRequest->SGL,
-           (MPT_SGE_FLAGS_SSIMPLE_READ|4), buf_dma);
+       }
+       ioc->add_sge((char *)&IstwiRWRequest->SGL, (MPT_SGE_FLAGS_SSIMPLE_READ|4),buf_dma);
 
-       ioc->ioctl->wait_done = 0;
+       retval = 0;
+       SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context, IstwiRWRequest->MsgContext);
+       INITIALIZE_MGMT_STATUS(ioc->ioctl_cmds.status)
        mpt_put_msg_frame(mptctl_id, ioc, mf);
-
-       rc = wait_event_timeout(mptctl_wait,
-            ioc->ioctl->wait_done == 1,
-            HZ*MPT_IOCTL_DEFAULT_TIMEOUT /* 10 sec */);
-
-       if(rc <=0 && (ioc->ioctl->wait_done != 1 )) {
-               /*
-                * Now we need to reset the board
-                */
-               mpt_free_msg_frame(ioc, mf);
-               mptctl_timeout_expired(ioc->ioctl);
+       timeleft = wait_for_completion_timeout(&ioc->ioctl_cmds.done, HZ*MPT_IOCTL_DEFAULT_TIMEOUT);
+       if (!(ioc->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
+               retval = -ETIME;
+               printk(MYIOC_s_WARN_FMT "%s: failed\n", ioc->name, __FUNCTION__);
+               if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) {
+                       mpt_free_msg_frame(ioc, mf);
+                       goto out;
+               }
+               if (!timeleft)
+                       mptctl_timeout_expired(ioc, mf);
                goto out;
        }
 
-       /*
+       /* 
         *ISTWI Data Definition
         * pbuf[0] = FW_VERSION = 0x4
         * pbuf[1] = Bay Count = 6 or 4 or 2, depending on
@@ -2527,10 +2671,13 @@ mptctl_hp_hostinfo(unsigned long arg, unsigned int data_size)
         *   bays have drives in them
         * pbuf[3] = Checksum (0x100 = (byte0 + byte2 + byte3)
         */
-       if (ioc->ioctl->status & MPT_IOCTL_STATUS_RF_VALID)
+       if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID)
                karg.rsvd = *(u32 *)pbuf;
 
  out:
+       CLEAR_MGMT_STATUS(ioc->ioctl_cmds.status)
+       SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context, 0);
+
        if (pbuf)
                pci_free_consistent(ioc->pcidev, 4, pbuf, buf_dma);
 
@@ -2543,7 +2690,7 @@ mptctl_hp_hostinfo(unsigned long arg, unsigned int data_size)
                return -EFAULT;
        }
 
-       return 0;
+       return retval;
 
 }
 
@@ -2583,13 +2730,14 @@ mptctl_hp_targetinfo(unsigned long arg)
 
        if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
                (ioc == NULL)) {
+               if (mpt_debug_level & MPT_DEBUG_IOCTL)
                printk(KERN_DEBUG MYNAM "%s::mptctl_hp_targetinfo() @%d - ioc%d not found!\n",
                                __FILE__, __LINE__, iocnum);
                return -ENODEV;
        }
-       dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_hp_targetinfo called.\n",
-           ioc->name));
 
+       dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": mptctl_hp_targetinfo called.\n",
+           ioc->name));
        /*  There is nothing to do for FCP parts.
         */
        if ((ioc->bus_type == SAS) || (ioc->bus_type == FC))
@@ -2681,7 +2829,7 @@ mptctl_hp_targetinfo(unsigned long arg)
                        pci_free_consistent(ioc->pcidev, data_sz, (u8 *) pg3_alloc, page_dma);
                }
        }
-       hd = shost_priv(ioc->sh);
+       hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
        if (hd != NULL)
                karg.select_timeouts = hd->sel_timeout[karg.hdr.id];
 
@@ -2699,7 +2847,7 @@ mptctl_hp_targetinfo(unsigned long arg)
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 
-static const struct file_operations mptctl_fops = {
+static struct file_operations mptctl_fops = {
        .owner =        THIS_MODULE,
        .llseek =       no_llseek,
        .release =      mptctl_release,
@@ -2739,8 +2887,9 @@ compat_mptfwxfer_ioctl(struct file *filp, unsigned int cmd,
        iocnumX = kfw32.iocnum & 0xFF;
        if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) ||
            (iocp == NULL)) {
+               if (mpt_debug_level & MPT_DEBUG_IOCTL)
                printk(KERN_DEBUG MYNAM "::compat_mptfwxfer_ioctl @%d - ioc%d not found!\n",
-                       __LINE__, iocnumX);
+                               __LINE__, iocnumX);
                return -ENODEV;
        }
 
@@ -2755,7 +2904,7 @@ compat_mptfwxfer_ioctl(struct file *filp, unsigned int cmd,
 
        ret = mptctl_do_fw_download(kfw.iocnum, kfw.bufp, kfw.fwlen);
 
-       mutex_unlock(&iocp->ioctl->ioctl_mutex);
+       mutex_unlock(&iocp->ioctl_cmds.mutex);
 
        return ret;
 }
@@ -2779,8 +2928,9 @@ compat_mpt_command(struct file *filp, unsigned int cmd,
        iocnumX = karg32.hdr.iocnum & 0xFF;
        if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) ||
            (iocp == NULL)) {
+               if (mpt_debug_level & MPT_DEBUG_IOCTL)
                printk(KERN_DEBUG MYNAM "::compat_mpt_command @%d - ioc%d not found!\n",
-                       __LINE__, iocnumX);
+                               __LINE__, iocnumX);
                return -ENODEV;
        }
 
@@ -2809,7 +2959,7 @@ compat_mpt_command(struct file *filp, unsigned int cmd,
         */
        ret = mptctl_do_mpt_command (karg, &uarg->MF);
 
-       mutex_unlock(&iocp->ioctl->ioctl_mutex);
+       mutex_unlock(&iocp->ioctl_cmds.mutex);
 
        return ret;
 }
@@ -2829,6 +2979,31 @@ static long compat_mpctl_ioctl(struct file *f, unsigned int cmd, unsigned long a
        case MPTHARDRESET:
        case HP_GETHOSTINFO:
        case HP_GETTARGETINFO:
+#if defined(CPQ_CIM)
+       case CC_CSMI_SAS_GET_DRIVER_INFO:
+       case CC_CSMI_SAS_GET_CNTLR_CONFIG:
+       case CC_CSMI_SAS_GET_CNTLR_STATUS:
+       case CC_CSMI_SAS_GET_SCSI_ADDRESS:
+       case CC_CSMI_SAS_GET_DEVICE_ADDRESS:
+       case CC_CSMI_SAS_GET_PHY_INFO:
+       case CC_CSMI_SAS_GET_SATA_SIGNATURE:
+       case CC_CSMI_SAS_GET_LINK_ERRORS:
+       case CC_CSMI_SAS_SMP_PASSTHRU:
+       case CC_CSMI_SAS_SSP_PASSTHRU:
+       case CC_CSMI_SAS_FIRMWARE_DOWNLOAD:
+       case CC_CSMI_SAS_GET_RAID_INFO:
+       case CC_CSMI_SAS_GET_RAID_CONFIG:
+       case CC_CSMI_SAS_GET_RAID_FEATURES:
+       case CC_CSMI_SAS_SET_RAID_CONTROL:
+       case CC_CSMI_SAS_GET_RAID_ELEMENT:
+       case CC_CSMI_SAS_SET_RAID_OPERATION:
+       case CC_CSMI_SAS_SET_PHY_INFO:
+       case CC_CSMI_SAS_STP_PASSTHRU:
+       case CC_CSMI_SAS_TASK_MANAGEMENT:
+       case CC_CSMI_SAS_PHY_CONTROL:
+       case CC_CSMI_SAS_GET_CONNECTOR_INFO:
+       case CC_CSMI_SAS_GET_LOCATION:
+#endif /* CPQ_CIM */
        case MPTTEST:
                ret = __mptctl_ioctl(f, cmd, arg);
                break;
@@ -2861,21 +3036,11 @@ static long compat_mpctl_ioctl(struct file *f, unsigned int cmd, unsigned long a
 static int
 mptctl_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
-       MPT_IOCTL *mem;
        MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
 
-       /*
-        * Allocate and inite a MPT_IOCTL structure
-       */
-       mem = kzalloc(sizeof(MPT_IOCTL), GFP_KERNEL);
-       if (!mem) {
-               mptctl_remove(pdev);
-               return -ENOMEM;
-       }
+       mutex_init(&ioc->ioctl_cmds.mutex);
+       init_completion(&ioc->ioctl_cmds.done);
 
-       ioc->ioctl = mem;
-       ioc->ioctl->ioc = ioc;
-       mutex_init(&ioc->ioctl->ioctl_mutex);
        return 0;
 }
 
@@ -2889,9 +3054,22 @@ mptctl_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 static void
 mptctl_remove(struct pci_dev *pdev)
 {
+#if defined(DIAG_BUFFER_SUPPORT)
        MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
+       int     i;
 
-       kfree ( ioc->ioctl );
+       /*
+        * Cleanup diag buffer allocated memory
+        */
+       for (i = 0; i < MPI_DIAG_BUF_TYPE_COUNT; i++) {
+               if (ioc->DiagBuffer[i] == NULL)
+                       continue;
+               pci_free_consistent(ioc->pcidev, ioc->DiagBuffer_sz[i],
+                   ioc->DiagBuffer[i], ioc->DiagBuffer_dma[i]);
+               ioc->DiagBuffer[i] = NULL;
+               ioc->DiagBuffer_Status[i] = 0;
+       }
+#endif
 }
 
 static struct mpt_pci_driver mptctl_driver = {
@@ -2931,6 +3109,7 @@ static int __init mptctl_init(void)
                goto out_fail;
        }
 
+       mptctl_taskmgmt_id = mpt_register(mptctl_taskmgmt_reply, MPTCTL_DRIVER);
        mpt_reset_register(mptctl_id, mptctl_ioc_reset);
        mpt_event_register(mptctl_id, mptctl_event_process);
 
@@ -2952,15 +3131,23 @@ static void mptctl_exit(void)
 
        /* De-register reset handler from base module */
        mpt_reset_deregister(mptctl_id);
+       mpt_reset_deregister(mptctl_taskmgmt_id);
 
        /* De-register callback handler from base module */
        mpt_deregister(mptctl_id);
 
         mpt_device_driver_deregister(MPTCTL_DRIVER);
-
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 
+#if defined(CPQ_CIM)
+#include "csmi/csmisas.c"
+#endif // CPQ_CIM
+
+#if defined(DIAG_BUFFER_SUPPORT)
+#include "rejected_ioctls/diag_buffer.c"
+#endif
+
 module_init(mptctl_init);
 module_exit(mptctl_exit);
index 2c1890127e155d18e2053a414ab26926c6e71d44..c9cd72b243aa69b3c3797d81b0e083412da65a13 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/message/fusion/mptioctl.h
+ *  linux/drivers/message/fusion/mptctl.h
  *      Fusion MPT misc device (ioctl) driver.
  *      For use with PCI chip/adapter(s):
  *          LSIFC9xx/LSI409xx Fibre Channel
@@ -458,9 +458,6 @@ typedef struct _hp_target_info {
 #define HP_DEV_SPEED_SCSI1     7
 #define HP_DEV_SPEED_ULTRA320  8
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-
-
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 
 #endif
index 34016a2a31ecd4d10967b71cfb06f5591d2b2cc3..233bde5ad7eb14ee3b606c03e260071fc5e8371a 100644 (file)
  *
  * Example:  (programming for MPT_DEBUG_EVENTS on host 5)
  *
+ * global setting:
+ * echo 8 > /sys/module/mptbase/parameters/mpt_debug_level
+ *
+ * per host setting:
  * echo 8 > /sys/class/scsi_host/host5/debug_level
  *
  * --------------------------------------------------------
@@ -55,6 +59,7 @@
 #define MPT_DEBUG_RESET                        0x00008000
 #define MPT_DEBUG_SCSI                 0x00010000
 #define MPT_DEBUG_IOCTL                        0x00020000
+#define MPT_DEBUG_CSMISAS              0x00040000
 #define MPT_DEBUG_FC                   0x00080000
 #define MPT_DEBUG_SAS                  0x00100000
 #define MPT_DEBUG_SAS_WIDE             0x00200000
 #define dctlprintk(IOC, CMD)                   \
        MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_IOCTL)
 
+#define dcsmisasprintk(IOC, CMD)               \
+       MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_CSMISAS)
+
 #define dfcprintk(IOC, CMD)                    \
        MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_FC)
 
 #define d36memprintk(IOC, CMD)         \
        MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_36GB_MEM)
 
-
 /*
  * Verbose logging
  */
index fce544e847c8c3c547061f3bb77d411402369c48..18e24593a9e4e2e023225c87f7343acc022f16dd 100644 (file)
@@ -43,6 +43,7 @@
     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/delay.h>       /* for mdelay */
 #include <linux/interrupt.h>   /* needed for in_interrupt() proto */
 #include <linux/reboot.h>      /* notifier code */
+#include <linux/sched.h>
 #include <linux/workqueue.h>
 #include <linux/sort.h>
+#include <linux/pci.h>
 
 #include <scsi/scsi.h>
 #include <scsi/scsi_cmnd.h>
@@ -62,6 +65,7 @@
 #include <scsi/scsi_tcq.h>
 #include <scsi/scsi_transport_fc.h>
 
+#include "linux_compat.h"      /* linux-2.6 tweaks */
 #include "mptbase.h"
 #include "mptscsih.h"
 
@@ -84,6 +88,14 @@ MODULE_PARM_DESC(mptfc_dev_loss_tmo, " Initial time the driver programs the "
                                     " return following a device loss event."
                                     "  Default=60.");
 
+static int mpt_sdev_queue_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
+static int mptfc_set_sdev_queue_depth(const char *val, struct kernel_param *kp);
+module_param_call(mpt_sdev_queue_depth, mptfc_set_sdev_queue_depth,
+    param_get_int,  &mpt_sdev_queue_depth, 0600);
+MODULE_PARM_DESC(mpt_sdev_queue_depth,
+    " Max Device Queue Depth (default="
+    __MODULE_STRING(MPT_SCSI_CMD_PER_DEV_HIGH) ")");
+
 /* scsi-mid layer global parmeter is max_report_luns, which is 511 */
 #define MPTFC_MAX_LUN (16895)
 static int max_lun = MPTFC_MAX_LUN;
@@ -183,6 +195,34 @@ static struct fc_function_template mptfc_transport_functions = {
        .show_host_symbolic_name = 1,
 };
 
+/**
+ *     mptfc_set_sdev_queue_depth - global setting of the mpt_sdev_queue_depth
+ *     found via /sys/module/mptfc/parameters/mpt_sdev_queue_depth
+ *     @val:
+ *     @kp:
+ *
+ *     Returns
+ **/
+static int
+mptfc_set_sdev_queue_depth(const char *val, struct kernel_param *kp)
+{
+       int ret = param_set_int(val, kp);
+       MPT_ADAPTER *ioc;
+       struct scsi_device      *sdev;
+
+       if (ret)
+               return ret;
+
+       list_for_each_entry(ioc, &ioc_list, list) {
+               if (ioc->bus_type != FC)
+                       continue;
+               shost_for_each_device(sdev, ioc->sh)
+                       mptscsih_change_queue_depth(sdev, mpt_sdev_queue_depth);
+               ioc->sdev_queue_depth = mpt_sdev_queue_depth;
+       }
+       return 0;
+}
+
 static int
 mptfc_block_error_handler(struct scsi_cmnd *SCpnt,
                          int (*func)(struct scsi_cmnd *SCpnt),
@@ -194,9 +234,9 @@ mptfc_block_error_handler(struct scsi_cmnd *SCpnt,
        struct fc_rport         *rport = starget_to_rport(scsi_target(sdev));
        unsigned long           flags;
        int                     ready;
-       MPT_ADAPTER             *ioc;
+       MPT_ADAPTER             *ioc;
 
-       hd = shost_priv(SCpnt->device->host);
+       hd = shost_private(SCpnt->device->host);
        ioc = hd->ioc;
        spin_lock_irqsave(shost->host_lock, flags);
        while ((ready = fc_remote_port_chkready(rport) >> 16) == DID_IMM_RETRY) {
@@ -476,6 +516,7 @@ mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0)
                                if (vtarget) {
                                        vtarget->id = pg0->CurrentTargetID;
                                        vtarget->channel = pg0->CurrentBus;
+                                       vtarget->deleted = 0;
                                }
                        }
                        *((struct mptfc_rport_info **)rport->dd_data) = ri;
@@ -513,6 +554,7 @@ mptfc_target_destroy(struct scsi_target *starget)
        struct fc_rport         *rport;
        struct mptfc_rport_info *ri;
 
+       printk("%s - starget=%p\n", __FUNCTION__, starget);
        rport = starget_to_rport(starget);
        if (rport) {
                ri = *((struct mptfc_rport_info **)rport->dd_data);
@@ -560,6 +602,7 @@ mptfc_target_alloc(struct scsi_target *starget)
 
        return rc;
 }
+
 /*
  *     mptfc_dump_lun_info
  *     @ioc
@@ -589,7 +632,6 @@ mptfc_dump_lun_info(MPT_ADAPTER *ioc, struct fc_rport *rport, struct scsi_device
                (unsigned long long)nn));
 }
 
-
 /*
  *     OS entry point to allow host driver to alloc memory
  *     for each scsi device. Called once per device the bus scan.
@@ -604,7 +646,7 @@ mptfc_slave_alloc(struct scsi_device *sdev)
        VirtDevice              *vdevice;
        struct scsi_target      *starget;
        struct fc_rport         *rport;
-       MPT_ADAPTER             *ioc;
+       MPT_ADAPTER             *ioc;
 
        starget = scsi_target(sdev);
        rport = starget_to_rport(starget);
@@ -612,13 +654,12 @@ mptfc_slave_alloc(struct scsi_device *sdev)
        if (!rport || fc_remote_port_chkready(rport))
                return -ENXIO;
 
-       hd = shost_priv(sdev->host);
+       hd = shost_private(sdev->host);
        ioc = hd->ioc;
-
        vdevice = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
        if (!vdevice) {
                printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n",
-                               ioc->name, sizeof(VirtDevice));
+                   ioc->name, sizeof(VirtDevice));
                return -ENOMEM;
        }
 
@@ -635,10 +676,7 @@ mptfc_slave_alloc(struct scsi_device *sdev)
        vdevice->lun = sdev->lun;
 
        vtarget->num_luns++;
-
-
        mptfc_dump_lun_info(ioc, rport, sdev, vtarget);
-
        return 0;
 }
 
@@ -944,11 +982,12 @@ start_over:
        return rc;
 }
 
-static void
+static int
 mptfc_SetFcPortPage1_defaults(MPT_ADAPTER *ioc)
 {
        int             ii;
        FCPortPage1_t   *pp1;
+       int             rc;
 
        #define MPTFC_FW_DEVICE_TIMEOUT (1)
        #define MPTFC_FW_IO_PEND_TIMEOUT (1)
@@ -956,8 +995,8 @@ mptfc_SetFcPortPage1_defaults(MPT_ADAPTER *ioc)
        #define OFF_FLAGS (MPI_FCPORTPAGE1_FLAGS_VERBOSE_RESCAN_EVENTS)
 
        for (ii=0; ii<ioc->facts.NumberOfPorts; ii++) {
-               if (mptfc_GetFcPortPage1(ioc, ii) != 0)
-                       continue;
+               if ((rc = mptfc_GetFcPortPage1(ioc, ii)) < 0)
+                       return rc;
                pp1 = ioc->fc_data.fc_port_page1[ii].data;
                if ((pp1->InitiatorDeviceTimeout == MPTFC_FW_DEVICE_TIMEOUT)
                 && (pp1->InitiatorIoPendTimeout == MPTFC_FW_IO_PEND_TIMEOUT)
@@ -968,8 +1007,10 @@ mptfc_SetFcPortPage1_defaults(MPT_ADAPTER *ioc)
                pp1->InitiatorIoPendTimeout = MPTFC_FW_IO_PEND_TIMEOUT;
                pp1->Flags &= ~OFF_FLAGS;
                pp1->Flags |= ON_FLAGS;
-               mptfc_WriteFcPortPage1(ioc, ii);
+               if ((rc = mptfc_WriteFcPortPage1(ioc, ii)) < 0)
+                       return rc;
        }
+       return 0;
 }
 
 
@@ -1068,9 +1109,16 @@ mptfc_init_host_attr(MPT_ADAPTER *ioc,int portnum)
 }
 
 static void
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19))
+mptfc_link_status_change(struct work_struct *work)
+{
+       MPT_ADAPTER             *ioc =
+               container_of(work, MPT_ADAPTER, fc_rescan_work);
+#else
 mptfc_link_status_change(void *arg)
 {
        MPT_ADAPTER             *ioc = (MPT_ADAPTER *)arg;
+#endif
        int ii;
 
        for (ii=0; ii < ioc->facts.NumberOfPorts; ii++)
@@ -1079,11 +1127,21 @@ mptfc_link_status_change(void *arg)
 }
 
 static void
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19))
+mptfc_setup_reset(struct work_struct *work)
+{
+       MPT_ADAPTER             *ioc =
+               container_of(work, MPT_ADAPTER, fc_setup_reset_work);
+#else
 mptfc_setup_reset(void *arg)
 {
        MPT_ADAPTER             *ioc = (MPT_ADAPTER *)arg;
+#endif
        u64                     pn;
        struct mptfc_rport_info *ri;
+       struct scsi_target      *starget;
+       VirtTarget              *vtarget;
+
 
        /* reset about to happen, delete (block) all rports */
        list_for_each_entry(ri, &ioc->fc_rports, list) {
@@ -1091,6 +1149,12 @@ mptfc_setup_reset(void *arg)
                        ri->flags &= ~MPT_RPORT_INFO_FLAGS_REGISTERED;
                        fc_remote_port_delete(ri->rport);       /* won't sleep */
                        ri->rport = NULL;
+                       starget = ri->starget;
+                       if (starget) {
+                               vtarget = starget->hostdata;
+                               if (vtarget)
+                                       vtarget->deleted = 1;
+                       }
 
                        pn = (u64)ri->pg0.WWPN.High << 32 |
                             (u64)ri->pg0.WWPN.Low;
@@ -1104,12 +1168,33 @@ mptfc_setup_reset(void *arg)
 }
 
 static void
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19))
+mptfc_rescan_devices(struct work_struct *work)
+{
+       MPT_ADAPTER             *ioc =
+               container_of(work, MPT_ADAPTER, fc_rescan_work);
+#else
 mptfc_rescan_devices(void *arg)
 {
        MPT_ADAPTER             *ioc = (MPT_ADAPTER *)arg;
+#endif
        int                     ii;
+       int                     rc;
        u64                     pn;
        struct mptfc_rport_info *ri;
+       struct scsi_target      *starget;
+       VirtTarget              *vtarget;
+
+       /*
+        * if cannot set defaults, something's really wrong, bail out
+        */
+
+       if ((rc = mptfc_SetFcPortPage1_defaults(ioc)) < 0) {
+               dfcprintk (ioc, printk(MYIOC_s_DEBUG_FMT
+                   "mptfc_rescan.%d: unable to set PP1 defaults, rc %d.\n",
+                   ioc->name, ioc->sh->host_no, rc));
+               return;
+       }
 
        /* start by tagging all ports as missing */
        list_for_each_entry(ri, &ioc->fc_rports, list) {
@@ -1137,6 +1222,12 @@ mptfc_rescan_devices(void *arg)
                                       MPT_RPORT_INFO_FLAGS_MISSING);
                        fc_remote_port_delete(ri->rport);       /* won't sleep */
                        ri->rport = NULL;
+                       starget = ri->starget;
+                       if (starget) {
+                               vtarget = starget->hostdata;
+                               if (vtarget)
+                                       vtarget->deleted = 1;
+                       }
 
                        pn = (u64)ri->pg0.WWPN.High << 32 |
                             (u64)ri->pg0.WWPN.Low;
@@ -1215,9 +1306,15 @@ mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
         }
 
        spin_lock_init(&ioc->fc_rescan_work_lock);
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19))
+       INIT_WORK(&ioc->fc_rescan_work, mptfc_rescan_devices);
+       INIT_WORK(&ioc->fc_setup_reset_work, mptfc_setup_reset);
+       INIT_WORK(&ioc->fc_lsc_work, mptfc_link_status_change);
+#else
        INIT_WORK(&ioc->fc_rescan_work, mptfc_rescan_devices,(void *)ioc);
-       INIT_WORK(&ioc->fc_setup_reset_work, mptfc_setup_reset,(void *)ioc);
-       INIT_WORK(&ioc->fc_lsc_work, mptfc_link_status_change,(void *)ioc);
+       INIT_WORK(&ioc->fc_setup_reset_work, mptfc_setup_reset, (void *)ioc);
+       INIT_WORK(&ioc->fc_lsc_work, mptfc_link_status_change, (void *)ioc);
+#endif
 
        spin_lock_irqsave(&ioc->FreeQlock, flags);
 
@@ -1237,6 +1334,8 @@ mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 
        sh->this_id = ioc->pfacts[0].PortSCSIID;
 
+       ioc->sdev_queue_depth = mpt_sdev_queue_depth;
+
        /* Required entry.
         */
        sh->unique_id = ioc->id;
@@ -1273,7 +1372,7 @@ mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 
        spin_unlock_irqrestore(&ioc->FreeQlock, flags);
 
-       hd = shost_priv(sh);
+       hd = shost_private(sh);
        hd->ioc = ioc;
 
        /* SCSI needs scsi_cmnd lookup table!
@@ -1289,30 +1388,6 @@ mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n",
                 ioc->name, ioc->ScsiLookup));
 
-       /* Clear the TM flags
-        */
-       hd->tmPending = 0;
-       hd->tmState = TM_STATE_NONE;
-       hd->resetPending = 0;
-       hd->abortSCpnt = NULL;
-
-       /* Clear the pointer used to store
-        * single-threaded commands, i.e., those
-        * issued during a bus scan, dv and
-        * configuration pages.
-        */
-       hd->cmdPtr = NULL;
-
-       /* Initialize this SCSI Hosts' timers
-        * To use, set the timer expires field
-        * and add_timer
-        */
-       init_timer(&hd->timer);
-       hd->timer.data = (unsigned long) hd;
-       hd->timer.function = mptscsih_timer_expired;
-
-       init_waitqueue_head(&hd->scandv_waitq);
-       hd->scandv_wait_done = 0;
        hd->last_queue_full = 0;
 
        sh->transportt = mptfc_transport_template;
@@ -1339,7 +1414,6 @@ mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {
                (void) mptfc_GetFcPortPage0(ioc, ii);
        }
-       mptfc_SetFcPortPage1_defaults(ioc);
 
        /*
         * scan for rports -
@@ -1377,11 +1451,8 @@ mptfc_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
        unsigned long flags;
        int rc=1;
 
-       devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n",
-                       ioc->name, event));
-
        if (ioc->sh == NULL ||
-               ((hd = shost_priv(ioc->sh)) == NULL))
+               ((hd = shost_private(ioc->sh)) == NULL))
                return 1;
 
        switch (event) {
@@ -1415,45 +1486,45 @@ mptfc_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
        unsigned long   flags;
 
        rc = mptscsih_ioc_reset(ioc,reset_phase);
-       if (rc == 0)
+       if ((ioc->bus_type != FC) || (!rc))
                return rc;
 
-
-       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
-               ": IOC %s_reset routed to FC host driver!\n",ioc->name,
-               reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
-               reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
-
-       if (reset_phase == MPT_IOC_SETUP_RESET) {
+       switch(reset_phase) {
+       case MPT_IOC_SETUP_RESET:
+               dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __FUNCTION__));
                spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);
                if (ioc->fc_rescan_work_q) {
                        queue_work(ioc->fc_rescan_work_q,
                                   &ioc->fc_setup_reset_work);
                }
                spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
-       }
-
-       else if (reset_phase == MPT_IOC_PRE_RESET) {
-       }
-
-       else {  /* MPT_IOC_POST_RESET */
-               mptfc_SetFcPortPage1_defaults(ioc);
+               break;
+       case MPT_IOC_PRE_RESET:
+               dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "%s: MPT_IOC_PRE_RESET\n", ioc->name, __FUNCTION__));
+               break;
+       case MPT_IOC_POST_RESET:
+               dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "%s: MPT_IOC_POST_RESET\n",  ioc->name, __FUNCTION__));
                spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);
                if (ioc->fc_rescan_work_q) {
                        queue_work(ioc->fc_rescan_work_q,
                                   &ioc->fc_rescan_work);
                }
                spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
+               break;
+       default:
+               break;
        }
        return 1;
 }
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *     mptfc_init - Register MPT adapter(s) as SCSI host(s) with SCSI mid-layer.
  *
  *     Returns 0 for success, non-zero for failure.
- */
+ **/
 static int __init
 mptfc_init(void)
 {
@@ -1485,12 +1556,11 @@ mptfc_init(void)
        return error;
 }
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *     mptfc_remove - Remove fc infrastructure for devices
  *     @pdev: Pointer to pci_dev structure
  *
- */
+ **/
 static void __devexit
 mptfc_remove(struct pci_dev *pdev)
 {
@@ -1500,6 +1570,8 @@ mptfc_remove(struct pci_dev *pdev)
        unsigned long           flags;
        int                     ii;
 
+       printk("%s -pdev=%p\n", __FUNCTION__, pdev);
+
        /* destroy workqueue */
        if ((work_q=ioc->fc_rescan_work_q)) {
                spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);
@@ -1542,7 +1614,6 @@ mptfc_exit(void)
 
        mpt_reset_deregister(mptfcDoneCtx);
        mpt_event_deregister(mptfcDoneCtx);
-
        mpt_deregister(mptfcInternalCtx);
        mpt_deregister(mptfcTaskCtx);
        mpt_deregister(mptfcDoneCtx);
index e1b0af07347eb097672097945dd2ba2abdec9a3c..0cb1fb669acd9870efbed64ebb5f5b739fcba872 100644 (file)
@@ -6,7 +6,6 @@
  *
  *  Copyright (c) 2000-2007 LSI Corporation
  *  (mailto:DL-MPTFusionLinux@lsi.com)
- *
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -53,6 +52,7 @@
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 
 #include "mptlan.h"
+#include <linux/version.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/fs.h>
@@ -113,7 +113,13 @@ struct mpt_lan_priv {
        u32 total_posted;
        u32 total_received;
        struct net_device_stats stats;  /* Per device statistics */
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19))
+       struct delayed_work post_buckets_task;
+       struct net_device *dev;
+#else
        struct work_struct post_buckets_task;
+#endif
        unsigned long post_buckets_active;
 };
 
@@ -134,7 +140,11 @@ static int  lan_reply (MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf,
 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);
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19))
+static void mpt_lan_post_receive_buckets(struct mpt_lan_priv *priv);
+#else
 static void mpt_lan_post_receive_buckets(void *dev_id);
+#endif
 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);
@@ -162,6 +172,11 @@ static struct NAA_Hosed *mpt_bad_naa = NULL;
 DEFINE_RWLOCK(bad_naa_lock);
 #endif
 
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * Fusion MPT LAN external data
+ */
+
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *     lan_reply - Handle all data sent from the hardware.
@@ -188,8 +203,7 @@ lan_reply (MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply)
                u32 tmsg = CAST_PTR_TO_U32(reply);
 
                dioprintk((KERN_INFO MYNAM ": %s/%s: @lan_reply, tmsg %08x\n",
-                               IOC_AND_NETDEV_NAMES_s_s(dev),
-                               tmsg));
+                   IOC_AND_NETDEV_NAMES_s_s(dev), tmsg));
 
                switch (GET_LAN_FORM(tmsg)) {
 
@@ -341,7 +355,11 @@ mpt_lan_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
                        priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = i;
                spin_unlock_irqrestore(&priv->rxfidx_lock, flags);
        } else {
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19))
+               mpt_lan_post_receive_buckets(priv);
+#else
                mpt_lan_post_receive_buckets(dev);
+#endif
                netif_wake_queue(dev);
        }
 
@@ -437,7 +455,12 @@ mpt_lan_open(struct net_device *dev)
 
        dlprintk((KERN_INFO MYNAM "/lo: Finished initializing RcvCtl\n"));
 
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19))
+       mpt_lan_post_receive_buckets(priv);
+#else
        mpt_lan_post_receive_buckets(dev);
+#endif
+
        printk(KERN_INFO MYNAM ": %s/%s: interface up & active\n",
                        IOC_AND_NETDEV_NAMES_s_s(dev));
 
@@ -706,7 +729,9 @@ mpt_lan_sdu_send (struct sk_buff *skb, struct net_device *dev)
        LANSendRequest_t *pSendReq;
        SGETransaction32_t *pTrans;
        SGESimple64_t *pSimple;
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,20))
        const unsigned char *mac;
+#endif
        dma_addr_t dma;
        unsigned long flags;
        int ctx;
@@ -746,7 +771,11 @@ mpt_lan_sdu_send (struct sk_buff *skb, struct net_device *dev)
        /* Set the mac.raw pointer, since this apparently isn't getting
         * done before we get the skb. Pull the data pointer past the mac data.
         */
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,20))
        skb_reset_mac_header(skb);
+#else
+       skb->mac.raw = skb->data;
+#endif
        skb_pull(skb, 12);
 
         dma = pci_map_single(mpt_dev->pcidev, skb->data, skb->len,
@@ -777,7 +806,10 @@ mpt_lan_sdu_send (struct sk_buff *skb, struct net_device *dev)
 //                     IOC_AND_NETDEV_NAMES_s_s(dev),
 //                     ctx, skb, skb->data));
 
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,20))
        mac = skb_mac_header(skb);
+#endif
+
 #ifdef QLOGIC_NAA_WORKAROUND
 {
        struct NAA_Hosed *nh;
@@ -787,12 +819,21 @@ mpt_lan_sdu_send (struct sk_buff *skb, struct net_device *dev)
           drops. */
        read_lock_irq(&bad_naa_lock);
        for (nh = mpt_bad_naa; nh != NULL; nh=nh->next) {
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,20))
                if ((nh->ieee[0] == mac[0]) &&
                    (nh->ieee[1] == mac[1]) &&
                    (nh->ieee[2] == mac[2]) &&
                    (nh->ieee[3] == mac[3]) &&
                    (nh->ieee[4] == mac[4]) &&
                    (nh->ieee[5] == mac[5])) {
+#else
+               if ((nh->ieee[0] == skb->mac.raw[0]) &&
+                   (nh->ieee[1] == skb->mac.raw[1]) &&
+                   (nh->ieee[2] == skb->mac.raw[2]) &&
+                   (nh->ieee[3] == skb->mac.raw[3]) &&
+                   (nh->ieee[4] == skb->mac.raw[4]) &&
+                   (nh->ieee[5] == skb->mac.raw[5])) {
+#endif
                        cur_naa = nh->NAA;
                        dlprintk ((KERN_INFO "mptlan/sdu_send: using NAA value "
                                  "= %04x.\n", cur_naa));
@@ -803,6 +844,8 @@ mpt_lan_sdu_send (struct sk_buff *skb, struct net_device *dev)
 }
 #endif
 
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,20))
        pTrans->TransactionDetails[0] = cpu_to_le32((cur_naa         << 16) |
                                                    (mac[0] <<  8) |
                                                    (mac[1] <<  0));
@@ -810,6 +853,15 @@ mpt_lan_sdu_send (struct sk_buff *skb, struct net_device *dev)
                                                    (mac[3] << 16) |
                                                    (mac[4] <<  8) |
                                                    (mac[5] <<  0));
+#else
+       pTrans->TransactionDetails[0] = cpu_to_le32((cur_naa         << 16) |
+                                                   (skb->mac.raw[0] <<  8) |
+                                                   (skb->mac.raw[1] <<  0));
+       pTrans->TransactionDetails[1] = cpu_to_le32((skb->mac.raw[2] << 24) |
+                                                   (skb->mac.raw[3] << 16) |
+                                                   (skb->mac.raw[4] <<  8) |
+                                                   (skb->mac.raw[5] <<  0));
+#endif
 
        pSimple = (SGESimple64_t *) &pTrans->TransactionDetails[2];
 
@@ -924,7 +976,11 @@ mpt_lan_receive_post_turbo(struct net_device *dev, u32 tmsg)
                pci_dma_sync_single_for_cpu(mpt_dev->pcidev, priv->RcvCtl[ctx].dma,
                                            priv->RcvCtl[ctx].len, PCI_DMA_FROMDEVICE);
 
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,20))
                skb_copy_from_linear_data(old_skb, skb_put(skb, len), len);
+#else
+               memcpy(skb_put(skb, len), old_skb->data, len);
+#endif
 
                pci_dma_sync_single_for_device(mpt_dev->pcidev, priv->RcvCtl[ctx].dma,
                                               priv->RcvCtl[ctx].len, PCI_DMA_FROMDEVICE);
@@ -1085,7 +1141,11 @@ mpt_lan_receive_post_reply(struct net_device *dev,
                                                    priv->RcvCtl[ctx].dma,
                                                    priv->RcvCtl[ctx].len,
                                                    PCI_DMA_FROMDEVICE);
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,20))
                        skb_copy_from_linear_data(old_skb, skb_put(skb, l), l);
+#else
+                       memcpy(skb_put(skb, l), old_skb->data, l);
+#endif
 
                        pci_dma_sync_single_for_device(mpt_dev->pcidev,
                                                       priv->RcvCtl[ctx].dma,
@@ -1114,8 +1174,11 @@ mpt_lan_receive_post_reply(struct net_device *dev,
                                            priv->RcvCtl[ctx].len,
                                            PCI_DMA_FROMDEVICE);
 
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,20))
                skb_copy_from_linear_data(old_skb, skb_put(skb, len), len);
-
+#else
+               memcpy(skb_put(skb, len), old_skb->data, len);
+#endif
                pci_dma_sync_single_for_device(mpt_dev->pcidev,
                                               priv->RcvCtl[ctx].dma,
                                               priv->RcvCtl[ctx].len,
@@ -1186,10 +1249,16 @@ mpt_lan_receive_post_reply(struct net_device *dev,
 /* Simple SGE's only at the moment */
 
 static void
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19))
+mpt_lan_post_receive_buckets(struct mpt_lan_priv *priv)
+{
+       struct net_device *dev = priv->dev;
+#else
 mpt_lan_post_receive_buckets(void *dev_id)
 {
        struct net_device *dev = dev_id;
        struct mpt_lan_priv *priv = dev->priv;
+#endif
        MPT_ADAPTER *mpt_dev = priv->mpt_dev;
        MPT_FRAME_HDR *mf;
        LANReceivePostRequest_t *pRecvReq;
@@ -1334,15 +1403,24 @@ out:
 
        clear_bit(0, &priv->post_buckets_active);
 }
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19))
+static void
+mpt_lan_post_receive_buckets_work(struct work_struct *work)
+{
+       mpt_lan_post_receive_buckets(container_of(work, struct mpt_lan_priv,
+               post_buckets_task.work));
+}
+#endif
+
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 static struct net_device *
 mpt_register_lan_device (MPT_ADAPTER *mpt_dev, int pnum)
 {
-       struct net_device *dev;
-       struct mpt_lan_priv *priv;
+       struct net_device *dev = alloc_fcdev(sizeof(struct mpt_lan_priv));
+       struct mpt_lan_priv *priv = NULL;
        u8 HWaddr[FC_ALEN], *a;
 
-       dev = alloc_fcdev(sizeof(struct mpt_lan_priv));
        if (!dev)
                return NULL;
 
@@ -1350,12 +1428,20 @@ mpt_register_lan_device (MPT_ADAPTER *mpt_dev, int pnum)
 
        priv = netdev_priv(dev);
 
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19))
+       priv->dev = dev;
+#endif
        priv->mpt_dev = mpt_dev;
        priv->pnum = pnum;
 
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19))
        memset(&priv->post_buckets_task, 0, sizeof(priv->post_buckets_task));
+       INIT_DELAYED_WORK(&priv->post_buckets_task,
+               mpt_lan_post_receive_buckets_work);
+#else
        memset(&priv->post_buckets_task, 0, sizeof(struct work_struct));
        INIT_WORK(&priv->post_buckets_task, mpt_lan_post_receive_buckets, dev);
+#endif
        priv->post_buckets_active = 0;
 
        dlprintk((KERN_INFO MYNAM "@%d: bucketlen = %d\n",
@@ -1414,7 +1500,9 @@ mpt_register_lan_device (MPT_ADAPTER *mpt_dev, int pnum)
        dlprintk((KERN_INFO MYNAM ": Finished registering dev "
                "and setting initial values\n"));
 
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23))
        SET_MODULE_OWNER(dev);
+#endif
 
        if (register_netdev(dev) != 0) {
                free_netdev(dev);
@@ -1533,7 +1621,11 @@ 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;
 
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,20))
        skb_reset_mac_header(skb);
+#else
+       skb->mac.raw = skb->data;
+#endif
        skb_pull(skb, sizeof(struct mpt_lan_ohdr));
 
        if (fch->dtype == htons(0xffff)) {
index bafb67fc81813d4ccfbceaa8ca70fb06234995a2..816aac99898e8a267d83ae6bf102fd28b07bf7c8 100644 (file)
@@ -6,7 +6,6 @@
  *
  *  Copyright (c) 2000-2007 LSI Corporation
  *  (mailto:DL-MPTFusionLinux@lsi.com)
- *
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -55,6 +54,7 @@
 #include <linux/module.h>
 #endif
 
+#include <linux/version.h>
 #include <linux/netdevice.h>
 #include <linux/errno.h>
 // #include <linux/etherdevice.h>
@@ -73,6 +73,7 @@
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
+#include <linux/pci.h>
 
     /* Override mptbase.h by pre-defining these! */
 #define MODULEAUTHOR   "LSI Corporation"
index 44e6e3deddee0ead9aff8cc463cfb51538925856..6972533fab163ebdc9e05668dd8fd31c53702be6 100644 (file)
@@ -5,7 +5,6 @@
  *
  *  Copyright (c) 1999-2007 LSI Corporation
  *  (mailto:DL-MPTFusionLinux@lsi.com)
- *  Copyright (c) 2005-2007 Dell
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-
+#include "linux_compat.h"       /* linux-2.6 tweaks */
+#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/errno.h>
-#include <linux/jiffies.h>
+#include <linux/sched.h>
 #include <linux/workqueue.h>
 #include <linux/delay.h>       /* for mdelay */
+#include <linux/pci.h>
 
 #include <scsi/scsi.h>
 #include <scsi/scsi_cmnd.h>
 #include <scsi/scsi_transport_sas.h>
 #include <scsi/scsi_dbg.h>
 
+#include "linux_compat.h"      /* linux-2.6 tweaks */
 #include "mptbase.h"
 #include "mptscsih.h"
-#include "mptsas.h"
 
+/* The glue to get a single driver working in both
+ * SLES10 and RHEL5 environments
+ */
+#if (defined(CONFIG_SUSE_KERNEL) && defined(scsi_is_sas_phy_local)) || LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18)
+#define MPT_WIDE_PORT_API      1
+#define MPT_WIDE_PORT_API_PLUS 1
+#endif
+
+#include "mptsas.h"
 
 #define my_NAME                "Fusion MPT SAS Host driver"
 #define my_VERSION     MPT_LINUX_VERSION_COMMON
 /*
  * Reserved channel for integrated raid
  */
+#if defined(MPT_WIDE_PORT_API)
 #define MPTSAS_RAID_CHANNEL    1
+#else
+#define MPTSAS_RAID_CHANNEL    8
+#endif
+
+#define SAS_CONFIG_PAGE_TIMEOUT                30
 
 MODULE_AUTHOR(MODULEAUTHOR);
 MODULE_DESCRIPTION(my_NAME);
@@ -84,6 +100,25 @@ MODULE_PARM_DESC(mpt_pt_clear,
                " Clear persistency table: enable=1  "
                "(default=MPTSCSIH_PT_CLEAR=0)");
 
+static int mpt_cmd_retry_count = 144;
+module_param(mpt_cmd_retry_count, int, 0);
+MODULE_PARM_DESC(mpt_cmd_retry_count,
+               " Device discovery TUR command retry count: default=144");
+
+static int mpt_disable_hotplug_remove = 0;
+module_param(mpt_disable_hotplug_remove, int, 0);
+MODULE_PARM_DESC(mpt_disable_hotplug_remove,
+               " Disable hotpug remove events: default=0");
+
+static int mpt_sdev_queue_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
+static int mptsas_set_sdev_queue_depth(const char *val,
+    struct kernel_param *kp);
+module_param_call(mpt_sdev_queue_depth, mptsas_set_sdev_queue_depth,
+    param_get_int, &mpt_sdev_queue_depth, 0600);
+MODULE_PARM_DESC(mpt_sdev_queue_depth,
+    " Max Device Queue Depth (default="
+    __MODULE_STRING(MPT_SCSI_CMD_PER_DEV_HIGH) ")");
+
 /* scsi-mid layer global parmeter is max_report_luns, which is 511 */
 #define MPTSAS_MAX_LUN (16895)
 static int max_lun = MPTSAS_MAX_LUN;
@@ -94,8 +129,52 @@ static u8   mptsasDoneCtx = MPT_MAX_PROTOCOL_DRIVERS;
 static u8      mptsasTaskCtx = MPT_MAX_PROTOCOL_DRIVERS;
 static u8      mptsasInternalCtx = MPT_MAX_PROTOCOL_DRIVERS; /* Used only for internal commands */
 static u8      mptsasMgmtCtx = MPT_MAX_PROTOCOL_DRIVERS;
+static u8      mptsasDeviceResetCtx = MPT_MAX_PROTOCOL_DRIVERS;
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19))
+static void mptsas_hotplug_work(struct work_struct *work);
+#else
+static void mptsas_hotplug_work(void *arg);
+#endif
+
+#if defined(CPQ_CIM)
+static struct mptsas_phyinfo * mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc,
+       u64 sas_address);
+static int mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info,
+       u32 form, u32 form_specific);
+static int mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure,
+               u32 form, u32 form_specific);
+#endif
+
+static int mptsas_add_end_device(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info);
+
+/**
+ *     mptsas_set_sdev_queue_depth - global setting of the mpt_sdev_queue_depth
+ *     found via /sys/module/mptsas/parameters/mpt_sdev_queue_depth
+ *     @val:
+ *     @kp:
+ *
+ *     Returns
+ **/
+static int
+mptsas_set_sdev_queue_depth(const char *val, struct kernel_param *kp)
+{
+       int ret = param_set_int(val, kp);
+       MPT_ADAPTER *ioc;
+       struct scsi_device      *sdev;
+
+       if (ret)
+               return ret;
 
-static void mptsas_hotplug_work(void* arg);
+       list_for_each_entry(ioc, &ioc_list, list) {
+               if (ioc->bus_type != SAS)
+                       continue;
+               shost_for_each_device(sdev, ioc->sh)
+                       mptscsih_change_queue_depth(sdev, mpt_sdev_queue_depth);
+               ioc->sdev_queue_depth = mpt_sdev_queue_depth;
+       }
+       return 0;
+}
 
 static void mptsas_print_phy_data(MPT_ADAPTER *ioc,
                                        MPI_SAS_IO_UNIT0_PHY_DATA *phy_data)
@@ -219,23 +298,40 @@ static void mptsas_print_expander_pg1(MPT_ADAPTER *ioc, SasExpanderPage1_t *pg1)
            le16_to_cpu(pg1->AttachedDevHandle)));
 }
 
-static inline MPT_ADAPTER *phy_to_ioc(struct sas_phy *phy)
+/**
+ *     phy_to_ioc -
+ *     @phy:
+ *
+ *
+ **/
+static inline MPT_ADAPTER *
+phy_to_ioc(struct sas_phy *phy)
 {
        struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
        return ((MPT_SCSI_HOST *)shost->hostdata)->ioc;
 }
 
-static inline MPT_ADAPTER *rphy_to_ioc(struct sas_rphy *rphy)
+/**
+ *     rphy_to_ioc -
+ *     @rphy:
+ *
+ *
+ **/
+static inline MPT_ADAPTER *
+rphy_to_ioc(struct sas_rphy *rphy)
 {
        struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent);
        return ((MPT_SCSI_HOST *)shost->hostdata)->ioc;
 }
 
-/*
- * mptsas_find_portinfo_by_handle
+/**
+ *     mptsas_find_portinfo_by_handle -
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @handle:
  *
- * This function should be called with the sas_topology_mutex already held
- */
+ *     This function should be called with the sas_topology_mutex already held
+ *
+ **/
 static struct mptsas_portinfo *
 mptsas_find_portinfo_by_handle(MPT_ADAPTER *ioc, u16 handle)
 {
@@ -252,9 +348,39 @@ mptsas_find_portinfo_by_handle(MPT_ADAPTER *ioc, u16 handle)
        return rc;
 }
 
-/*
- * Returns true if there is a scsi end device
- */
+/**
+ *     mptsas_find_portinfo_by_sas_address -
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @handle:
+ *
+ *     This function should be called with the sas_topology_mutex already held
+ *
+ **/
+static struct mptsas_portinfo *
+mptsas_find_portinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address)
+{
+       struct mptsas_portinfo *port_info, *rc=NULL;
+       int i;
+
+       mutex_lock(&ioc->sas_topology_mutex);
+       list_for_each_entry(port_info, &ioc->sas_topology, list)
+               for (i = 0; i < port_info->num_phys; i++)
+                       if (port_info->phy_info[i].identify.sas_address ==
+                           sas_address) {
+                               rc = port_info;
+                               goto out;
+                       }
+ out:
+       mutex_unlock(&ioc->sas_topology_mutex);
+       return rc;
+}
+
+/**
+ *     mptsas_is_end_device -
+ *     @attached:
+ *
+ *     Returns true if there is a scsi end device
+ **/
 static inline int
 mptsas_is_end_device(struct mptsas_devinfo * attached)
 {
@@ -272,7 +398,52 @@ mptsas_is_end_device(struct mptsas_devinfo * attached)
                return 0;
 }
 
-/* no mutex */
+/**
+ *     mptsas_get_rphy -
+ *     @phy_info:
+ *
+ **/
+static inline struct sas_rphy *
+mptsas_get_rphy(struct mptsas_phyinfo *phy_info)
+{
+       if (phy_info->port_details)
+               return phy_info->port_details->rphy;
+       else
+               return NULL;
+}
+
+/**
+ *     mptsas_set_rphy -
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @phy_info:
+ *     @rphy:
+ *
+ **/
+static inline void
+mptsas_set_rphy(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, struct sas_rphy *rphy)
+{
+       if (phy_info->port_details) {
+               phy_info->port_details->rphy = rphy;
+               dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "sas_rphy_add: rphy=%p\n", ioc->name, rphy));
+       }
+
+       if (rphy) {
+               dsaswideprintk(ioc, dev_printk(KERN_DEBUG,
+                   &rphy->dev, MYIOC_s_FMT "add:", ioc->name));
+               dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "rphy=%p release=%p\n",
+                   ioc->name, rphy, rphy->dev.release));
+       }
+}
+
+/**
+ *     mptsas_port_delete -
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @port_details:
+ *
+ *     (no mutex)
+ *
+ **/
 static void
 mptsas_port_delete(MPT_ADAPTER *ioc, struct mptsas_portinfo_details * port_details)
 {
@@ -286,46 +457,51 @@ mptsas_port_delete(MPT_ADAPTER *ioc, struct mptsas_portinfo_details * port_detai
        port_info = port_details->port_info;
        phy_info = port_info->phy_info;
 
+#if defined(MPT_WIDE_PORT_API)
        dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: [%p]: num_phys=%02d "
            "bitmask=0x%016llX\n", ioc->name, __FUNCTION__, port_details,
            port_details->num_phys, (unsigned long long)
            port_details->phy_bitmask));
+#else
+       dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: [%p]: port=%02d num_phys=%02d "
+           "rphy=%02d bitmask=0x%016llX\n", ioc->name, __FUNCTION__, port_details,
+           port_details->port_id,  port_details->num_phys,
+           port_details->rphy_id, (unsigned long long)
+           port_details->phy_bitmask));
+#endif
 
        for (i = 0; i < port_info->num_phys; i++, phy_info++) {
                if(phy_info->port_details != port_details)
                        continue;
                memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
+               mptsas_set_rphy(ioc, phy_info, NULL);
                phy_info->port_details = NULL;
        }
        kfree(port_details);
 }
 
-static inline struct sas_rphy *
-mptsas_get_rphy(struct mptsas_phyinfo *phy_info)
+#if !defined(MPT_WIDE_PORT_API)
+/**
+ *     mptsas_get_rphy_id -
+ *     @phy_info:
+ *
+ **/
+static inline u8
+mptsas_get_rphy_id(struct mptsas_phyinfo *phy_info)
 {
        if (phy_info->port_details)
-               return phy_info->port_details->rphy;
+               return phy_info->port_details->rphy_id;
        else
-               return NULL;
-}
-
-static inline void
-mptsas_set_rphy(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, struct sas_rphy *rphy)
-{
-       if (phy_info->port_details) {
-               phy_info->port_details->rphy = rphy;
-               dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "sas_rphy_add: rphy=%p\n",
-                   ioc->name, rphy));
-       }
-
-       if (rphy) {
-               dsaswideprintk(ioc, dev_printk(KERN_DEBUG,
-                   &rphy->dev, MYIOC_s_FMT "add:", ioc->name));
-               dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "rphy=%p release=%p\n",
-                   ioc->name, rphy, rphy->dev.release));
-       }
+               return 0xFF;
 }
+#endif
 
+#if defined(MPT_WIDE_PORT_API)
+/**
+ *     mptsas_get_port -
+ *     @phy_info:
+ *
+ **/
 static inline struct sas_port *
 mptsas_get_port(struct mptsas_phyinfo *phy_info)
 {
@@ -335,6 +511,13 @@ mptsas_get_port(struct mptsas_phyinfo *phy_info)
                return NULL;
 }
 
+/**
+ *     mptsas_set_port -
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @phy_info:
+ *     @port:
+ *
+ **/
 static inline void
 mptsas_set_port(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, struct sas_port *port)
 {
@@ -348,7 +531,13 @@ mptsas_set_port(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, struct sas_po
                    ioc->name, port, port->dev.release));
        }
 }
+#endif
 
+/**
+ *     mptsas_get_starget -
+ *     @phy_info:
+ *
+ **/
 static inline struct scsi_target *
 mptsas_get_starget(struct mptsas_phyinfo *phy_info)
 {
@@ -358,6 +547,12 @@ mptsas_get_starget(struct mptsas_phyinfo *phy_info)
                return NULL;
 }
 
+/**
+ *     mptsas_set_starget -
+ *     @phy_info:
+ *     @starget:
+ *
+ **/
 static inline void
 mptsas_set_starget(struct mptsas_phyinfo *phy_info, struct scsi_target *
 starget)
@@ -366,140 +561,476 @@ starget)
                phy_info->port_details->starget = starget;
 }
 
-
-/*
- * mptsas_setup_wide_ports
+#if defined(CPQ_CIM)
+/**
+ *     mptsas_add_device_component -
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @channel: fw mapped id's
+ *     @id:
+ *     @sas_address:
+ *     @device_info:
  *
- * Updates for new and existing narrow/wide port configuration
- * in the sas_topology
- */
+ **/
 static void
-mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
+mptsas_add_device_component(MPT_ADAPTER *ioc, u8 channel, u8 id,
+       u64 sas_address, u32 device_info, u16 slot, u64 enclosure_logical_id)
 {
-       struct mptsas_portinfo_details * port_details;
-       struct mptsas_phyinfo *phy_info, *phy_info_cmp;
-       u64     sas_address;
-       int     i, j;
+       struct sas_device_info  *sas_info, *next;
+       struct scsi_device      *sdev;
+       struct scsi_target      *starget;
+       struct sas_rphy         *rphy;
 
-       mutex_lock(&ioc->sas_topology_mutex);
+       down(&ioc->sas_device_info_mutex);
 
-       phy_info = port_info->phy_info;
-       for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) {
-               if (phy_info->attached.handle)
-                       continue;
-               port_details = phy_info->port_details;
-               if (!port_details)
-                       continue;
-               if (port_details->num_phys < 2)
+       /*
+        * Delete all matching sas_address's out of tree
+        */
+       list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list, list) {
+               if (sas_info->sas_address != sas_address)
                        continue;
-               /*
-                * Removing a phy from a port, letting the last
-                * phy be removed by firmware events.
-                */
-               dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
-                   "%s: [%p]: deleting phy = %d\n",
-                   ioc->name, __FUNCTION__, port_details, i));
-               port_details->num_phys--;
-               port_details->phy_bitmask &= ~ (1 << phy_info->phy_id);
-               memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
-               sas_port_delete_phy(port_details->port, phy_info->phy);
-               phy_info->port_details = NULL;
+               list_del(&sas_info->list);
+               kfree(sas_info);
        }
 
        /*
-        * Populate and refresh the tree
+        * If there is a matching channel/id, then swap out with new target info
         */
-       phy_info = port_info->phy_info;
-       for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) {
-               sas_address = phy_info->attached.sas_address;
-               dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "phy_id=%d sas_address=0x%018llX\n",
-                   ioc->name, i, (unsigned long long)sas_address));
-               if (!sas_address)
-                       continue;
-               port_details = phy_info->port_details;
-               /*
-                * Forming a port
-                */
-               if (!port_details) {
-                       port_details = kzalloc(sizeof(*port_details),
-                               GFP_KERNEL);
-                       if (!port_details)
-                               goto out;
-                       port_details->num_phys = 1;
-                       port_details->port_info = port_info;
-                       if (phy_info->phy_id < 64 )
-                               port_details->phy_bitmask |=
-                                   (1 << phy_info->phy_id);
-                       phy_info->sas_port_add_phy=1;
-                       dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tForming port\n\t\t"
-                           "phy_id=%d sas_address=0x%018llX\n",
-                           ioc->name, i, (unsigned long long)sas_address));
-                       phy_info->port_details = port_details;
-               }
+       list_for_each_entry(sas_info, &ioc->sas_device_info_list, list) {
+               if (sas_info->fw.channel == channel && sas_info->fw.id == id)
+                       goto initialize_data;
+       }
 
-               if (i == port_info->num_phys - 1)
-                       continue;
-               phy_info_cmp = &port_info->phy_info[i + 1];
-               for (j = i + 1 ; j < port_info->num_phys ; j++,
-                   phy_info_cmp++) {
-                       if (!phy_info_cmp->attached.sas_address)
-                               continue;
-                       if (sas_address != phy_info_cmp->attached.sas_address)
-                               continue;
-                       if (phy_info_cmp->port_details == port_details )
-                               continue;
-                       dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
-                           "\t\tphy_id=%d sas_address=0x%018llX\n",
-                           ioc->name, j, (unsigned long long)
-                           phy_info_cmp->attached.sas_address));
-                       if (phy_info_cmp->port_details) {
-                               port_details->rphy =
-                                   mptsas_get_rphy(phy_info_cmp);
-                               port_details->port =
-                                   mptsas_get_port(phy_info_cmp);
-                               port_details->starget =
-                                   mptsas_get_starget(phy_info_cmp);
-                               port_details->num_phys =
-                                       phy_info_cmp->port_details->num_phys;
-                               if (!phy_info_cmp->port_details->num_phys)
-                                       kfree(phy_info_cmp->port_details);
-                       } else
-                               phy_info_cmp->sas_port_add_phy=1;
-                       /*
-                        * Adding a phy to a port
-                        */
-                       phy_info_cmp->port_details = port_details;
-                       if (phy_info_cmp->phy_id < 64 )
-                               port_details->phy_bitmask |=
-                               (1 << phy_info_cmp->phy_id);
-                       port_details->num_phys++;
+       if (!(sas_info = kzalloc(sizeof(*sas_info), GFP_KERNEL)))
+               goto out;
+
+       /*
+        * Set Firmware mapping
+        */
+       sas_info->fw.id = id;
+       sas_info->fw.channel = channel;
+       list_add_tail(&sas_info->list, &ioc->sas_device_info_list);
+
+ initialize_data:
+
+       sas_info->sas_address = sas_address;
+       sas_info->device_info = device_info;
+       sas_info->slot = slot;
+       sas_info->enclosure_logical_id = enclosure_logical_id;
+       sas_info->is_cached = 0;
+       sas_info->is_logical_volume = 0;
+
+       /*
+        * Set OS mapping
+        */
+       shost_for_each_device(sdev, ioc->sh) {
+               starget = scsi_target(sdev);
+               rphy = dev_to_rphy(starget->dev.parent);
+               if (rphy->identify.sas_address == sas_address) {
+                       sas_info->os.id = starget->id;
+                       sas_info->os.channel = starget->channel;
                }
        }
 
  out:
+       up(&ioc->sas_device_info_mutex);
+       return;
+}
 
-       for (i = 0; i < port_info->num_phys; i++) {
-               port_details = port_info->phy_info[i].port_details;
-               if (!port_details)
-                       continue;
-               dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
-                   "%s: [%p]: phy_id=%02d num_phys=%02d "
-                   "bitmask=0x%016llX\n", ioc->name, __FUNCTION__,
-                   port_details, i, port_details->num_phys,
-                   (unsigned long long)port_details->phy_bitmask));
-               dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tport = %p rphy=%p\n",
-                   ioc->name, port_details->port, port_details->rphy));
-       }
-       dsaswideprintk(ioc, printk("\n"));
-       mutex_unlock(&ioc->sas_topology_mutex);
+/**
+ *     mptsas_add_device_component_by_fw -
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @channel:  fw mapped id's
+ *     @id:
+ *
+ **/
+static void
+mptsas_add_device_component_by_fw(MPT_ADAPTER *ioc, u8 channel, u8 id)
+{
+       struct mptsas_devinfo sas_device;
+       struct mptsas_enclosure enclosure_info;
+       int rc;
+
+       rc = mptsas_sas_device_pg0(ioc, &sas_device,
+           (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
+            MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
+           (channel << 8) + id);
+       if (rc)
+               return;
+
+       memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
+       mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
+           (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
+            MPI_SAS_ENCLOS_PGAD_FORM_SHIFT),
+            sas_device.handle_enclosure);
+
+       mptsas_add_device_component(ioc, sas_device.channel,
+           sas_device.id, sas_device.sas_address, sas_device.device_info,
+           sas_device.slot, enclosure_info.enclosure_logical_id);
 }
 
 /**
- * csmisas_find_vtarget
+ *     mptsas_add_device_component_starget_ir - Handle Integrated RAID, adding
+ *     each individual device to list
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @channel: fw mapped id's
+ *     @id:
  *
- * @ioc
- * @volume_id
- * @volume_bus
+ **/
+static void
+mptsas_add_device_component_starget_ir(MPT_ADAPTER *ioc, struct scsi_target *starget)
+{
+       CONFIGPARMS                     cfg;
+       ConfigPageHeader_t              hdr;
+       dma_addr_t                      dma_handle;
+       pRaidVolumePage0_t              buffer = NULL;
+       int                             i;
+       RaidPhysDiskPage0_t             phys_disk;
+       struct sas_device_info          *sas_info;
+
+       memset(&cfg, 0 , sizeof(CONFIGPARMS));
+       memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
+       hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
+       cfg.pageAddr = starget->id; /* assumption that all volumes on channel = 0 */
+       cfg.cfghdr.hdr = &hdr;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+       cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
+
+       if (mpt_config(ioc, &cfg) != 0)
+               goto out;
+
+       if (!hdr.PageLength)
+               goto out;
+
+       buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
+           &dma_handle);
+
+       if (!buffer)
+               goto out;
+
+       cfg.physAddr = dma_handle;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+
+       if (mpt_config(ioc, &cfg) != 0)
+               goto out;
+
+       if (!buffer->NumPhysDisks)
+               goto out;
+
+       /*
+        * Adding entry for hidden components
+        */
+       for (i = 0; i < buffer->NumPhysDisks; i++) {
+
+               if(mpt_raid_phys_disk_pg0(ioc,
+                   buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
+                       continue;
+
+               mptsas_add_device_component_by_fw(ioc, phys_disk.PhysDiskBus,
+                   phys_disk.PhysDiskID);
+       }
+
+       /*
+        * Adding entry for logical volume in list
+        */
+       list_for_each_entry(sas_info, &ioc->sas_device_info_list, list) {
+               if (sas_info->fw.channel == 0 && sas_info->fw.id ==  starget->id)
+                       goto initialize_data;
+       }
+
+       if (!(sas_info = kzalloc(sizeof(*sas_info), GFP_KERNEL)))
+               goto out;
+
+       sas_info->fw.id = starget->id;
+       sas_info->fw.channel = 0; /* channel zero */
+       down(&ioc->sas_device_info_mutex);
+       list_add_tail(&sas_info->list, &ioc->sas_device_info_list);
+       up(&ioc->sas_device_info_mutex);
+
+ initialize_data:
+
+       sas_info->os.id = starget->id;
+       sas_info->os.channel = starget->channel;
+       sas_info->sas_address = 0;
+       sas_info->device_info = 0;
+       sas_info->slot = 0;
+       sas_info->enclosure_logical_id = 0;
+       sas_info->is_logical_volume = 1;
+       sas_info->is_cached = 0;
+
+ out:
+       if (buffer)
+               pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
+                   dma_handle);
+}
+
+/**
+ *     mptsas_add_device_component_starget -
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @starget:
+ *
+ **/
+static void
+mptsas_add_device_component_starget(MPT_ADAPTER *ioc, struct scsi_target *starget)
+{
+       VirtTarget              *vtarget;
+       struct sas_rphy         *rphy;
+       struct mptsas_phyinfo *phy_info = NULL;
+       struct mptsas_enclosure enclosure_info;
+
+       rphy = dev_to_rphy(starget->dev.parent);
+       vtarget = starget->hostdata;
+       phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
+                   rphy->identify.sas_address);
+       if (!phy_info)
+               return;
+
+       memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
+       mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
+           (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
+            MPI_SAS_ENCLOS_PGAD_FORM_SHIFT),
+            phy_info->attached.handle_enclosure);
+
+       mptsas_add_device_component(ioc, phy_info->attached.channel,
+           phy_info->attached.id, phy_info->attached.sas_address,
+           phy_info->attached.device_info,
+           phy_info->attached.slot, enclosure_info.enclosure_logical_id);
+}
+
+/**
+ *     mptsas_del_device_component_by_os - Once a device has been removed, we
+ *     mark the entry in the list as being cached
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @channel: os mapped id's
+ *     @id:
+ *
+ **/
+static void
+mptsas_del_device_component_by_os(MPT_ADAPTER *ioc, u8 channel, u8 id)
+{
+       struct sas_device_info  *sas_info, *next;
+
+       /*
+        * Set is_cached flag
+        */
+       list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list, list) {
+               if (sas_info->os.channel == channel && sas_info->os.id == id)
+                       sas_info->is_cached = 1;
+       }
+}
+
+/**
+ *     mptsas_del_device_components - Cleaning the list
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *
+ **/
+static void
+mptsas_del_device_components(MPT_ADAPTER *ioc)
+{
+       struct sas_device_info  *sas_info, *next;
+
+       down(&ioc->sas_device_info_mutex);
+       list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list, list) {
+               list_del(&sas_info->list);
+               kfree(sas_info);
+       }
+       up(&ioc->sas_device_info_mutex);
+}
+#endif
+
+/**
+ *     mptsas_setup_wide_ports - Updates for new and existing narrow/wide port
+ *     configuration
+ *     in the sas_topology
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @port_info:
+ *
+ */
+static void
+mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
+{
+       struct mptsas_portinfo_details * port_details;
+       struct mptsas_phyinfo *phy_info, *phy_info_cmp;
+       u64     sas_address;
+#if !defined(MPT_WIDE_PORT_API)
+       u8      found_wide_port;
+#endif
+       int     i, j;
+
+       mutex_lock(&ioc->sas_topology_mutex);
+
+       phy_info = port_info->phy_info;
+       for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) {
+               if (phy_info->attached.handle)
+                       continue;
+               port_details = phy_info->port_details;
+               if (!port_details)
+                       continue;
+               if (port_details->num_phys < 2)
+                       continue;
+
+               /*
+                * Removing a phy from a port, letting the last
+                * phy be removed by firmware events.
+                */
+#if defined(MPT_WIDE_PORT_API)
+               dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                       "%s: [%p]: deleting phy = %d\n",
+                       ioc->name, __FUNCTION__, port_details, i));
+#else
+               dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                       "%s: [%p]: port=%d deleting phy = %d\n",
+                       ioc->name, __FUNCTION__, port_details,
+                       port_details->port_id, i));
+#endif
+               port_details->num_phys--;
+               port_details->phy_bitmask &= ~ (1 << phy_info->phy_id);
+               memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
+#if defined(MPT_WIDE_PORT_API)
+               devtprintk(ioc, dev_printk(KERN_DEBUG, &phy_info->phy->dev,
+                   MYIOC_s_FMT "delete phy %d, phy-obj (0x%p)\n", ioc->name,
+                    phy_info->phy_id, phy_info->phy));
+               sas_port_delete_phy(port_details->port, phy_info->phy);
+               phy_info->phy = NULL;
+#endif
+               phy_info->port_details = NULL;
+       }
+
+       /*
+        * Populate and refresh the tree
+        */
+       phy_info = port_info->phy_info;
+       for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) {
+               sas_address = phy_info->attached.sas_address;
+               dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "phy_id=%d sas_address=0x%018llX\n",
+                   ioc->name, i, (unsigned long long)sas_address));
+               if (!sas_address)
+                       continue;
+               port_details = phy_info->port_details;
+               /*
+                * Forming a port
+                */
+               if (!port_details) {
+                       port_details = kzalloc(sizeof(*port_details),
+                               GFP_KERNEL);
+                       if (!port_details)
+                               goto out;
+                       port_details->num_phys = 1;
+                       port_details->port_info = port_info;
+#if !defined(MPT_WIDE_PORT_API)
+                       port_details->port_id = phy_info->port_id;
+                       port_details->rphy_id = i;
+                       port_details->device_info = phy_info->attached.device_info;
+#endif
+                       if (phy_info->phy_id < 64 )
+                               port_details->phy_bitmask |=
+                                   (1 << phy_info->phy_id);
+#if defined(MPT_WIDE_PORT_API)
+                       phy_info->sas_port_add_phy=1;
+#endif
+                       dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tForming port\n\t\t"
+                           "phy_id=%d sas_address=0x%018llX\n", ioc->name, i,
+                           (unsigned long long) sas_address));
+                       phy_info->port_details = port_details;
+               }
+
+               if (i == port_info->num_phys - 1)
+                       continue;
+               phy_info_cmp = &port_info->phy_info[i + 1];
+#if !defined(MPT_WIDE_PORT_API)
+               found_wide_port = 0;
+#endif
+               for (j = i + 1 ; j < port_info->num_phys ; j++,
+                   phy_info_cmp++) {
+                       if (!phy_info_cmp->attached.sas_address)
+                               continue;
+                       if (sas_address != phy_info_cmp->attached.sas_address)
+                               continue;
+#if !defined(MPT_WIDE_PORT_API)
+                       found_wide_port = 1;
+#endif
+                       if (phy_info_cmp->port_details == port_details )
+                               continue;
+                       dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                           "\t\tphy_id=%d sas_address=0x%018llX\n",
+                           ioc->name, j, (unsigned long long)
+                           phy_info_cmp->attached.sas_address));
+                       if (phy_info_cmp->port_details) {
+                               port_details->rphy =
+                                   mptsas_get_rphy(phy_info_cmp);
+#if defined(MPT_WIDE_PORT_API)
+                               port_details->port =
+                                   mptsas_get_port(phy_info_cmp);
+#endif
+                               port_details->starget =
+                                   mptsas_get_starget(phy_info_cmp);
+#if !defined(MPT_WIDE_PORT_API)
+                               port_details->port_id =
+                                       phy_info_cmp->port_details->port_id;
+                               port_details->rphy_id =
+                                       phy_info_cmp->port_details->rphy_id;
+#endif
+                               port_details->num_phys =
+                                       phy_info_cmp->port_details->num_phys;
+                               if (!phy_info_cmp->port_details->num_phys)
+                                       kfree(phy_info_cmp->port_details);
+#if defined(MPT_WIDE_PORT_API)
+                       } else
+                               phy_info_cmp->sas_port_add_phy=1;
+#else
+                       }
+#endif
+                       /*
+                        * Adding a phy to a port
+                        */
+                       phy_info_cmp->port_details = port_details;
+                       if (phy_info_cmp->phy_id < 64 )
+                               port_details->phy_bitmask |=
+                               (1 << phy_info_cmp->phy_id);
+                       port_details->num_phys++;
+#if !defined(MPT_WIDE_PORT_API)
+                       phy_info_cmp->attached.wide_port_enable = 1;
+#endif
+               }
+#if !defined(MPT_WIDE_PORT_API)
+               phy_info->attached.wide_port_enable = (found_wide_port) ? 1:0;
+#endif
+       }
+
+ out:
+
+       for (i = 0; i < port_info->num_phys; i++) {
+               port_details = port_info->phy_info[i].port_details;
+               if (!port_details)
+                       continue;
+#if defined(MPT_WIDE_PORT_API)
+               dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "%s: [%p]: phy_id=%02d num_phys=%02d "
+                   "bitmask=0x%016llX\n", ioc->name, __FUNCTION__,
+                   port_details, i, port_details->num_phys,
+                   (unsigned long long)port_details->phy_bitmask));
+               dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tport = %p rphy=%p\n",
+                   ioc->name, port_details->port, port_details->rphy));
+#else
+               dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                       "%s: [%p]: phy=%02d port=%02d num_phys=%02d "
+                       "rphy=%02d bitmask=0x%016llX\n",
+                       ioc->name, __FUNCTION__,
+                       port_details, i, port_details->port_id,
+                       port_details->num_phys, port_details->rphy_id,
+                       (unsigned long long)port_details->phy_bitmask));
+               dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "\t\trphy=%p\n", ioc->name, port_details->rphy));
+#endif
+       }
+       dsaswideprintk(ioc, printk("\n"));
+       mutex_unlock(&ioc->sas_topology_mutex);
+}
+
+/**
+ *     csmisas_find_vtarget -
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @volume_id:
+ *     @volume_bus:
  *
  **/
 static VirtTarget *
@@ -510,7 +1041,8 @@ mptsas_find_vtarget(MPT_ADAPTER *ioc, u8 channel, u8 id)
        VirtTarget                      *vtarget = NULL;
 
        shost_for_each_device(sdev, ioc->sh) {
-               if ((vdevice = sdev->hostdata) == NULL)
+               if ((vdevice = sdev->hostdata) == NULL ||
+                       (vdevice->vtarget == NULL))
                        continue;
                if (vdevice->vtarget->id == id &&
                    vdevice->vtarget->channel == channel)
@@ -520,16 +1052,14 @@ mptsas_find_vtarget(MPT_ADAPTER *ioc, u8 channel, u8 id)
 }
 
 /**
- * mptsas_target_reset
- *
- * Issues TARGET_RESET to end device using handshaking method
+ *     mptsas_target_reset - Issues TARGET_RESET to end device using
+ *     handshaking method
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @channel:
+ *     @id:
  *
- * @ioc
- * @channel
- * @id
- *
- * Returns (1) success
- *         (0) failure
+ *     Returns (1) success
+ *             (0) failure
  *
  **/
 static int
@@ -538,12 +1068,18 @@ mptsas_target_reset(MPT_ADAPTER *ioc, u8 channel, u8 id)
        MPT_FRAME_HDR   *mf;
        SCSITaskMgmt_t  *pScsiTm;
 
-       if ((mf = mpt_get_msg_frame(ioc->TaskCtx, ioc)) == NULL) {
+       if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0)
+               return 0;
+
+       if ((mf = mpt_get_msg_frame(mptsasDeviceResetCtx, ioc)) == NULL) {
                dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames @%d!!\n",
                    ioc->name,__FUNCTION__, __LINE__));
-               return 0;
+               goto out_fail;
        }
 
+       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request (mf=%p)\n",
+               ioc->name, mf));
+
        /* Format the Request
         */
        pScsiTm = (SCSITaskMgmt_t *) mf;
@@ -556,29 +1092,34 @@ mptsas_target_reset(MPT_ADAPTER *ioc, u8 channel, u8 id)
 
        DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)mf);
 
-       mpt_put_msg_frame_hi_pri(ioc->TaskCtx, ioc, mf);
+       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt type=%d (sas device delete) fw_channel = %d fw_id = %d)\n",
+           ioc->name, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET, channel, id));
+
+       mpt_put_msg_frame_hi_pri(mptsasDeviceResetCtx, ioc, mf);
 
        return 1;
+
+ out_fail:
+
+       mpt_clear_taskmgmt_in_progress_flag(ioc);
+       return 0;
 }
 
 /**
- * mptsas_target_reset_queue
- *
- * Receive request for TARGET_RESET after recieving an firmware
- * event NOT_RESPONDING_EVENT, then put command in link list
- * and queue if task_queue already in use.
- *
- * @ioc
- * @sas_event_data
+ *     mptsas_target_reset_queue - Receive request for TARGET_RESET after
+ *     recieving an firmware event NOT_RESPONDING_EVENT, then put command in
+ *     link list and queue if task_queue already in use.
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @sas_event_data:
  *
  **/
 static void
 mptsas_target_reset_queue(MPT_ADAPTER *ioc,
     EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data)
 {
-       MPT_SCSI_HOST   *hd = shost_priv(ioc->sh);
+       MPT_SCSI_HOST   *hd = shost_private(ioc->sh);
        VirtTarget *vtarget = NULL;
-       struct mptsas_target_reset_event *target_reset_list;
+       struct mptsas_target_reset_event        *target_reset_list;
        u8              id, channel;
 
        id = sas_event_data->TargetID;
@@ -587,7 +1128,8 @@ mptsas_target_reset_queue(MPT_ADAPTER *ioc,
        if (!(vtarget = mptsas_find_vtarget(ioc, channel, id)))
                return;
 
-       vtarget->deleted = 1; /* block IO */
+       if (!ioc->disable_hotplug_remove)
+               vtarget->deleted = 1; /* block IO */
 
        target_reset_list = kzalloc(sizeof(*target_reset_list),
            GFP_ATOMIC);
@@ -601,55 +1143,94 @@ mptsas_target_reset_queue(MPT_ADAPTER *ioc,
                sizeof(*sas_event_data));
        list_add_tail(&target_reset_list->list, &hd->target_reset_list);
 
-       if (hd->resetPending)
-               return;
+       target_reset_list->time_count = jiffies;
 
-       if (mptsas_target_reset(ioc, channel, id)) {
+       if (mptsas_target_reset(ioc, channel, id))
                target_reset_list->target_reset_issued = 1;
-               hd->resetPending = 1;
-       }
 }
 
 /**
- * mptsas_dev_reset_complete
- *
- * Completion for TARGET_RESET after NOT_RESPONDING_EVENT,
- * enable work queue to finish off removing device from upper layers.
- * then send next TARGET_RESET in the queue.
- *
- * @ioc
+ *     mptsas_taskmgmt_complete - Completion for TARGET_RESET after
+ *     NOT_RESPONDING_EVENT, enable work queue to finish off removing device
+ *     from upper layers. then send next TARGET_RESET in the queue.
+ *     @ioc: Pointer to MPT_ADAPTER structure
  *
  **/
-static void
-mptsas_dev_reset_complete(MPT_ADAPTER *ioc)
+static int
+mptsas_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
 {
-       MPT_SCSI_HOST   *hd = shost_priv(ioc->sh);
+       MPT_SCSI_HOST   *hd = shost_private(ioc->sh);
         struct list_head *head = &hd->target_reset_list;
-       struct mptsas_target_reset_event *target_reset_list;
+       struct mptsas_target_reset_event        *target_reset_list;
        struct mptsas_hotplug_event *ev;
        EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data;
        u8              id, channel;
        __le64          sas_address;
+       SCSITaskMgmtReply_t *pScsiTmReply;
+
+       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt completed: "
+           "(mf = %p, mr = %p)\n", ioc->name, mf, mr));
+
+       pScsiTmReply = (SCSITaskMgmtReply_t *)mr;
+       if (pScsiTmReply) {
+               dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "\tTaskMgmt completed: fw_channel = %d, fw_id = %d,\n"
+                   "\ttask_type = 0x%02X, iocstatus = 0x%04X "
+                   "loginfo = 0x%08X,\n\tresponse_code = 0x%02X, "
+                   "term_cmnds = %d\n", ioc->name,
+                   pScsiTmReply->Bus, pScsiTmReply->TargetID,
+                   pScsiTmReply->TaskType,
+                   le16_to_cpu(pScsiTmReply->IOCStatus),
+                   le32_to_cpu(pScsiTmReply->IOCLogInfo),
+                   pScsiTmReply->ResponseCode,
+                   le32_to_cpu(pScsiTmReply->TerminationCount)));
+
+               if (pScsiTmReply->ResponseCode)
+                       mptscsih_taskmgmt_response_code(ioc,
+                       pScsiTmReply->ResponseCode);
+       }
+
+       if (pScsiTmReply && (pScsiTmReply->TaskType ==
+           MPI_SCSITASKMGMT_TASKTYPE_QUERY_TASK || pScsiTmReply->TaskType ==
+            MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET)) {
+               ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
+               ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
+               memcpy(ioc->taskmgmt_cmds.reply, mr,
+                   min(MPT_DEFAULT_FRAME_SIZE, 4 * mr->u.reply.MsgLength));
+               if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) {
+                       ioc->taskmgmt_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
+                       complete(&ioc->taskmgmt_cmds.done);
+                       return 1;
+               }
+               return 0;
+       }
+
+       mpt_clear_taskmgmt_in_progress_flag(ioc);
 
        if (list_empty(head))
-               return;
+               return 1;
+
+       target_reset_list = list_entry(head->next,
+           struct mptsas_target_reset_event, list);
 
-       target_reset_list = list_entry(head->next, struct mptsas_target_reset_event, list);
+       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+           "TaskMgmt: completed (%d seconds)\n",
+           ioc->name, jiffies_to_msecs(jiffies -
+           target_reset_list->time_count)/1000));
 
        sas_event_data = &target_reset_list->sas_event_data;
        id = sas_event_data->TargetID;
        channel = sas_event_data->Bus;
-       hd->resetPending = 0;
+
+       target_reset_list->time_count = jiffies;
 
        /*
         * retry target reset
         */
        if (!target_reset_list->target_reset_issued) {
-               if (mptsas_target_reset(ioc, channel, id)) {
+               if (mptsas_target_reset(ioc, channel, id))
                        target_reset_list->target_reset_issued = 1;
-                       hd->resetPending = 1;
-               }
-               return;
+               return 1;
        }
 
        /*
@@ -659,25 +1240,28 @@ mptsas_dev_reset_complete(MPT_ADAPTER *ioc)
 
        ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
        if (!ev) {
-               dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, failed to allocate mem @%d..!!\n",
-                   ioc->name,__FUNCTION__, __LINE__));
-               return;
+               dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: failed to "
+                   "allocate mem @%d..!!\n", ioc->name,__FUNCTION__,
+                   __LINE__));
+               return 1;
        }
 
-       INIT_WORK(&ev->work, mptsas_hotplug_work,ev);
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19))
+       INIT_DELAYED_WORK(&ev->hotplug_work, mptsas_hotplug_work);
+#else
+       INIT_WORK(&ev->hotplug_work, mptsas_hotplug_work, ev);
+#endif
        ev->ioc = ioc;
        ev->handle = le16_to_cpu(sas_event_data->DevHandle);
-       ev->parent_handle =
-           le16_to_cpu(sas_event_data->ParentDevHandle);
        ev->channel = channel;
-       ev->id =id;
+       ev->id = id;
        ev->phy_id = sas_event_data->PhyNum;
        memcpy(&sas_address, &sas_event_data->SASAddress,
            sizeof(__le64));
        ev->sas_address = le64_to_cpu(sas_address);
        ev->device_info = le32_to_cpu(sas_event_data->DeviceInfo);
        ev->event_type = MPTSAS_DEL_DEVICE;
-       schedule_work(&ev->work);
+       schedule_delayed_work(&ev->hotplug_work, 0);
        kfree(target_reset_list);
 
        /*
@@ -686,7 +1270,7 @@ mptsas_dev_reset_complete(MPT_ADAPTER *ioc)
 
        head = &hd->target_reset_list;
        if (list_empty(head))
-               return;
+               return 1;
 
        target_reset_list = list_entry(head->next, struct mptsas_target_reset_event,
            list);
@@ -695,69 +1279,79 @@ mptsas_dev_reset_complete(MPT_ADAPTER *ioc)
        id = sas_event_data->TargetID;
        channel = sas_event_data->Bus;
 
-       if (mptsas_target_reset(ioc, channel, id)) {
+       target_reset_list->time_count = jiffies;
+
+       if (mptsas_target_reset(ioc, channel, id))
                target_reset_list->target_reset_issued = 1;
-               hd->resetPending = 1;
-       }
-}
 
-/**
- * mptsas_taskmgmt_complete
- *
- * @ioc
- * @mf
- * @mr
- *
- **/
-static int
-mptsas_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
-{
-       mptsas_dev_reset_complete(ioc);
-       return mptscsih_taskmgmt_complete(ioc, mf, mr);
+       return 1;
 }
 
 /**
- * mptscsih_ioc_reset
- *
- * @ioc
- * @reset_phase
+ *     mptsas_ioc_reset -
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @reset_phase:
  *
  **/
 static int
 mptsas_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
 {
-       MPT_SCSI_HOST   *hd;
+       MPT_SCSI_HOST   *hd;
        struct mptsas_target_reset_event *target_reset_list, *n;
        int rc;
 
        rc = mptscsih_ioc_reset(ioc, reset_phase);
+       if ((ioc->bus_type != SAS) || (!rc))
+               return rc;
 
-       if (ioc->bus_type != SAS)
-               goto out;
-
-       if (reset_phase != MPT_IOC_POST_RESET)
-               goto out;
-
-       if (!ioc->sh || !ioc->sh->hostdata)
-               goto out;
-       hd = shost_priv(ioc->sh);
-       if (!hd->ioc)
-               goto out;
-
-       if (list_empty(&hd->target_reset_list))
-               goto out;
-
-       /* flush the target_reset_list */
-       list_for_each_entry_safe(target_reset_list, n,
-           &hd->target_reset_list, list) {
-               list_del(&target_reset_list->list);
-               kfree(target_reset_list);
+       switch(reset_phase) {
+       case MPT_IOC_SETUP_RESET:
+               dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __FUNCTION__));
+               break;
+       case MPT_IOC_PRE_RESET:
+               dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "%s: MPT_IOC_PRE_RESET\n", ioc->name, __FUNCTION__));
+               break;
+       case MPT_IOC_POST_RESET:
+               dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "%s: MPT_IOC_POST_RESET\n", ioc->name, __FUNCTION__));
+               if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_PENDING) {
+                       ioc->sas_mgmt.status |= MPT_MGMT_STATUS_DID_IOCRESET;
+                       complete(&ioc->sas_mgmt.done);
+               }
+               hd = shost_private(ioc->sh);
+               if (!hd->ioc)
+                       goto out;
+               if (list_empty(&hd->target_reset_list))
+                       break;
+               /* flush the target_reset_list */
+               list_for_each_entry_safe(target_reset_list, n,
+                   &hd->target_reset_list, list) {
+                       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                           "%s: removing target reset for id=%d\n",
+                           ioc->name, __FUNCTION__,
+                           target_reset_list->sas_event_data.TargetID));
+                       list_del(&target_reset_list->list);
+                       kfree(target_reset_list);
+               }
+               break;
+       default:
+               break;
        }
 
  out:
        return rc;
 }
 
+/**
+ *     mptsas_sas_enclosure_pg0 -
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @enclosure:
+ *     @form:
+ *     @form_specific:
+ *
+ **/
 static int
 mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure,
                u32 form, u32 form_specific)
@@ -780,7 +1374,7 @@ mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure,
        cfg.pageAddr = form + form_specific;
        cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
        cfg.dir = 0;    /* read */
-       cfg.timeout = 10;
+       cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
 
        error = mpt_config(ioc, &cfg);
        if (error)
@@ -823,24 +1417,322 @@ mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure,
        return error;
 }
 
+/**
+ *     mptsas_get_lun_number - returns the first entry in report_luns table
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @channel:
+ *     @id:
+ *     @lun:
+ *
+ */
+static int
+mptsas_get_lun_number(MPT_ADAPTER *ioc, u8 channel, u8 id, int *lun)
+{
+       INTERNAL_CMD    *iocmd;
+       struct scsi_lun *lun_data;
+       dma_addr_t      lun_data_dma;
+       u32             lun_data_len;
+       u8              *data;
+       MPT_SCSI_HOST   *hd;
+       int             rc;
+       u32             length, num_luns;
+
+       iocmd = NULL;
+       hd = shost_private(ioc->sh);
+       lun_data_len = (255 * sizeof(struct scsi_lun));
+       lun_data = pci_alloc_consistent(ioc->pcidev, lun_data_len,
+           &lun_data_dma);
+       if (!lun_data) {
+               printk(MYIOC_s_ERR_FMT "%s: pci_alloc_consistent(%d) FAILED!\n",
+                   ioc->name, __FUNCTION__, lun_data_len);
+               rc = -ENOMEM;
+               goto out;
+       }
+
+       iocmd = kzalloc(sizeof(INTERNAL_CMD), GFP_KERNEL);
+       if (!iocmd) {
+               printk(MYIOC_s_ERR_FMT "%s: kzalloc(%zd) FAILED!\n",
+                   ioc->name, __FUNCTION__, sizeof(INTERNAL_CMD));
+               rc = -ENOMEM;
+               goto out;
+       }
+
+       /*
+        * Report Luns
+        */
+       iocmd->cmd = REPORT_LUNS;
+       iocmd->data_dma = lun_data_dma;
+       iocmd->data = (u8 *)lun_data;
+       iocmd->size = lun_data_len;
+       iocmd->channel = channel;
+       iocmd->id = id;
+
+       if ((rc = mptscsih_do_cmd(hd, iocmd)) < 0) {
+               printk(MYIOC_s_ERR_FMT "%s: fw_channel=%d fw_id=%d: "
+                   "report_luns failed due to rc=0x%x\n", ioc->name,
+                   __FUNCTION__, channel, id, rc);
+               goto out;
+       }
+
+       if (rc != MPT_SCANDV_GOOD) {
+               printk(MYIOC_s_ERR_FMT "%s: fw_channel=%d fw_id=%d: "
+                   "report_luns failed due to rc=0x%x\n", ioc->name,
+                   __FUNCTION__, channel, id, rc);
+               rc = -rc;
+               goto out;
+       }
+
+       data = (u8 *)lun_data;
+       length = ((data[0] << 24) | (data[1] << 16) |
+           (data[2] << 8) | (data[3] << 0));
+
+       num_luns = (length / sizeof(struct scsi_lun));
+       if (!num_luns)
+               goto out;
+       /* return 1st lun in the list */
+       *lun = mpt_scsilun_to_int(&lun_data[1]);
+
+#if 0
+       /* some debugging, left commented out */
+       {
+               struct scsi_lun *lunp;
+               for (lunp = &lun_data[1]; lunp <= &lun_data[num_luns]; lunp++)
+                       printk("%x\n", mpt_scsilun_to_int(lunp));
+       }
+#endif
+
+ out:
+       if (lun_data)
+               pci_free_consistent(ioc->pcidev, lun_data_len, lun_data,
+                   lun_data_dma);
+       kfree(iocmd);
+       return rc;
+}
+
+/**
+ *     mptsas_test_unit_ready -
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @channel:
+ *     @id:
+ *
+ **/
+static int
+mptsas_test_unit_ready(MPT_ADAPTER *ioc, u8 channel, u8 id)
+{
+       INTERNAL_CMD    *iocmd;
+       MPT_SCSI_HOST   *hd = shost_private(ioc->sh);
+       int             rc, retries;
+       u8              skey, asc, ascq;
+
+       iocmd = kzalloc(sizeof(INTERNAL_CMD), GFP_KERNEL);
+       if (!iocmd) {
+               printk(MYIOC_s_ERR_FMT "%s: kzalloc(%zd) FAILED!\n",
+               ioc->name, __FUNCTION__, sizeof(INTERNAL_CMD));
+               return -1;
+       }
+
+       iocmd->cmd = TEST_UNIT_READY;
+       iocmd->data_dma = -1;
+       iocmd->data = NULL;
+
+       if (mptscsih_is_phys_disk(ioc, channel, id)) {
+               iocmd->flags |= MPT_ICFLAG_PHYS_DISK;
+               iocmd->physDiskNum = mptscsih_raid_id_to_num(ioc, channel, id);
+               iocmd->id = id;
+       }
+       iocmd->channel = channel;
+       iocmd->id = id;
+
+       for (retries = 0, rc = -1 ; retries < mpt_cmd_retry_count; retries++) {
+               devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: fw_channel=%d "
+                   "fw_id=%d lun=%d count=%d\n", ioc->name, __FUNCTION__,
+                   channel, id, iocmd->lun, retries));
+               rc = mptscsih_do_cmd(hd, iocmd);
+               devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: rc=0x%02x\n",
+                   ioc->name, __FUNCTION__, rc));
+               if (rc < 0) {
+                       printk(MYIOC_s_ERR_FMT "%s: fw_channel=%d fw_id=%d: "
+                           "tur failed due to timeout\n", ioc->name,
+                           __FUNCTION__, channel, id);
+                       goto tur_done;
+               }
+               switch(rc) {
+               case MPT_SCANDV_GOOD:
+                       goto tur_done;
+               case MPT_SCANDV_BUSY:
+                       devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: "
+                           "fw_channel=%d fw_id=%d : device busy\n",
+                           ioc->name, __FUNCTION__, channel, id));
+                       ssleep(1);
+                       break;
+               case MPT_SCANDV_DID_RESET:
+                       devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: "
+                           "fw_channel=%d fw_id=%d : did reset\n",
+                           ioc->name, __FUNCTION__, channel, id));
+                       ssleep(1);
+                       break;
+               case MPT_SCANDV_SENSE:
+                       skey = ioc->internal_cmds.sense[2] & 0x0F;
+                       asc = ioc->internal_cmds.sense[12];
+                       ascq = ioc->internal_cmds.sense[13];
+
+                       devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: "
+                           "fw_channel=%d fw_id=%d : [sense_key,asc,"
+                           "ascq]: [0x%02x,0x%02x,0x%02x]\n", ioc->name,
+                            __FUNCTION__, channel, id, skey, asc, ascq));
+
+                       if (skey == UNIT_ATTENTION)
+                               break;
+                       else if (skey == NOT_READY) {
+                               /*
+                                * medium isn't present
+                                */
+                               if (asc == 0x3a) {
+                                       rc = MPT_SCANDV_GOOD;
+                                       goto tur_done;
+                               }
+                               /*
+                                * LU becoming ready, or
+                                * LU hasn't self-configured yet
+                                */
+                               if ((asc == 0x04 && ascq == 0x01) ||
+                                   (asc == 0x3e && ascq == 0x00)) {
+                                       ssleep(1);
+                                       break;
+                               }
+                       } else if (skey == ILLEGAL_REQUEST) {
+                               /* try sending a tur to a non-zero lun number */
+                               if (!iocmd->lun && !mptsas_get_lun_number(ioc,
+                                   channel, id, &iocmd->lun) && iocmd->lun)
+                                       continue;
+                       }
+                       printk(MYIOC_s_ERR_FMT "%s: fw_channel=%d fw_id=%d : "
+                           "tur failed due to [sense_key,asc,ascq]: "
+                           "[0x%02x,0x%02x,0x%02x]\n", ioc->name,
+                           __FUNCTION__, channel, id, skey, asc, ascq);
+                       goto tur_done;
+               case MPT_SCANDV_SELECTION_TIMEOUT:
+                       printk(MYIOC_s_ERR_FMT "%s: fw_channel=%d fw_id=%d: "
+                           "tur failed due to no device\n", ioc->name,
+                           __FUNCTION__, channel,
+                           id);
+                       goto tur_done;
+               case MPT_SCANDV_SOME_ERROR:
+                       printk(MYIOC_s_ERR_FMT "%s: fw_channel=%d fw_id=%d: "
+                           "tur failed due to some error\n", ioc->name,
+                           __FUNCTION__,
+                           channel, id);
+                       goto tur_done;
+               default:
+                       printk(MYIOC_s_ERR_FMT
+                           "%s: fw_channel=%d fw_id=%d: tur failed due to "
+                           "unknown rc=0x%02x\n", ioc->name, __FUNCTION__,
+                           channel, id, rc );
+                       goto tur_done;
+               }
+       }
+ tur_done:
+       kfree(iocmd);
+       return rc;
+}
+
+/**
+ *     mptsas_issue_tlr - Enabling Transport Layer Retries
+ *     @hd:
+ *     @sdev:
+ *
+ **/
+static void
+mptsas_issue_tlr(MPT_SCSI_HOST *hd, struct scsi_device *sdev)
+{
+       INTERNAL_CMD    *iocmd;
+       VirtDevice      *vdevice = sdev->hostdata;
+       u8              retries;
+       u8              rc;
+       MPT_ADAPTER *ioc = hd->ioc;
+
+       if ( sdev->inquiry[8]  == 'H' &&
+            sdev->inquiry[9]  == 'P' &&
+            sdev->inquiry[10] == ' ' &&
+            sdev->inquiry[11] == ' ' &&
+            sdev->inquiry[12] == ' ' &&
+            sdev->inquiry[13] == ' ' &&
+            sdev->inquiry[14] == ' ' &&
+            sdev->inquiry[15] == ' ' ) {
+
+               iocmd = kzalloc(sizeof(INTERNAL_CMD), GFP_KERNEL);
+               if (!iocmd) {
+                       printk(MYIOC_s_ERR_FMT "%s: kzalloc(%zd) FAILED!\n",
+                       __FUNCTION__, ioc->name, sizeof(INTERNAL_CMD));
+                       return;
+               }
+               iocmd->id = vdevice->vtarget->id;
+               iocmd->channel = vdevice->vtarget->channel;
+               iocmd->lun = vdevice->lun;
+               iocmd->physDiskNum = -1;
+               iocmd->cmd = TRANSPORT_LAYER_RETRIES;
+               iocmd->data_dma = -1;
+               for (retries = 0, rc = -1; retries < 3; retries++) {
+                       rc = mptscsih_do_cmd(hd, iocmd);
+                       if (!rc)
+                               break;
+               }
+               if (rc != 0)
+                       printk(MYIOC_s_DEBUG_FMT "unable to enable TLR on"
+                          " fw_channel %d, fw_id %d, lun=%d\n",
+                          ioc->name, vdevice->vtarget->channel,
+                          vdevice->vtarget->id, sdev->lun);
+               kfree(iocmd);
+       }
+}
+
+/**
+ *     mptsas_slave_configure -
+ *     @sdev:
+ *
+ **/
 static int
 mptsas_slave_configure(struct scsi_device *sdev)
 {
+       struct Scsi_Host        *host = sdev->host;
+       MPT_SCSI_HOST           *hd = shost_private(host);
+       MPT_ADAPTER             *ioc = hd->ioc;
 
-       if (sdev->channel == MPTSAS_RAID_CHANNEL)
+       /*
+        * RAID volumes placed beyond the last expected port.
+        * Ignore sending sas mode pages in that case..
+        */
+       if (sdev->channel == MPTSAS_RAID_CHANNEL) {
+#if defined(CPQ_CIM)
+               mptsas_add_device_component_starget_ir(ioc, scsi_target(sdev));
+#endif
                goto out;
+       }
 
        sas_read_port_mode_page(sdev);
 
+#if defined(CPQ_CIM)
+       mptsas_add_device_component_starget(ioc, scsi_target(sdev));
+#endif
+
+       if (sdev->type == TYPE_TAPE &&
+           (ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_TLR ))
+               mptsas_issue_tlr(hd, sdev);
  out:
+
        return mptscsih_slave_configure(sdev);
 }
 
+/**
+ *     mptsas_target_alloc -
+ *     @starget:
+ *
+ **/
 static int
 mptsas_target_alloc(struct scsi_target *starget)
 {
        struct Scsi_Host *host = dev_to_shost(&starget->dev);
-       MPT_SCSI_HOST           *hd = shost_priv(host);
+       MPT_SCSI_HOST           *hd = shost_private(host);
        VirtTarget              *vtarget;
        u8                      id, channel;
        struct sas_rphy         *rphy;
@@ -862,9 +1754,14 @@ mptsas_target_alloc(struct scsi_target *starget)
         * RAID volumes placed beyond the last expected port.
         */
        if (starget->channel == MPTSAS_RAID_CHANNEL) {
+               if (!ioc->raid_data.pIocPg2) {
+                       kfree(vtarget);
+                       return -ENXIO;
+               }
                for (i=0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++)
                        if (id == ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID)
                                channel = ioc->raid_data.pIocPg2->RaidVolume[i].VolumeBus;
+               vtarget->raidVolume = 1;
                goto out;
        }
 
@@ -873,18 +1770,24 @@ mptsas_target_alloc(struct scsi_target *starget)
        list_for_each_entry(p, &ioc->sas_topology, list) {
                for (i = 0; i < p->num_phys; i++) {
                        if (p->phy_info[i].attached.sas_address !=
-                                       rphy->identify.sas_address)
+                           rphy->identify.sas_address)
                                continue;
                        id = p->phy_info[i].attached.id;
                        channel = p->phy_info[i].attached.channel;
                        mptsas_set_starget(&p->phy_info[i], starget);
 
+                       starget_printk(KERN_INFO, starget, MYIOC_s_FMT
+                       "add device: fw_channel %d, fw_id %d, phy %d, sas_addr 0x%llx\n",
+                       ioc->name, p->phy_info[i].attached.channel,
+                       p->phy_info[i].attached.id, p->phy_info[i].attached.phy_id,
+                       (unsigned long long)p->phy_info[i].attached.sas_address);
+
                        /*
                         * Exposing hidden raid components
                         */
                        if (mptscsih_is_phys_disk(ioc, channel, id)) {
                                id = mptscsih_raid_id_to_num(ioc,
-                                               channel, id);
+                                   channel, id);
                                vtarget->tflags |=
                                    MPT_TARGET_FLAGS_RAID_COMPONENT;
                                p->phy_info[i].attached.phys_disk_num = id;
@@ -905,19 +1808,29 @@ mptsas_target_alloc(struct scsi_target *starget)
        return 0;
 }
 
+/**
+ *     mptsas_target_destroy -
+ *     @starget:
+ *
+ **/
 static void
 mptsas_target_destroy(struct scsi_target *starget)
 {
        struct Scsi_Host *host = dev_to_shost(&starget->dev);
-       MPT_SCSI_HOST           *hd = shost_priv(host);
+       MPT_SCSI_HOST           *hd = shost_private(host);
        struct sas_rphy         *rphy;
        struct mptsas_portinfo  *p;
        int                      i;
-       MPT_ADAPTER *ioc = hd->ioc;
+       MPT_ADAPTER             *ioc = hd->ioc;
 
        if (!starget->hostdata)
                return;
 
+#if defined(CPQ_CIM)
+       mptsas_del_device_component_by_os(ioc, starget->channel,
+           starget->id);
+#endif
+
        if (starget->channel == MPTSAS_RAID_CHANNEL)
                goto out;
 
@@ -927,7 +1840,13 @@ mptsas_target_destroy(struct scsi_target *starget)
                        if (p->phy_info[i].attached.sas_address !=
                                        rphy->identify.sas_address)
                                continue;
-                       mptsas_set_starget(&p->phy_info[i], NULL);
+
+                       starget_printk(KERN_INFO, starget, MYIOC_s_FMT
+                       "delete device: fw_channel %d, fw_id %d, phy %d, sas_addr 0x%llx\n",
+                       ioc->name, p->phy_info[i].attached.channel,
+                       p->phy_info[i].attached.id, p->phy_info[i].attached.phy_id,
+                       (unsigned long long)p->phy_info[i].attached.sas_address);
+
                        goto out;
                }
        }
@@ -937,28 +1856,35 @@ mptsas_target_destroy(struct scsi_target *starget)
        starget->hostdata = NULL;
 }
 
-
+/**
+ *     mptsas_slave_alloc -
+ *     @sdev:
+ *
+ **/
 static int
 mptsas_slave_alloc(struct scsi_device *sdev)
 {
        struct Scsi_Host        *host = sdev->host;
-       MPT_SCSI_HOST           *hd = shost_priv(host);
+       MPT_SCSI_HOST           *hd = shost_private(host);
        struct sas_rphy         *rphy;
        struct mptsas_portinfo  *p;
        VirtDevice              *vdevice;
        struct scsi_target      *starget;
        int                     i;
-       MPT_ADAPTER *ioc = hd->ioc;
+       MPT_ADAPTER             *ioc = hd->ioc;
 
        vdevice = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
        if (!vdevice) {
                printk(MYIOC_s_ERR_FMT "slave_alloc kzalloc(%zd) FAILED!\n",
-                               ioc->name, sizeof(VirtDevice));
+                   ioc->name, sizeof(VirtDevice));
                return -ENOMEM;
        }
        starget = scsi_target(sdev);
        vdevice->vtarget = starget->hostdata;
 
+       /*
+        * RAID volumes placed beyond the last expected port.
+        */
        if (sdev->channel == MPTSAS_RAID_CHANNEL)
                goto out;
 
@@ -992,6 +1918,12 @@ mptsas_slave_alloc(struct scsi_device *sdev)
        return 0;
 }
 
+/**
+ *     mptsas_qcmd -
+ *     @SCpnt:
+ *     @done:
+ *
+ **/
 static int
 mptsas_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
 {
@@ -1003,8 +1935,7 @@ mptsas_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
                return 0;
        }
 
-//     scsi_print_command(SCpnt);
-
+//     scsi_print_command(SCpnt);
        return mptscsih_qcmd(SCpnt,done);
 }
 
@@ -1036,6 +1967,11 @@ static struct scsi_host_template mptsas_driver_template = {
        .shost_attrs                    = mptscsih_host_attrs,
 };
 
+/**
+ *     mptsas_get_linkerrors -
+ *     @phy:
+ *
+ **/
 static int mptsas_get_linkerrors(struct sas_phy *phy)
 {
        MPT_ADAPTER *ioc = phy_to_ioc(phy);
@@ -1045,9 +1981,11 @@ static int mptsas_get_linkerrors(struct sas_phy *phy)
        dma_addr_t dma_handle;
        int error;
 
+#if defined(MPT_WIDE_PORT_API_PLUS)
        /* FIXME: only have link errors on local phys */
        if (!scsi_is_sas_phy_local(phy))
                return -EINVAL;
+#endif
 
        hdr.PageVersion = MPI_SASPHY1_PAGEVERSION;
        hdr.ExtPageLength = 0;
@@ -1062,7 +2000,7 @@ static int mptsas_get_linkerrors(struct sas_phy *phy)
        cfg.pageAddr = phy->identify.phy_identifier;
        cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
        cfg.dir = 0;    /* read */
-       cfg.timeout = 10;
+       cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
 
        error = mpt_config(ioc, &cfg);
        if (error)
@@ -1098,19 +2036,37 @@ static int mptsas_get_linkerrors(struct sas_phy *phy)
        return error;
 }
 
+/**
+ *     mptsas_mgmt_done -
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @req:
+ *     @reply:
+ *
+ **/
 static int mptsas_mgmt_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
                MPT_FRAME_HDR *reply)
 {
-       ioc->sas_mgmt.status |= MPT_SAS_MGMT_STATUS_COMMAND_GOOD;
+       ioc->sas_mgmt.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
        if (reply != NULL) {
-               ioc->sas_mgmt.status |= MPT_SAS_MGMT_STATUS_RF_VALID;
+               ioc->sas_mgmt.status |= MPT_MGMT_STATUS_RF_VALID;
                memcpy(ioc->sas_mgmt.reply, reply,
                    min(ioc->reply_sz, 4 * reply->u.reply.MsgLength));
        }
-       complete(&ioc->sas_mgmt.done);
-       return 1;
+
+       if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_PENDING) {
+               ioc->sas_mgmt.status &= ~MPT_MGMT_STATUS_PENDING;
+               complete(&ioc->sas_mgmt.done);
+               return 1;
+       }
+       return 0;
 }
 
+/**
+ *     mptsas_phy_reset -
+ *     @phy:
+ *     @hard_reset:
+ *
+ **/
 static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset)
 {
        MPT_ADAPTER *ioc = phy_to_ioc(phy);
@@ -1121,9 +2077,11 @@ static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset)
        unsigned long timeleft;
        int error = -ERESTARTSYS;
 
+#if defined(MPT_WIDE_PORT_API_PLUS)
        /* FIXME: fusion doesn't allow non-local phy reset */
        if (!scsi_is_sas_phy_local(phy))
                return -EINVAL;
+#endif
 
        /* not implemented for expanders */
        if (phy->identify.target_port_protocols & SAS_PROTOCOL_SMP)
@@ -1147,21 +2105,24 @@ static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset)
                MPI_SAS_OP_PHY_HARD_RESET : MPI_SAS_OP_PHY_LINK_RESET;
        req->PhyNum = phy->identify.phy_identifier;
 
+       INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status)
        mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
-
-       timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done,
-                       10 * HZ);
-       if (!timeleft) {
-               /* On timeout reset the board */
+       timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10*HZ);
+       if (!(ioc->sas_mgmt.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
+               error = -ETIME;
                mpt_free_msg_frame(ioc, mf);
-               mpt_HardResetHandler(ioc, CAN_SLEEP);
-               error = -ETIMEDOUT;
+               if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_DID_IOCRESET)
+                       goto out;
+               if (!timeleft) {
+                       if (mpt_SoftResetHandler(ioc, CAN_SLEEP) != 0)
+                               mpt_HardResetHandler(ioc, CAN_SLEEP);
+               }
                goto out_unlock;
        }
 
        /* a reply frame is expected */
        if ((ioc->sas_mgmt.status &
-           MPT_IOCTL_STATUS_RF_VALID) == 0) {
+           MPT_MGMT_STATUS_RF_VALID) == 0) {
                error = -ENXIO;
                goto out_unlock;
        }
@@ -1178,11 +2139,18 @@ static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset)
        error = 0;
 
  out_unlock:
+       CLEAR_MGMT_STATUS(ioc->sas_mgmt.status)
        mutex_unlock(&ioc->sas_mgmt.mutex);
  out:
        return error;
 }
 
+/**
+ *     mptsas_get_enclosure_identifier -
+ *     @rphy:
+ *     @identifier:
+ *
+ **/
 static int
 mptsas_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier)
 {
@@ -1211,12 +2179,18 @@ mptsas_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier)
        memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
        error = mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
                        (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
-                        MPI_SAS_ENCLOS_PGAD_FORM_SHIFT), enclosure_handle);
+                        MPI_SAS_ENCLOS_PGAD_FORM_SHIFT),
+                        enclosure_handle);
        if (!error)
                *identifier = enclosure_info.enclosure_logical_id;
        return error;
 }
 
+/**
+ *     mptsas_get_bay_identifier -
+ *     @rphy:
+ *
+ **/
 static int
 mptsas_get_bay_identifier(struct sas_rphy *rphy)
 {
@@ -1249,6 +2223,12 @@ static struct sas_function_template mptsas_transport_functions = {
 
 static struct scsi_transport_template *mptsas_transport_template;
 
+/**
+ *     mptsas_sas_io_unit_pg0 -
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @port_info:
+ *
+ **/
 static int
 mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
 {
@@ -1271,7 +2251,7 @@ mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
        cfg.pageAddr = 0;
        cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
        cfg.dir = 0;    /* read */
-       cfg.timeout = 10;
+       cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
 
        error = mpt_config(ioc, &cfg);
        if (error)
@@ -1318,6 +2298,10 @@ mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
                port_info->phy_info[i].portinfo = port_info;
                port_info->phy_info[i].handle =
                    le16_to_cpu(buffer->PhyData[i].ControllerDevHandle);
+#if defined(CPQ_CIM)
+               port_info->phy_info[i].port_flags =
+                   buffer->PhyData[i].PortFlags;
+#endif
        }
 
  out_free_consistent:
@@ -1327,6 +2311,11 @@ mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
        return error;
 }
 
+/**
+ *     mptsas_sas_io_unit_pg1 -
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *
+ **/
 static int
 mptsas_sas_io_unit_pg1(MPT_ADAPTER *ioc)
 {
@@ -1342,11 +2331,11 @@ mptsas_sas_io_unit_pg1(MPT_ADAPTER *ioc)
 
        cfg.cfghdr.ehdr = &hdr;
        cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
-       cfg.timeout = 10;
        cfg.cfghdr.ehdr->PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
        cfg.cfghdr.ehdr->ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
        cfg.cfghdr.ehdr->PageVersion = MPI_SASIOUNITPAGE1_PAGEVERSION;
        cfg.cfghdr.ehdr->PageNumber = 1;
+       cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
 
        error = mpt_config(ioc, &cfg);
        if (error)
@@ -1384,6 +2373,14 @@ mptsas_sas_io_unit_pg1(MPT_ADAPTER *ioc)
        return error;
 }
 
+/**
+ *     mptsas_sas_phy_pg0 -
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @phy_info:
+ *     @form:
+ *     @form_specific:
+ *
+ **/
 static int
 mptsas_sas_phy_pg0(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
                u32 form, u32 form_specific)
@@ -1404,12 +2401,12 @@ mptsas_sas_phy_pg0(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
 
        cfg.cfghdr.ehdr = &hdr;
        cfg.dir = 0;    /* read */
-       cfg.timeout = 10;
 
        /* Get Phy Pg 0 for each Phy. */
        cfg.physAddr = -1;
        cfg.pageAddr = form + form_specific;
        cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+       cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
 
        error = mpt_config(ioc, &cfg);
        if (error)
@@ -1440,6 +2437,10 @@ mptsas_sas_phy_pg0(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
        phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
        phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
        phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
+#if defined(CPQ_CIM)
+       phy_info->change_count = buffer->ChangeCount;
+#endif
+       phy_info->phy_info = le32_to_cpu(buffer->PhyInfo);
 
  out_free_consistent:
        pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
@@ -1448,6 +2449,14 @@ mptsas_sas_phy_pg0(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
        return error;
 }
 
+/**
+ *     mptsas_sas_device_pg0 -
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @device_info:
+ *     @form:
+ *     @form_specific:
+ *
+ **/
 static int
 mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info,
                u32 form, u32 form_specific)
@@ -1476,7 +2485,7 @@ mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info,
        cfg.physAddr = -1;
        cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
        cfg.dir = 0;    /* read */
-       cfg.timeout = 10;
+       cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
 
        memset(device_info, 0, sizeof(struct mptsas_devinfo));
        error = mpt_config(ioc, &cfg);
@@ -1525,6 +2534,14 @@ mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info,
        return error;
 }
 
+/**
+ *     mptsas_sas_expander_pg0 -
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @port_info:
+ *     @form:
+ *     @form_specific:
+ *
+ **/
 static int
 mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info,
                u32 form, u32 form_specific)
@@ -1533,6 +2550,7 @@ mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info,
        CONFIGPARMS cfg;
        SasExpanderPage0_t *buffer;
        dma_addr_t dma_handle;
+       __le64 sas_address;
        int i, error;
 
        hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION;
@@ -1548,7 +2566,7 @@ mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info,
        cfg.pageAddr = form + form_specific;
        cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
        cfg.dir = 0;    /* read */
-       cfg.timeout = 10;
+       cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
 
        memset(port_info, 0, sizeof(struct mptsas_portinfo));
        error = mpt_config(ioc, &cfg);
@@ -1575,6 +2593,11 @@ mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info,
                goto out_free_consistent;
 
        /* save config data */
+       if (!buffer->NumPhys) {
+               error = -ENXIO;
+               goto out;
+       }
+
        port_info->num_phys = buffer->NumPhys;
        port_info->phy_info = kcalloc(port_info->num_phys,
                sizeof(*port_info->phy_info),GFP_KERNEL);
@@ -1583,10 +2606,15 @@ mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info,
                goto out_free_consistent;
        }
 
+       memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64));
        for (i = 0; i < port_info->num_phys; i++) {
                port_info->phy_info[i].portinfo = port_info;
                port_info->phy_info[i].handle =
                    le16_to_cpu(buffer->DevHandle);
+               port_info->phy_info[i].identify.sas_address =
+                   le64_to_cpu(sas_address);
+               port_info->phy_info[i].identify.handle_parent =
+                   le16_to_cpu(buffer->ParentDevHandle);
        }
 
  out_free_consistent:
@@ -1596,6 +2624,14 @@ mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info,
        return error;
 }
 
+/**
+ *     mptsas_sas_expander_pg1 -
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @phy_info:
+ *     @form:
+ *     @form_specific:
+ *
+ **/
 static int
 mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
                u32 form, u32 form_specific)
@@ -1610,7 +2646,7 @@ mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
                mptsas_is_end_device(&phy_info->attached))
                        goto out;
 
-       hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION;
+       hdr.PageVersion = MPI_SASEXPANDER1_PAGEVERSION;
        hdr.ExtPageLength = 0;
        hdr.PageNumber = 1;
        hdr.Reserved1 = 0;
@@ -1623,7 +2659,7 @@ mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
        cfg.pageAddr = form + form_specific;
        cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
        cfg.dir = 0;    /* read */
-       cfg.timeout = 10;
+       cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
 
        error = mpt_config(ioc, &cfg);
        if (error)
@@ -1659,6 +2695,10 @@ mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
        phy_info->hw_link_rate = buffer->HwLinkRate;
        phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
        phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
+#if defined(CPQ_CIM)
+       phy_info->change_count = buffer->ChangeCount;
+#endif
+       phy_info->phy_info = le32_to_cpu(buffer->PhyInfo);
 
  out_free_consistent:
        pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
@@ -1667,6 +2707,12 @@ mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
        return error;
 }
 
+/**
+ *     mptsas_parse_device_info -
+ *     @identify:
+ *     @device_info:
+ *
+ **/
 static void
 mptsas_parse_device_info(struct sas_identify *identify,
                struct mptsas_devinfo *device_info)
@@ -1726,12 +2772,21 @@ mptsas_parse_device_info(struct sas_identify *identify,
        }
 }
 
+/**
+ *     mptsas_probe_one_phy -
+ *     @dev:
+ *     @phy_info:
+ *     @local:
+ *
+ **/
 static int mptsas_probe_one_phy(struct device *dev,
                struct mptsas_phyinfo *phy_info, int index, int local)
 {
        MPT_ADAPTER *ioc;
        struct sas_phy *phy;
+#if defined(MPT_WIDE_PORT_API)
        struct sas_port *port;
+#endif
        int error = 0;
 
        if (!dev) {
@@ -1748,6 +2803,9 @@ static int mptsas_probe_one_phy(struct device *dev,
        } else
                phy = phy_info->phy;
 
+#if !defined(MPT_WIDE_PORT_API)
+       phy->port_identifier = phy_info->port_id;
+#endif
        mptsas_parse_device_info(&phy->identify, &phy_info->identify);
 
        /*
@@ -1833,6 +2891,10 @@ static int mptsas_probe_one_phy(struct device *dev,
 
        if (!phy_info->phy) {
 
+#if !defined(MPT_WIDE_PORT_API_PLUS)
+               if (local)
+                       phy->local_attached = 1;
+#endif
                error = sas_phy_add(phy);
                if (error) {
                        sas_phy_free(phy);
@@ -1845,11 +2907,13 @@ static int mptsas_probe_one_phy(struct device *dev,
                        !phy_info->port_details)
                goto out;
 
+#if defined(MPT_WIDE_PORT_API)
        port = mptsas_get_port(phy_info);
+#endif
        ioc = phy_to_ioc(phy_info->phy);
 
+#if defined(MPT_WIDE_PORT_API)
        if (phy_info->sas_port_add_phy) {
-
                if (!port) {
                        port = sas_port_alloc_num(dev);
                        if (!port) {
@@ -1864,65 +2928,88 @@ static int mptsas_probe_one_phy(struct device *dev,
                                goto out;
                        }
                        mptsas_set_port(ioc, phy_info, port);
-                       dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
-                           "sas_port_alloc: port=%p dev=%p port_id=%d\n",
-                           ioc->name, port, dev, port->port_identifier));
+                       devtprintk(ioc, dev_printk(KERN_DEBUG, &port->dev,
+                           MYIOC_s_FMT "add port %d, sas_addr (0x%llx)\n",
+                           ioc->name, port->port_identifier,
+                           (unsigned long long)phy_info->attached.sas_address));
                }
-               dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "sas_port_add_phy: phy_id=%d\n",
-                   ioc->name, phy_info->phy_id));
                sas_port_add_phy(port, phy_info->phy);
                phy_info->sas_port_add_phy = 0;
+               devtprintk(ioc, dev_printk(KERN_DEBUG, &phy_info->phy->dev,
+                   MYIOC_s_FMT "add phy %d, phy-obj (0x%p)\n", ioc->name,
+                    phy_info->phy_id, phy_info->phy));
        }
+#else
+       /*
+        * wide port suport
+        * only report the expander or end device once
+        */
+       if (phy_info->attached.wide_port_enable &&
+               (phy_info->phy_id != mptsas_get_rphy_id(phy_info)))
+                       goto out;
+
+#endif
 
+#if defined(MPT_WIDE_PORT_API)
        if (!mptsas_get_rphy(phy_info) && port && !port->rphy) {
+#else
+       if (!mptsas_get_rphy(phy_info)) {
+#endif
 
                struct sas_rphy *rphy;
                struct device *parent;
                struct sas_identify identify;
 
                parent = dev->parent->parent;
-               /*
-                * Let the hotplug_work thread handle processing
-                * the adding/removing of devices that occur
-                * after start of day.
-                */
-               if (ioc->sas_discovery_runtime &&
-                       mptsas_is_end_device(&phy_info->attached))
-                               goto out;
+
+               if (mptsas_is_end_device(&phy_info->attached) &&
+                   phy_info->attached.handle_parent) {
+                       if (!ioc->sas_discovery_runtime)
+                               mptsas_add_end_device(ioc, phy_info);
+                       goto out;
+               }
 
                mptsas_parse_device_info(&identify, &phy_info->attached);
                if (scsi_is_host_device(parent)) {
                        struct mptsas_portinfo *port_info;
                        int i;
 
-                       mutex_lock(&ioc->sas_topology_mutex);
-                       port_info = mptsas_find_portinfo_by_handle(ioc,
-                                                                  ioc->handle);
-                       mutex_unlock(&ioc->sas_topology_mutex);
-
+                       port_info = ioc->hba_port_info;
                        for (i = 0; i < port_info->num_phys; i++)
                                if (port_info->phy_info[i].identify.sas_address ==
                                    identify.sas_address) {
+#if defined(MPT_WIDE_PORT_API_PLUS)
                                        sas_port_mark_backlink(port);
+#endif
                                        goto out;
-                               }
+                       }
 
                } else if (scsi_is_sas_rphy(parent)) {
                        struct sas_rphy *parent_rphy = dev_to_rphy(parent);
                        if (identify.sas_address ==
                            parent_rphy->identify.sas_address) {
+#if defined(MPT_WIDE_PORT_API_PLUS)
                                sas_port_mark_backlink(port);
+#endif
                                goto out;
                        }
                }
 
                switch (identify.device_type) {
                case SAS_END_DEVICE:
+#if defined(MPT_WIDE_PORT_API)
                        rphy = sas_end_device_alloc(port);
+#else
+                       rphy = sas_end_device_alloc(phy);
+#endif
                        break;
                case SAS_EDGE_EXPANDER_DEVICE:
                case SAS_FANOUT_EXPANDER_DEVICE:
+#if defined(MPT_WIDE_PORT_API)
                        rphy = sas_expander_alloc(port, identify.device_type);
+#else
+                       rphy = sas_expander_alloc(phy, identify.device_type);
+#endif
                        break;
                default:
                        rphy = NULL;
@@ -1951,6 +3038,12 @@ static int mptsas_probe_one_phy(struct device *dev,
        return error;
 }
 
+/**
+ *     mptsas_probe_hba_phys -
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @handle:
+ *
+ **/
 static int
 mptsas_probe_hba_phys(MPT_ADAPTER *ioc)
 {
@@ -1967,10 +3060,10 @@ mptsas_probe_hba_phys(MPT_ADAPTER *ioc)
 
        mptsas_sas_io_unit_pg1(ioc);
        mutex_lock(&ioc->sas_topology_mutex);
-       ioc->handle = hba->phy_info[0].handle;
-       port_info = mptsas_find_portinfo_by_handle(ioc, ioc->handle);
+       port_info = ioc->hba_port_info;
        if (!port_info) {
-               port_info = hba;
+               ioc->hba_port_info = port_info = hba;
+               port_info->ioc = ioc;
                list_add_tail(&port_info->list, &ioc->sas_topology);
        } else {
                for (i = 0; i < hba->num_phys; i++) {
@@ -1980,21 +3073,29 @@ mptsas_probe_hba_phys(MPT_ADAPTER *ioc)
                                hba->phy_info[i].handle;
                        port_info->phy_info[i].port_id =
                                hba->phy_info[i].port_id;
+#if defined(CPQ_CIM)
+                       port_info->phy_info[i].port_flags =
+                           hba->phy_info[i].port_flags;
+#endif
                }
                kfree(hba->phy_info);
                kfree(hba);
                hba = NULL;
        }
        mutex_unlock(&ioc->sas_topology_mutex);
+#if defined(CPQ_CIM)
+       ioc->num_ports = port_info->num_phys;
+#endif
        for (i = 0; i < port_info->num_phys; i++) {
                mptsas_sas_phy_pg0(ioc, &port_info->phy_info[i],
                        (MPI_SAS_PHY_PGAD_FORM_PHY_NUMBER <<
                         MPI_SAS_PHY_PGAD_FORM_SHIFT), i);
-
+               port_info->phy_info[i].identify.handle =
+                   port_info->phy_info[i].handle;
                mptsas_sas_device_pg0(ioc, &port_info->phy_info[i].identify,
                        (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
                         MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
-                        port_info->phy_info[i].handle);
+                        port_info->phy_info[i].identify.handle);
                port_info->phy_info[i].identify.phy_id =
                    port_info->phy_info[i].phy_id = i;
                if (port_info->phy_info[i].attached.handle)
@@ -2019,62 +3120,37 @@ mptsas_probe_hba_phys(MPT_ADAPTER *ioc)
        return error;
 }
 
-static int
-mptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle)
+/**
+ *     mptsas_add_expander - refresh or add new expander properties
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @port_info: expander port_info struct
+ *     @is_new: is this a new expander being added (1:yes, 0:no)
+ *
+ **/
+static void
+mptsas_add_expander(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info, u8 is_new)
 {
-       struct mptsas_portinfo *port_info, *p, *ex;
-       struct device *parent;
-       struct sas_rphy *rphy;
-       int error = -ENOMEM, i;
-       u8      add_new_expander;
-       u64     expander_sas_address;
-
-       add_new_expander = 0;
-       ex = kzalloc(sizeof(*port_info), GFP_KERNEL);
-       if (!ex)
-               goto out;
-
-       error = mptsas_sas_expander_pg0(ioc, ex,
-           (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
-            MPI_SAS_EXPAND_PGAD_FORM_SHIFT), *handle);
-       if (error)
-               goto out_free_port_info;
-
-       *handle = ex->phy_info[0].handle;
-
-       mutex_lock(&ioc->sas_topology_mutex);
-       port_info = mptsas_find_portinfo_by_handle(ioc, *handle);
-       if (!port_info) {
-               port_info = ex;
-               list_add_tail(&port_info->list, &ioc->sas_topology);
-               add_new_expander = 1;
-       } else {
-               for (i = 0; i < ex->num_phys; i++) {
-                       port_info->phy_info[i].handle =
-                               ex->phy_info[i].handle;
-                       port_info->phy_info[i].port_id =
-                               ex->phy_info[i].port_id;
-               }
-               kfree(ex->phy_info);
-               kfree(ex);
-               ex = NULL;
-       }
-       mutex_unlock(&ioc->sas_topology_mutex);
+       struct mptsas_portinfo *p;
+       struct device   *parent;
+       struct sas_rphy *rphy;
+       int             i;
+       u64             expander_sas_address;
+       u32             handle;
 
+       handle = port_info->phy_info[0].handle;
+       expander_sas_address = port_info->phy_info[0].identify.sas_address;
        for (i = 0; i < port_info->num_phys; i++) {
                mptsas_sas_expander_pg1(ioc, &port_info->phy_info[i],
                        (MPI_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM <<
-                        MPI_SAS_EXPAND_PGAD_FORM_SHIFT), (i << 16) + *handle);
+                        MPI_SAS_EXPAND_PGAD_FORM_SHIFT), (i << 16) + handle);
 
-               if (port_info->phy_info[i].identify.handle) {
-                       mptsas_sas_device_pg0(ioc,
-                               &port_info->phy_info[i].identify,
-                               (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
-                                MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
-                               port_info->phy_info[i].identify.handle);
-                       port_info->phy_info[i].identify.phy_id =
-                           port_info->phy_info[i].phy_id;
-               }
+               mptsas_sas_device_pg0(ioc,
+                       &port_info->phy_info[i].identify,
+                       (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
+                        MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
+                       port_info->phy_info[i].identify.handle);
+               port_info->phy_info[i].identify.phy_id =
+                   port_info->phy_info[i].phy_id;
 
                if (port_info->phy_info[i].attached.handle) {
                        mptsas_sas_device_pg0(ioc,
@@ -2087,9 +3163,7 @@ mptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle)
                }
        }
 
-       expander_sas_address = port_info->phy_info[0].identify.sas_address;
-
-       if (add_new_expander)
+       if (is_new)
                printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, "
                    "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
                    (unsigned long long)expander_sas_address);
@@ -2115,34 +3189,375 @@ mptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle)
        for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
                mptsas_probe_one_phy(parent, &port_info->phy_info[i],
                    ioc->sas_index, 0);
+}
 
-       return 0;
+/**
+ *     mptsas_probe_expander_phys - probing for new expanders, and refreshing existing
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @handle:
+ *
+ **/
+static void
+mptsas_probe_expander_phys(MPT_ADAPTER *ioc)
+{
+       struct mptsas_portinfo buffer;
+       struct mptsas_portinfo *port_info;
+       u32                     handle;
+       int                     i;
+       u8                      add_new_expander;
 
- out_free_port_info:
-       if (ex) {
-               kfree(ex->phy_info);
-               kfree(ex);
+       handle = 0xFFFF;
+       while (!mptsas_sas_expander_pg0(ioc, &buffer,
+           (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
+            MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle)) {
+
+               handle = buffer.phy_info[0].handle;
+               port_info = mptsas_find_portinfo_by_sas_address(ioc,
+                   buffer.phy_info[0].identify.sas_address);
+               if (!port_info) {
+                       port_info = kzalloc(sizeof(*port_info), GFP_KERNEL);
+                       if (!port_info) {
+                               dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+                               "%s: exit at line=%d\n", ioc->name,
+                               __FUNCTION__, __LINE__));
+                               return;
+                       }
+                       port_info->num_phys = buffer.num_phys;
+                       port_info->phy_info = buffer.phy_info;
+                       for (i = 0; i < port_info->num_phys; i++)
+                               port_info->phy_info[i].portinfo = port_info;
+                       mutex_lock(&ioc->sas_topology_mutex);
+                       list_add_tail(&port_info->list, &ioc->sas_topology);
+                       mutex_unlock(&ioc->sas_topology_mutex);
+                       port_info->ioc = ioc;
+                       add_new_expander = 1;
+               } else {
+                       add_new_expander = 0;
+                       for (i = 0; i < buffer.num_phys; i++) {
+                               port_info->phy_info[i].handle =
+                                   buffer.phy_info[i].handle;
+                               port_info->phy_info[i].port_id =
+                                   buffer.phy_info[i].port_id;
+                       }
+                       kfree(buffer.phy_info);
+               }
+               mptsas_add_expander(ioc, port_info, add_new_expander);
        }
- out:
-       return error;
 }
 
-/*
- * mptsas_delete_expander_phys
- *
+/**
+ *     mptsas_delete_expander - remove this expander
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @port_info: expander port_info struct
  *
- * This will traverse topology, and remove expanders
- * that are no longer present
- */
+ **/
 static void
-mptsas_delete_expander_phys(MPT_ADAPTER *ioc)
+mptsas_delete_expander(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
 {
-       struct mptsas_portinfo buffer;
-       struct mptsas_portinfo *port_info, *n, *parent;
+       struct mptsas_portinfo *parent;
+       int             i;
+       u64             expander_sas_address;
+       char            *ds = NULL;
        struct mptsas_phyinfo *phy_info;
+#if defined(MPT_WIDE_PORT_API)
        struct sas_port * port;
+       struct mptsas_portinfo_details * port_details;
+#else
+       struct sas_rphy * rphy;
+#endif
+
+       /*
+        * Obtain the port_info instance to the parent port
+        */
+       expander_sas_address =
+           port_info->phy_info[0].identify.sas_address;
+       parent = mptsas_find_portinfo_by_handle(ioc,
+           port_info->phy_info[0].identify.handle_parent);
+       if (!parent)
+               goto remove_end_devices;
+
+       /*
+        * Delete rphys in the parent that point
+        * to this expander.  The transport layer will
+        * cleanup all the children.
+        */
+#if defined(MPT_WIDE_PORT_API)
+       phy_info = parent->phy_info;
+       port_details = NULL;
+       port = NULL;
+       for (i = 0; i < parent->num_phys; i++, phy_info++) {
+               if(!phy_info->phy)
+                       continue;
+               if (phy_info->attached.sas_address !=
+                   expander_sas_address)
+                       continue;
+               if (!port) {
+                       port = mptsas_get_port(phy_info);
+                       port_details = phy_info->port_details;
+               }
+               devtprintk(ioc, dev_printk(KERN_DEBUG, &phy_info->phy->dev,
+                   MYIOC_s_FMT "delete phy %d, phy-obj (0x%p)\n", ioc->name,
+                   phy_info->phy_id, phy_info->phy));
+               sas_port_delete_phy(port, phy_info->phy);
+               phy_info->phy = NULL;
+       }
+       if (port && port_details) {
+               devtprintk(ioc, dev_printk(KERN_DEBUG, &port->dev,
+                   MYIOC_s_FMT "delete port %d, sas_addr (0x%llx)\n",
+                   ioc->name, port->port_identifier,
+                   (unsigned long long)expander_sas_address));
+               sas_port_delete(port);
+               mptsas_port_delete(ioc, port_details);
+       }
+#else
+       phy_info = parent->phy_info;
+       for (i = 0; i < parent->num_phys; i++, phy_info++) {
+               rphy = mptsas_get_rphy(phy_info);
+               if (!rphy)
+                       continue;
+               if (phy_info->attached.sas_address !=
+                   expander_sas_address)
+                       continue;
+               dev_printk(KERN_DEBUG, &rphy->dev,
+                   MYIOC_s_FMT "delete: sas_addr (0x%llx)\n",
+                   ioc->name, (unsigned long long) expander_sas_address);
+               sas_rphy_delete(rphy);
+               mptsas_port_delete(ioc, phy_info->port_details);
+       }
+#endif
+ remove_end_devices:
+
+       printk(MYIOC_s_INFO_FMT "delete expander: num_phys %d, sas_addr (0x%llx)\n",
+           ioc->name, port_info->num_phys,
+           (unsigned long long)expander_sas_address);
+
+       /*
+        * removing end devices
+        */
+       phy_info = port_info->phy_info;
+       for (i = 0; i < port_info->num_phys; i++, phy_info++) {
+               if (!phy_info->port_details)
+                       continue;
+               if (phy_info->attached.sas_address) {
+                       ds = NULL;
+                       if (phy_info->attached.device_info &
+                           MPI_SAS_DEVICE_INFO_SSP_TARGET)
+                               ds = "ssp";
+                       if (phy_info->attached.device_info &
+                           MPI_SAS_DEVICE_INFO_STP_TARGET)
+                               ds = "stp";
+                       if (phy_info->attached.device_info &
+                           MPI_SAS_DEVICE_INFO_SATA_DEVICE)
+                               ds = "sata";
+                       if (ds)
+                               printk(MYIOC_s_INFO_FMT
+                               "removing %s device: fw_channel %d, fw_id %d,"
+                               " phy %d, sas_addr 0x%llx\n",
+                               ioc->name, ds, phy_info->attached.channel,
+                               phy_info->attached.id, phy_info->attached.phy_id,
+                               (unsigned long long)phy_info->attached.sas_address);
+               }
+               mptsas_port_delete(ioc, phy_info->port_details);
+       }
+
+       /*
+        * free link
+        */
+       list_del(&port_info->list);
+       kfree(port_info->phy_info);
+       kfree(port_info);
+}
+
+/**
+ *     mptsas_link_status_work -
+ *         delayed worktask handling link status change
+ *     @work: Pointer to mptsas_link_status_event structure
+ *
+ **/
+static void
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19))
+mptsas_link_status_work(struct work_struct *work)
+{
+       struct mptsas_link_status_event *ev =
+               container_of(work, struct mptsas_link_status_event, work);
+#else
+mptsas_link_status_work(void * arg)
+{
+       struct mptsas_link_status_event *ev = arg;
+#endif
+       struct mptsas_portinfo *port_info;
+       struct mptsas_phyinfo *phy_info;
+       __le64 sas_address;
+       MPT_ADAPTER *ioc;
+       u8 phy_num;
+       u8 link_rate;
+
+       ioc = ev->ioc;
+       if (ioc->sas_discovery_ignore_events) {
+               kfree(ev);
+               return;
+       }
+
+       memcpy(&sas_address, &ev->link_data.SASAddress, sizeof(__le64));
+       sas_address = le64_to_cpu(sas_address);
+       link_rate = ev->link_data.LinkRates >> 4;
+       phy_num = ev->link_data.PhyNum;
+
+       mutex_lock(&ioc->sas_discovery_mutex);
+       ioc->sas_discovery_runtime = 1;
+       scsi_block_requests(ioc->sh);
+       port_info = mptsas_find_portinfo_by_sas_address(ioc, sas_address);
+       if (!port_info)
+               goto out;
+       phy_info = &port_info->phy_info[phy_num];
+       if (!phy_info)
+               goto out;
+       phy_info->negotiated_link_rate = link_rate;
+
+       if (link_rate == MPI_SAS_IOUNIT0_RATE_1_5 ||
+           link_rate == MPI_SAS_IOUNIT0_RATE_3_0) {
+               if (port_info == ioc->hba_port_info)
+                       mptsas_probe_hba_phys(ioc);
+               else
+                       mptsas_add_expander(ioc, port_info, 0);
+       } else if (phy_info->phy) {
+               if (link_rate ==  MPI_SAS_IOUNIT0_RATE_PHY_DISABLED)
+                       phy_info->phy->negotiated_linkrate =
+                           SAS_PHY_DISABLED;
+               else if (link_rate ==
+                   MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION)
+                       phy_info->phy->negotiated_linkrate =
+                           SAS_LINK_RATE_FAILED;
+               else
+                       phy_info->phy->negotiated_linkrate =
+                           SAS_LINK_RATE_UNKNOWN;
+       }
+ out:
+       ioc->sas_discovery_runtime = 0;
+       scsi_unblock_requests(ioc->sh);
+       mutex_unlock(&ioc->sas_discovery_mutex);
+       kfree(ev);
+}
+
+/**
+ *     mptsas_expander_add_work -
+ *         delayed worktask handling adding expanders
+ *     @work: Pointer to port_info structure
+ *
+ **/
+static void
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19))
+mptsas_expander_add_work(struct work_struct *work)
+{
+       struct mptsas_portinfo *buffer =
+               container_of(work, struct mptsas_portinfo, add_work.work);
+#else
+mptsas_expander_add_work(void * arg)
+{
+       struct mptsas_portinfo *buffer = arg;
+#endif
+       MPT_ADAPTER *ioc;
+       struct mptsas_portinfo *port_info;
        int i;
-       u64     expander_sas_address;
+
+       ioc = buffer->ioc;
+       mutex_lock(&ioc->sas_discovery_mutex);
+       ioc->sas_discovery_runtime = 1;
+       scsi_block_requests(ioc->sh);
+       port_info = mptsas_find_portinfo_by_sas_address(ioc,
+           buffer->phy_info[0].identify.sas_address);
+
+       if (port_info) {
+               for (i = 0; i < port_info->num_phys; i++) {
+                       port_info->phy_info[i].portinfo = port_info;
+                       port_info->phy_info[i].handle =
+                           buffer->phy_info[i].handle;
+                       port_info->phy_info[i].identify.sas_address =
+                           buffer->phy_info[i].identify.sas_address;
+                       port_info->phy_info[i].identify.handle_parent =
+                           buffer->phy_info[i].identify.handle_parent;
+               }
+               mptsas_add_expander(ioc, port_info, 0);
+               kfree(buffer->phy_info);
+               kfree(buffer);
+       } else {
+               port_info = buffer;
+               mutex_lock(&ioc->sas_topology_mutex);
+               list_add_tail(&port_info->list, &ioc->sas_topology);
+               mutex_unlock(&ioc->sas_topology_mutex);
+               mptsas_add_expander(ioc, port_info, 1);
+       }
+       ioc->sas_discovery_runtime = 0;
+       scsi_unblock_requests(ioc->sh);
+       mutex_unlock(&ioc->sas_discovery_mutex);
+}
+
+/**
+ *     mptsas_expander_delete_work -
+ *         delayed worktask handling removal of expanders
+ *     that are no longer present
+ *     @work: Pointer to port_info structure
+ *
+ **/
+static void
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19))
+mptsas_expander_delete_work(struct work_struct *work)
+{
+       struct mptsas_portinfo *buffer =
+               container_of(work, struct mptsas_portinfo, del_work.work);
+#else
+mptsas_expander_delete_work(void * arg)
+{
+       struct mptsas_portinfo *buffer = arg;
+#endif
+       MPT_ADAPTER *ioc;
+       int rc;
+       struct mptsas_portinfo *port_info, tmp;
+
+       ioc = buffer->ioc;
+       mutex_lock(&ioc->sas_discovery_mutex);
+       port_info = mptsas_find_portinfo_by_sas_address(ioc,
+           buffer->phy_info[0].identify.sas_address);
+
+       /* In 1.05.12 firmware expander events were added, and we need to free
+        * this memory that was allocated in mptsas_send_expander_event */
+       if ((ioc->facts.HeaderVersion >> 8) >= 0xE) {
+               kfree(buffer->phy_info);
+               kfree(buffer);
+       }
+
+       if (!port_info)
+               goto out;
+
+       rc = mptsas_sas_expander_pg0(ioc, &tmp,
+           (MPI_SAS_EXPAND_PGAD_FORM_HANDLE <<
+           MPI_SAS_EXPAND_PGAD_FORM_SHIFT),
+           port_info->phy_info[0].handle);
+       kfree(tmp.phy_info);
+       if (rc) {
+               mutex_lock(&ioc->sas_topology_mutex);
+               mptsas_delete_expander(ioc, port_info);
+               mutex_unlock(&ioc->sas_topology_mutex);
+       }
+       port_info->del_work_scheduled=0;
+
+ out:
+       mutex_unlock(&ioc->sas_discovery_mutex);
+}
+
+/**
+ *     mptsas_remove_expanders_not_responding -
+ *         this will traverse topology removing not responding expanders
+ *     that are no longer present
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *
+ **/
+static void
+mptsas_remove_expanders_not_responding(MPT_ADAPTER *ioc)
+{
+       struct mptsas_portinfo buffer;
+       struct mptsas_portinfo *port_info, *n;
+       int                     rc;
 
        mutex_lock(&ioc->sas_topology_mutex);
        list_for_each_entry_safe(port_info, n, &ioc->sas_topology, list) {
@@ -2152,75 +3567,51 @@ mptsas_delete_expander_phys(MPT_ADAPTER *ioc)
                    MPI_SAS_DEVICE_INFO_SMP_TARGET)))
                        continue;
 
-               if (mptsas_sas_expander_pg0(ioc, &buffer,
-                    (MPI_SAS_EXPAND_PGAD_FORM_HANDLE <<
-                    MPI_SAS_EXPAND_PGAD_FORM_SHIFT),
-                    port_info->phy_info[0].handle)) {
-
-                       /*
-                        * Obtain the port_info instance to the parent port
-                        */
-                       parent = mptsas_find_portinfo_by_handle(ioc,
-                           port_info->phy_info[0].identify.handle_parent);
-
-                       if (!parent)
-                               goto next_port;
-
-                       expander_sas_address =
-                               port_info->phy_info[0].identify.sas_address;
+               rc = mptsas_sas_expander_pg0(ioc, &buffer,
+                   (MPI_SAS_EXPAND_PGAD_FORM_HANDLE <<
+                   MPI_SAS_EXPAND_PGAD_FORM_SHIFT),
+                   port_info->phy_info[0].handle);
 
-                       /*
-                        * Delete rphys in the parent that point
-                        * to this expander.  The transport layer will
-                        * cleanup all the children.
-                        */
-                       phy_info = parent->phy_info;
-                       for (i = 0; i < parent->num_phys; i++, phy_info++) {
-                               port = mptsas_get_port(phy_info);
-                               if (!port)
-                                       continue;
-                               if (phy_info->attached.sas_address !=
-                                       expander_sas_address)
-                                       continue;
-                               dsaswideprintk(ioc,
-                                   dev_printk(KERN_DEBUG, &port->dev,
-                                   MYIOC_s_FMT "delete port (%d)\n", ioc->name,
-                                   port->port_identifier));
-                               sas_port_delete(port);
-                               mptsas_port_delete(ioc, phy_info->port_details);
+               kfree(buffer.phy_info);
+               if (!rc)
+                       continue;
+               /* handle missing expanders */
+               if (ioc->device_missing_delay) {
+                       if(port_info->del_work_scheduled) {
+                               cancel_delayed_work(&port_info->del_work);
+                               port_info->del_work_scheduled=0;
                        }
- next_port:
 
-                       phy_info = port_info->phy_info;
-                       for (i = 0; i < port_info->num_phys; i++, phy_info++)
-                               mptsas_port_delete(ioc, phy_info->port_details);
-
-                       list_del(&port_info->list);
-                       kfree(port_info->phy_info);
-                       kfree(port_info);
-               }
-               /*
-               * Free this memory allocated from inside
-               * mptsas_sas_expander_pg0
-               */
-               kfree(buffer.phy_info);
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19))
+                       INIT_DELAYED_WORK(&port_info->del_work,
+                           mptsas_expander_delete_work);
+#else
+                       INIT_WORK(&port_info->del_work,
+                           mptsas_expander_delete_work, port_info);
+#endif
+                       schedule_delayed_work(&port_info->del_work,
+                           HZ * ioc->device_missing_delay);
+                       port_info->del_work_scheduled=1;
+               } else
+                       mptsas_delete_expander(ioc, port_info);
        }
        mutex_unlock(&ioc->sas_topology_mutex);
 }
 
-/*
- * Start of day discovery
- */
+/**
+ *     mptsas_scan_sas_topology - Start of day discovery
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @sas_address:
+ *
+ **/
 static void
 mptsas_scan_sas_topology(MPT_ADAPTER *ioc)
 {
-       u32 handle = 0xFFFF;
        int i;
 
        mutex_lock(&ioc->sas_discovery_mutex);
        mptsas_probe_hba_phys(ioc);
-       while (!mptsas_probe_expander_phys(ioc, &handle))
-               ;
+       mptsas_probe_expander_phys(ioc);
        /*
          Reporting RAID volumes.
        */
@@ -2230,7 +3621,10 @@ mptsas_scan_sas_topology(MPT_ADAPTER *ioc)
                goto out;
        if (!ioc->raid_data.pIocPg2->NumActiveVolumes)
                goto out;
-       for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
+       for (i=0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
+               printk(MYIOC_s_INFO_FMT "attaching raid volume, channel %d, "
+                   "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,
+                   ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID);
                scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL,
                    ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0);
        }
@@ -2238,41 +3632,45 @@ mptsas_scan_sas_topology(MPT_ADAPTER *ioc)
        mutex_unlock(&ioc->sas_discovery_mutex);
 }
 
-/*
- * Work queue thread to handle Runtime discovery
- * Mere purpose is the hot add/delete of expanders
- *(Mutex UNLOCKED)
- */
+/**
+ *     mptsas_discovery_work - Work queue thread to handle Runtime discovery,
+ *     with the mere purpose is the hot add/delete of expanders
+ *     @work: work queue payload containing the event info
+ *
+ *     (Mutex LOCKED)
+ **/
 static void
-__mptsas_discovery_work(MPT_ADAPTER *ioc)
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19))
+mptsas_discovery_work(struct work_struct *work)
 {
-       u32 handle = 0xFFFF;
-
-       ioc->sas_discovery_runtime=1;
-       mptsas_delete_expander_phys(ioc);
-       mptsas_probe_hba_phys(ioc);
-       while (!mptsas_probe_expander_phys(ioc, &handle))
-               ;
-       ioc->sas_discovery_runtime=0;
-}
-
-/*
- * Work queue thread to handle Runtime discovery
- * Mere purpose is the hot add/delete of expanders
- *(Mutex LOCKED)
- */
-static void
+       struct mptsas_discovery_event *ev =
+               container_of(work, struct mptsas_discovery_event, work);
+#else
 mptsas_discovery_work(void * arg)
 {
        struct mptsas_discovery_event *ev = arg;
+#endif
        MPT_ADAPTER *ioc = ev->ioc;
 
        mutex_lock(&ioc->sas_discovery_mutex);
-       __mptsas_discovery_work(ioc);
+       ioc->sas_discovery_runtime = 1;
+       if (!ioc->disable_hotplug_remove)
+               mptsas_remove_expanders_not_responding(ioc);
+       scsi_block_requests(ioc->sh);
+       mptsas_probe_hba_phys(ioc);
+       mptsas_probe_expander_phys(ioc);
+       ioc->sas_discovery_runtime = 0;
+       scsi_unblock_requests(ioc->sh);
        mutex_unlock(&ioc->sas_discovery_mutex);
        kfree(ev);
 }
 
+/**
+ *     mptsas_find_phyinfo_by_sas_address -
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @sas_address:
+ *
+ **/
 static struct mptsas_phyinfo *
 mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address)
 {
@@ -2297,76 +3695,119 @@ mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address)
        return phy_info;
 }
 
+/**
+ *     mptsas_find_phyinfo_by_phys_disk_num -
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @phys_disk_num:
+ *     @channel:
+ *     @id:
+ *
+ **/
 static struct mptsas_phyinfo *
-mptsas_find_phyinfo_by_target(MPT_ADAPTER *ioc, u8 channel, u8 id)
+mptsas_find_phyinfo_by_phys_disk_num(MPT_ADAPTER *ioc, u8 phys_disk_num, u8 channel, u8 id)
 {
+       struct mptsas_phyinfo *phy_info;
        struct mptsas_portinfo *port_info;
-       struct mptsas_phyinfo *phy_info = NULL;
+       RaidPhysDiskPage1_t *phys_disk = NULL;
+       int num_paths;
+       u64 sas_address = 0;
        int i;
 
-       mutex_lock(&ioc->sas_topology_mutex);
-       list_for_each_entry(port_info, &ioc->sas_topology, list) {
-               for (i = 0; i < port_info->num_phys; i++) {
-                       if (!mptsas_is_end_device(
-                               &port_info->phy_info[i].attached))
-                               continue;
-                       if (port_info->phy_info[i].attached.id != id)
-                               continue;
-                       if (port_info->phy_info[i].attached.channel != channel)
-                               continue;
-                       phy_info = &port_info->phy_info[i];
-                       break;
+       phy_info = NULL;
+       if (!ioc->raid_data.pIocPg3)
+               return NULL;
+       /* dual port support */
+       num_paths = mpt_raid_phys_disk_get_num_paths(ioc, phys_disk_num);
+       if (!num_paths)
+               goto out;
+       phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t,Path) +
+          (num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL);
+       if (!phys_disk)
+               goto out;
+       mpt_raid_phys_disk_pg1(ioc, phys_disk_num, phys_disk);
+       for (i = 0; i < num_paths; i++) {
+               if ((phys_disk->Path[i].Flags & 1) != 0) /* entry no longer valid */
+                       continue;
+               if ((id == phys_disk->Path[i].PhysDiskID) &&
+                   (channel == phys_disk->Path[i].PhysDiskBus)) {
+                       memcpy(&sas_address, &phys_disk->Path[i].WWID, sizeof(u64));
+                       phy_info = mptsas_find_phyinfo_by_sas_address(ioc, sas_address);
+                       goto out;
                }
        }
-       mutex_unlock(&ioc->sas_topology_mutex);
-       return phy_info;
-}
 
-static struct mptsas_phyinfo *
-mptsas_find_phyinfo_by_phys_disk_num(MPT_ADAPTER *ioc, u8 channel, u8 id)
-{
-       struct mptsas_portinfo *port_info;
-       struct mptsas_phyinfo *phy_info = NULL;
-       int i;
+ out:
+       kfree(phys_disk);
+       if (phy_info)
+               return phy_info;
 
+       /*
+        * Extra code to handle RAID0 case, where the sas_address is not updated
+        * in phys_disk_page_1 when hotswapped
+        */
        mutex_lock(&ioc->sas_topology_mutex);
        list_for_each_entry(port_info, &ioc->sas_topology, list) {
-               for (i = 0; i < port_info->num_phys; i++) {
+               for (i = 0; i < port_info->num_phys && !phy_info; i++) {
                        if (!mptsas_is_end_device(
                                &port_info->phy_info[i].attached))
                                continue;
                        if (port_info->phy_info[i].attached.phys_disk_num == ~0)
                                continue;
-                       if (port_info->phy_info[i].attached.phys_disk_num != id)
-                               continue;
-                       if (port_info->phy_info[i].attached.channel != channel)
-                               continue;
-                       phy_info = &port_info->phy_info[i];
-                       break;
+                       if (port_info->phy_info[i].attached.phys_disk_num == phys_disk_num &&
+                           port_info->phy_info[i].attached.id == id &&
+                           port_info->phy_info[i].attached.channel == channel)
+                               phy_info = &port_info->phy_info[i];
                }
        }
        mutex_unlock(&ioc->sas_topology_mutex);
        return phy_info;
 }
 
-/*
- * Work queue thread to clear the persitency table
- */
+/**
+ *     mptsas_persist_clear_table - Work queue thread to clear the persitency table
+ *     @work: work queue payload containing the MPT_ADAPTER structure
+ *
+ **/
 static void
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19))
+mptsas_persist_clear_table(struct work_struct *work)
+{
+       MPT_ADAPTER *ioc = container_of(work, MPT_ADAPTER, sas_persist_task);
+#else
 mptsas_persist_clear_table(void * arg)
 {
        MPT_ADAPTER *ioc = (MPT_ADAPTER *)arg;
+#endif
 
        mptbase_sas_persist_operation(ioc, MPI_SAS_OP_CLEAR_NOT_PRESENT);
 }
 
+/**
+ *     mptsas_reprobe_lun -
+ *     @sdev:
+ *     @data:
+ *
+ **/
 static void
 mptsas_reprobe_lun(struct scsi_device *sdev, void *data)
 {
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18))
+        int rc;
+#endif
        sdev->no_uld_attach = data ? 1 : 0;
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18))
+       rc = scsi_device_reprobe(sdev);
+#else
        scsi_device_reprobe(sdev);
+#endif
 }
 
+/**
+ *     mptsas_reprobe_target -
+ *     @starget:
+ *     @uld_attach:
+ *
+ **/
 static void
 mptsas_reprobe_target(struct scsi_target *starget, int uld_attach)
 {
@@ -2374,6 +3815,15 @@ mptsas_reprobe_target(struct scsi_target *starget, int uld_attach)
                        mptsas_reprobe_lun);
 }
 
+/**
+ *     mptsas_adding_inactive_raid_components -
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @channel:
+ *     @id:
+ *
+ *
+ *      TODO: check for hotspares
+ **/
 static void
 mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id)
 {
@@ -2383,7 +3833,8 @@ mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id)
        pRaidVolumePage0_t              buffer = NULL;
        RaidPhysDiskPage0_t             phys_disk;
        int                             i;
-       struct mptsas_hotplug_event     *ev;
+       struct mptsas_phyinfo           *phy_info;
+       struct mptsas_devinfo           sas_device;
 
        memset(&cfg, 0 , sizeof(CONFIGPARMS));
        memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
@@ -2391,6 +3842,7 @@ mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id)
        cfg.pageAddr = (channel << 8) + id;
        cfg.cfghdr.hdr = &hdr;
        cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+       cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
 
        if (mpt_config(ioc, &cfg) != 0)
                goto out;
@@ -2423,20 +3875,16 @@ mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id)
                    buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
                        continue;
 
-               ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
-               if (!ev) {
-                       printk(MYIOC_s_WARN_FMT "mptsas: lost hotplug event\n", ioc->name);
-                       goto out;
-               }
+               if (mptsas_sas_device_pg0(ioc, &sas_device,
+                   (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
+                    MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
+                       (phys_disk.PhysDiskBus << 8) +
+                       phys_disk.PhysDiskID))
+                       continue;
 
-               INIT_WORK(&ev->work, mptsas_hotplug_work,ev);
-               ev->ioc = ioc;
-               ev->id = phys_disk.PhysDiskID;
-               ev->channel = phys_disk.PhysDiskBus;
-               ev->phys_disk_num_valid = 1;
-               ev->phys_disk_num = phys_disk.PhysDiskNum;
-               ev->event_type = MPTSAS_ADD_DEVICE;
-               schedule_work(&ev->work);
+               phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
+                   sas_device.sas_address);
+               mptsas_add_end_device(ioc, phy_info);
        }
 
  out:
@@ -2444,280 +3892,490 @@ mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id)
                pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
                    dma_handle);
 }
-/*
- * Work queue thread to handle SAS hotplug events
- */
+
+/**
+ *     mptsas_add_end_device - report a new end device to sas transport layer
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @phy_info: decribes attached device
+ *
+ *     return (0) success (1) failure
+ *
+ **/
+static int
+mptsas_add_end_device(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info)
+{
+       struct sas_rphy *rphy;
+#if defined(MPT_WIDE_PORT_API)
+       struct sas_port *port;
+#endif
+       struct sas_identify identify;
+       char *ds = NULL;
+       u8 fw_id;
+
+       if (!phy_info){
+               dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+                       "%s: exit at line=%d\n", ioc->name,
+                       __FUNCTION__, __LINE__));
+               return 1;
+       }
+
+       fw_id = phy_info->attached.id;
+
+       if (mptsas_get_rphy(phy_info)) {
+               dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+                       "%s: fw_id=%d exit at line=%d\n", ioc->name,
+                       __FUNCTION__, fw_id, __LINE__));
+               return 2;
+       }
+
+#if defined(MPT_WIDE_PORT_API)
+       port = mptsas_get_port(phy_info);
+       if (!port) {
+               dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+                       "%s: fw_id=%d exit at line=%d\n", ioc->name,
+                       __FUNCTION__, fw_id, __LINE__));
+               return 3;
+       }
+#endif
+
+       if (mptsas_test_unit_ready(ioc, phy_info->attached.channel,
+           phy_info->attached.id) != 0) {
+               memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
+               dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+                       "%s: fw_id=%d exit at line=%d\n", ioc->name,
+                       __FUNCTION__, fw_id, __LINE__));
+               return 4;
+       }
+
+       if (phy_info->attached.device_info &
+           MPI_SAS_DEVICE_INFO_SSP_TARGET)
+               ds = "ssp";
+       if (phy_info->attached.device_info &
+           MPI_SAS_DEVICE_INFO_STP_TARGET)
+               ds = "stp";
+       if (phy_info->attached.device_info &
+           MPI_SAS_DEVICE_INFO_SATA_DEVICE)
+               ds = "sata";
+
+       printk(MYIOC_s_INFO_FMT "attaching %s device: fw_channel %d, fw_id %d,"
+           " phy %d, sas_addr 0x%llx\n", ioc->name, ds,
+           phy_info->attached.channel, phy_info->attached.id,
+           phy_info->attached.phy_id, (unsigned long long)
+           phy_info->attached.sas_address);
+
+       mptsas_parse_device_info(&identify, &phy_info->attached);
+#if defined(MPT_WIDE_PORT_API)
+       rphy = sas_end_device_alloc(port);
+#else
+       rphy = sas_end_device_alloc(phy_info->phy);
+#endif
+       if (!rphy) {
+               dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+                       "%s: fw_id=%d exit at line=%d\n", ioc->name,
+                       __FUNCTION__, fw_id, __LINE__));
+               return 5; /* non-fatal: an rphy can be added later */
+       }
+
+       rphy->identify = identify;
+       if (sas_rphy_add(rphy)) {
+               dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+                       "%s: fw_id=%d exit at line=%d\n", ioc->name,
+                       __FUNCTION__, fw_id, __LINE__));
+               sas_rphy_free(rphy);
+               return 6;
+       }
+       mptsas_set_rphy(ioc, phy_info, rphy);
+       return 0;
+}
+
+/**
+ *     mptsas_del_end_device - report a deleted end device to sas transport
+ *     layer
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @phy_info: decribes attached device
+ *
+ **/
+static void
+mptsas_del_end_device(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info)
+{
+       struct sas_rphy *rphy;
+#if defined(MPT_WIDE_PORT_API)
+       struct sas_port *port;
+       struct mptsas_portinfo *port_info;
+       struct mptsas_phyinfo *phy_info_lookup;
+       int i;
+#endif
+       struct scsi_target * starget;
+       char *ds = NULL;
+       u8 fw_id;
+       u64 sas_address;
+
+       if (!phy_info){
+               dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+                       "%s: exit at line=%d\n", ioc->name,
+                       __FUNCTION__, __LINE__));
+               return;
+       }
+
+       fw_id = phy_info->attached.id;
+       sas_address = phy_info->attached.sas_address;
+
+       if (!phy_info->port_details) {
+               dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+                       "%s: fw_id=%d exit at line=%d\n", ioc->name,
+                       __FUNCTION__, fw_id, __LINE__));
+               return;
+       }
+       rphy = mptsas_get_rphy(phy_info);
+       if (!rphy) {
+               dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+                       "%s: fw_id=%d exit at line=%d\n", ioc->name,
+                       __FUNCTION__, fw_id, __LINE__));
+               return;
+       }
+#if defined(MPT_WIDE_PORT_API)
+       port = mptsas_get_port(phy_info);
+       if (!port) {
+               dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+                       "%s: fw_id=%d exit at line=%d\n", ioc->name,
+                       __FUNCTION__, fw_id, __LINE__));
+               return;
+       }
+       port_info = phy_info->portinfo;
+       phy_info_lookup = port_info->phy_info;
+       for (i = 0; i < port_info->num_phys; i++, phy_info_lookup++) {
+               if(!phy_info_lookup->phy)
+                       continue;
+               if (phy_info_lookup->attached.sas_address !=
+                   sas_address)
+                       continue;
+               devtprintk(ioc, dev_printk(KERN_DEBUG, &phy_info_lookup->phy->dev,
+                   MYIOC_s_FMT "delete phy %d, phy-obj (0x%p)\n",
+                   ioc->name, phy_info_lookup->phy_id,
+                   phy_info_lookup->phy));
+               sas_port_delete_phy(port, phy_info_lookup->phy);
+               phy_info_lookup->phy = NULL;
+       }
+#endif
+       if (phy_info->attached.device_info &
+           MPI_SAS_DEVICE_INFO_SSP_TARGET)
+               ds = "ssp";
+       if (phy_info->attached.device_info &
+           MPI_SAS_DEVICE_INFO_STP_TARGET)
+               ds = "stp";
+       if (phy_info->attached.device_info &
+           MPI_SAS_DEVICE_INFO_SATA_DEVICE)
+               ds = "sata";
+
+       starget = mptsas_get_starget(phy_info);
+       if (starget)
+               starget_printk(KERN_INFO, starget, MYIOC_s_FMT "removing %s device: fw_channel %d,"
+                   " fw_id %d, phy %d, sas_addr 0x%llx\n", ioc->name, ds,
+                   phy_info->attached.channel, phy_info->attached.id,
+                   phy_info->attached.phy_id, (unsigned long long)
+                   sas_address);
+       else
+               printk(MYIOC_s_INFO_FMT "removing %s device: fw_channel %d,"
+                   " fw_id %d, phy %d, sas_addr 0x%llx\n", ioc->name, ds,
+                   phy_info->attached.channel, phy_info->attached.id,
+                   phy_info->attached.phy_id, (unsigned long long)
+                   sas_address);
+
+#if defined(MPT_WIDE_PORT_API)
+       devtprintk(ioc, dev_printk(KERN_DEBUG, &port->dev, MYIOC_s_FMT
+           "delete port %d, sas_addr (0x%llx)\n", ioc->name,
+            port->port_identifier, (unsigned long long)sas_address));
+       sas_port_delete(port);
+#else
+       sas_rphy_delete(rphy);
+#endif
+       mptsas_port_delete(ioc, phy_info->port_details);
+}
+
+/**
+ *     mptsas_hotplug_work - Work queue thread to handle SAS hotplug events
+ *     @work: work queue payload containing info describing the event
+ *
+ **/
 static void
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19))
+mptsas_hotplug_work(struct work_struct *work)
+{
+       struct mptsas_hotplug_event *ev =
+               container_of(work, struct mptsas_hotplug_event, hotplug_work.work);
+#else
 mptsas_hotplug_work(void *arg)
 {
        struct mptsas_hotplug_event *ev = arg;
+#endif
 
        MPT_ADAPTER *ioc = ev->ioc;
        struct mptsas_phyinfo *phy_info;
-       struct sas_rphy *rphy;
-       struct sas_port *port;
-       struct scsi_device *sdev;
        struct scsi_target * starget;
-       struct sas_identify identify;
-       char *ds = NULL;
        struct mptsas_devinfo sas_device;
+       struct mptsas_portinfo * port_info;
        VirtTarget *vtarget;
-       VirtDevice *vdevice;
+       int i;
 
-       mutex_lock(&ioc->sas_discovery_mutex);
        switch (ev->event_type) {
-       case MPTSAS_DEL_DEVICE:
 
-               phy_info = NULL;
-               if (ev->phys_disk_num_valid) {
-                       if (ev->hidden_raid_component){
-                               if (mptsas_sas_device_pg0(ioc, &sas_device,
-                                   (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
-                                    MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
-                                   (ev->channel << 8) + ev->id)) {
-                                       dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
-                                       "%s: exit at line=%d\n", ioc->name,
-                                               __FUNCTION__, __LINE__));
-                                       break;
-                               }
-                               phy_info = mptsas_find_phyinfo_by_sas_address(
-                                   ioc, sas_device.sas_address);
-                       }else
-                               phy_info = mptsas_find_phyinfo_by_phys_disk_num(
-                                   ioc, ev->channel, ev->phys_disk_num);
+       case MPTSAS_ADD_DEVICE:
+               mutex_lock(&ioc->sas_discovery_mutex);
+               phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
+                   ev->sas_address);
+               if (phy_info){
+                       port_info = phy_info->portinfo;
+                       if (port_info) {
+                               for (i = 0; i < port_info->num_phys; i++)
+                                   if(port_info->phy_info[i].attached.sas_address
+                                       == ev->sas_address)
+                                       port_info->phy_info[i].attached.id = ev->id;
+                       }
+                       mptsas_add_end_device(ioc, phy_info);
+                       mutex_unlock(&ioc->sas_discovery_mutex);
+                       break;
                }
 
-               if (!phy_info)
-                       phy_info = mptsas_find_phyinfo_by_target(ioc,
-                           ev->channel, ev->id);
-
+               mutex_unlock(&ioc->sas_discovery_mutex);
                /*
-                * Sanity checks, for non-existing phys and remote rphys.
+                * retry later if the phy_info wasn't created
                 */
-               if (!phy_info){
-                       dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
-                               "%s: exit at line=%d\n", ioc->name,
-                               __FUNCTION__, __LINE__));
+               if (ev->retries == 12)
                        break;
-               }
-               if (!phy_info->port_details) {
-                       dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
-                               "%s: exit at line=%d\n", ioc->name,
-                               __FUNCTION__, __LINE__));
-                       break;
-               }
-               rphy = mptsas_get_rphy(phy_info);
-               if (!rphy) {
-                       dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
-                               "%s: exit at line=%d\n", ioc->name,
-                               __FUNCTION__, __LINE__));
-                       break;
-               }
+               dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "%s: line=%d: fw_id=%d retry_add (%d)\n", ioc->name,
+                   __FUNCTION__, __LINE__, ev->id, ev->retries));
+               schedule_delayed_work(&ev->hotplug_work, 5*HZ);
+               ev->retries++;
+               return;
 
-               port = mptsas_get_port(phy_info);
-               if (!port) {
-                       dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
-                               "%s: exit at line=%d\n", ioc->name,
-                               __FUNCTION__, __LINE__));
-                       break;
+       case MPTSAS_DEL_DEVICE:
+
+               mutex_lock(&ioc->sas_discovery_mutex);
+               if (!ioc->disable_hotplug_remove) {
+                       phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
+                           ev->sas_address);
+                       mptsas_del_end_device(ioc, phy_info);
                }
+               mutex_unlock(&ioc->sas_discovery_mutex);
+               break;
 
-               starget = mptsas_get_starget(phy_info);
-               if (starget) {
-                       vtarget = starget->hostdata;
+       case MPTSAS_ADD_PHYSDISK:
 
-                       if (!vtarget) {
+               if (mptsas_sas_device_pg0(ioc, &sas_device,
+                   (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
+                    MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
+                       (ev->channel << 8) + ev->id)) {
                                dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
-                                       "%s: exit at line=%d\n", ioc->name,
-                                       __FUNCTION__, __LINE__));
+                                   "%s: fw_id=%d exit at line=%d\n",
+                                   ioc->name, __FUNCTION__, ev->id, __LINE__));
+                       break;
+               }
+
+               mutex_lock(&ioc->sas_discovery_mutex);
+               mutex_lock(&ioc->sas_topology_mutex);
+               port_info = mptsas_find_portinfo_by_handle(ioc,
+                   sas_device.handle_parent);
+               mutex_unlock(&ioc->sas_topology_mutex);
+               if (port_info) {
+                       ioc->sas_discovery_runtime = 1;
+                       scsi_block_requests(ioc->sh);
+                       mpt_findImVolumes(ioc);
+                       if (port_info == ioc->hba_port_info)
+                               mptsas_probe_hba_phys(ioc);
+                       else
+                               mptsas_add_expander(ioc, port_info, 0);
+                       scsi_unblock_requests(ioc->sh);
+                       ioc->sas_discovery_runtime = 0;
+                       phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
+                           sas_device.sas_address);
+                       if (phy_info) {
+                               phy_info->attached.id = ev->id;
+                               mptsas_add_end_device(ioc, phy_info);
+                               mutex_unlock(&ioc->sas_discovery_mutex);
                                break;
                        }
 
-                       /*
-                        * Handling  RAID components
-                        */
-                       if (ev->phys_disk_num_valid &&
-                           ev->hidden_raid_component) {
-                               printk(MYIOC_s_INFO_FMT
-                                   "RAID Hidding: channel=%d, id=%d, "
-                                   "physdsk %d \n", ioc->name, ev->channel,
-                                   ev->id, ev->phys_disk_num);
-                               vtarget->id = ev->phys_disk_num;
-                               vtarget->tflags |=
-                                   MPT_TARGET_FLAGS_RAID_COMPONENT;
-                               mptsas_reprobe_target(starget, 1);
-                               phy_info->attached.phys_disk_num =
-                                   ev->phys_disk_num;
-                       break;
-                       }
                }
+               mutex_unlock(&ioc->sas_discovery_mutex);
+               /*
+                * retry later if the phy_info wasn't created
+                */
+               if (ev->retries == 12)
+                       break;
+               dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "%s: line=%d: fw_id=%d retry_add (%d)\n", ioc->name,
+                   __FUNCTION__, __LINE__, ev->id, ev->retries));
+               schedule_delayed_work(&ev->hotplug_work, 5*HZ);
+               ev->retries++;
+               return;
 
-               if (phy_info->attached.device_info &
-                   MPI_SAS_DEVICE_INFO_SSP_TARGET)
-                       ds = "ssp";
-               if (phy_info->attached.device_info &
-                   MPI_SAS_DEVICE_INFO_STP_TARGET)
-                       ds = "stp";
-               if (phy_info->attached.device_info &
-                   MPI_SAS_DEVICE_INFO_SATA_DEVICE)
-                       ds = "sata";
-
-               printk(MYIOC_s_INFO_FMT
-                      "removing %s device, channel %d, id %d, phy %d\n",
-                      ioc->name, ds, ev->channel, ev->id, phy_info->phy_id);
-               dev_printk(KERN_DEBUG, &port->dev, MYIOC_s_FMT
-                   "delete port (%d)\n", ioc->name, port->port_identifier);
-               sas_port_delete(port);
-               mptsas_port_delete(ioc, phy_info->port_details);
+       case MPTSAS_DEL_PHYSDISK:
+
+               mutex_lock(&ioc->sas_discovery_mutex);
+               mpt_findImVolumes(ioc);
+               phy_info = mptsas_find_phyinfo_by_phys_disk_num(
+                   ioc, ev->phys_disk_num, ev->channel, ev->id);
+               mptsas_del_end_device(ioc, phy_info);
+               mutex_unlock(&ioc->sas_discovery_mutex);
                break;
-       case MPTSAS_ADD_DEVICE:
 
-               if (ev->phys_disk_num_valid)
-                       mpt_findImVolumes(ioc);
+       case MPTSAS_ADD_PHYSDISK_REPROBE:
 
-               /*
-                * Refresh sas device pg0 data
-                */
                if (mptsas_sas_device_pg0(ioc, &sas_device,
                    (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
                     MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
-                       (ev->channel << 8) + ev->id)) {
-                               dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
-                                       "%s: exit at line=%d\n", ioc->name,
-                                       __FUNCTION__, __LINE__));
+                   (ev->channel << 8) + ev->id)) {
+                       dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+                       "%s: fw_id=%d exit at line=%d\n", ioc->name,
+                               __FUNCTION__, ev->id, __LINE__));
                        break;
                }
 
-               __mptsas_discovery_work(ioc);
-
-               phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
-                               sas_device.sas_address);
+               mutex_lock(&ioc->sas_discovery_mutex);
+               phy_info = mptsas_find_phyinfo_by_sas_address(
+                   ioc, sas_device.sas_address);
+               mutex_unlock(&ioc->sas_discovery_mutex);
 
-               if (!phy_info || !phy_info->port_details) {
+               if (!phy_info){
                        dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
-                               "%s: exit at line=%d\n", ioc->name,
-                               __FUNCTION__, __LINE__));
+                               "%s: fw_id=%d exit at line=%d\n", ioc->name,
+                               __FUNCTION__, ev->id, __LINE__));
                        break;
                }
 
                starget = mptsas_get_starget(phy_info);
-               if (starget && (!ev->hidden_raid_component)){
+               if (!starget) {
+                       dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+                               "%s: fw_id=%d exit at line=%d\n", ioc->name,
+                               __FUNCTION__, ev->id, __LINE__));
+                       break;
+               }
+
+               vtarget = starget->hostdata;
+               if (!vtarget) {
+                       dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+                               "%s: fw_id=%d exit at line=%d\n", ioc->name,
+                               __FUNCTION__, ev->id, __LINE__));
+                       break;
+               }
 
-                       vtarget = starget->hostdata;
+               mpt_findImVolumes(ioc);
 
-                       if (!vtarget) {
-                               dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
-                                   "%s: exit at line=%d\n", ioc->name,
-                                   __FUNCTION__, __LINE__));
-                               break;
-                       }
-                       /*
-                        * Handling  RAID components
-                        */
-                       if (vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
-                               printk(MYIOC_s_INFO_FMT
-                                   "RAID Exposing: channel=%d, id=%d, "
-                                   "physdsk %d \n", ioc->name, ev->channel,
-                                   ev->id, ev->phys_disk_num);
-                               vtarget->tflags &=
-                                   ~MPT_TARGET_FLAGS_RAID_COMPONENT;
-                               vtarget->id = ev->id;
-                               mptsas_reprobe_target(starget, 0);
-                               phy_info->attached.phys_disk_num = ~0;
-                       }
+               starget_printk(KERN_INFO, starget, MYIOC_s_FMT
+                   "RAID Hidding: fw_channel=%d, fw_id=%d, physdsk %d, sas_addr 0x%llx\n",
+                   ioc->name, ev->channel, ev->id, ev->phys_disk_num, (unsigned long long)
+                   sas_device.sas_address);
+
+               vtarget->id = ev->phys_disk_num;
+               vtarget->tflags |= MPT_TARGET_FLAGS_RAID_COMPONENT;
+               phy_info->attached.phys_disk_num = ev->phys_disk_num;
+               mptsas_reprobe_target(starget, 1);
+               break;
+
+       case MPTSAS_DEL_PHYSDISK_REPROBE:
+
+               if (mptsas_sas_device_pg0(ioc, &sas_device,
+                   (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
+                    MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
+                       (ev->channel << 8) + ev->id)) {
+                               dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+                                       "%s: fw_id=%d exit at line=%d\n", ioc->name,
+                                       __FUNCTION__, ev->id, __LINE__));
                        break;
                }
 
-               if (mptsas_get_rphy(phy_info)) {
+               mutex_lock(&ioc->sas_discovery_mutex);
+               phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
+                               sas_device.sas_address);
+               mutex_unlock(&ioc->sas_discovery_mutex);
+               if (!phy_info) {
                        dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
-                               "%s: exit at line=%d\n", ioc->name,
-                               __FUNCTION__, __LINE__));
-                       if (ev->channel) printk("%d\n", __LINE__);
+                           "%s: fw_id=%d exit at line=%d\n", ioc->name,
+                           __FUNCTION__, ev->id, __LINE__));
                        break;
                }
 
-               port = mptsas_get_port(phy_info);
-               if (!port) {
+               starget = mptsas_get_starget(phy_info);
+               if (!starget) {
                        dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
-                               "%s: exit at line=%d\n", ioc->name,
-                               __FUNCTION__, __LINE__));
+                           "%s: fw_id=%d exit at line=%d\n", ioc->name,
+                           __FUNCTION__, ev->id, __LINE__));
                        break;
                }
-               memcpy(&phy_info->attached, &sas_device,
-                   sizeof(struct mptsas_devinfo));
-
-               if (phy_info->attached.device_info &
-                   MPI_SAS_DEVICE_INFO_SSP_TARGET)
-                       ds = "ssp";
-               if (phy_info->attached.device_info &
-                   MPI_SAS_DEVICE_INFO_STP_TARGET)
-                       ds = "stp";
-               if (phy_info->attached.device_info &
-                   MPI_SAS_DEVICE_INFO_SATA_DEVICE)
-                       ds = "sata";
-
-               printk(MYIOC_s_INFO_FMT
-                      "attaching %s device, channel %d, id %d, phy %d\n",
-                      ioc->name, ds, ev->channel, ev->id, ev->phy_id);
 
-               mptsas_parse_device_info(&identify, &phy_info->attached);
-               rphy = sas_end_device_alloc(port);
-               if (!rphy) {
+               vtarget = starget->hostdata;
+               if (!vtarget) {
                        dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
-                               "%s: exit at line=%d\n", ioc->name,
-                               __FUNCTION__, __LINE__));
-                       break; /* non-fatal: an rphy can be added later */
+                           "%s: fw_id=%d exit at line=%d\n", ioc->name,
+                           __FUNCTION__, ev->id, __LINE__));
+                       break;
                }
 
-               rphy->identify = identify;
-               if (sas_rphy_add(rphy)) {
+               if (!(vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)) {
                        dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
-                               "%s: exit at line=%d\n", ioc->name,
-                               __FUNCTION__, __LINE__));
-                       sas_rphy_free(rphy);
+                           "%s: fw_id=%d exit at line=%d\n", ioc->name,
+                           __FUNCTION__, ev->id, __LINE__));
                        break;
                }
-               mptsas_set_rphy(ioc, phy_info, rphy);
+
+               mpt_findImVolumes(ioc);
+
+               starget_printk(KERN_INFO, starget, MYIOC_s_FMT
+                   "RAID Exposing: fw_channel=%d, fw_id=%d, physdsk %d, sas_addr 0x%llx\n",
+                   ioc->name, ev->channel, ev->id, ev->phys_disk_num, (unsigned long long)
+                   sas_device.sas_address);
+
+               vtarget->tflags &= ~MPT_TARGET_FLAGS_RAID_COMPONENT;
+               vtarget->id = ev->id;
+               phy_info->attached.phys_disk_num = ~0;
+               mptsas_reprobe_target(starget, 0);
+#if defined(CPQ_CIM)
+               mptsas_add_device_component_by_fw(ioc,
+                   ev->channel, ev->id);
+#endif
                break;
+
        case MPTSAS_ADD_RAID:
-               sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
-                   ev->id, 0);
-               if (sdev) {
-                       scsi_device_put(sdev);
+
+               if (mptsas_test_unit_ready(ioc, ev->channel, ev->id) != 0)
                        break;
-               }
-               printk(MYIOC_s_INFO_FMT
-                      "attaching raid volume, channel %d, id %d\n",
-                      ioc->name, MPTSAS_RAID_CHANNEL, ev->id);
-               scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL, ev->id, 0);
                mpt_findImVolumes(ioc);
+               printk(MYIOC_s_INFO_FMT "attaching raid volume, channel %d, "
+                   "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL, ev->id);
+               scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL, ev->id, 0);
                break;
+
        case MPTSAS_DEL_RAID:
-               sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
-                   ev->id, 0);
-               if (!sdev)
-                       break;
-               printk(MYIOC_s_INFO_FMT
-                      "removing raid volume, channel %d, id %d\n",
-                      ioc->name, MPTSAS_RAID_CHANNEL, ev->id);
-               vdevice = sdev->hostdata;
-               scsi_remove_device(sdev);
-               scsi_device_put(sdev);
+
                mpt_findImVolumes(ioc);
+               printk(MYIOC_s_INFO_FMT "removing raid volume, channel %d, "
+                   "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL, ev->id);
+               scsi_remove_device(ev->sdev);
+               scsi_device_put(ev->sdev);
                break;
+
        case MPTSAS_ADD_INACTIVE_VOLUME:
-               mptsas_adding_inactive_raid_components(ioc,
-                   ev->channel, ev->id);
+
+               mpt_findImVolumes(ioc);
+               mutex_lock(&ioc->sas_discovery_mutex);
+               mptsas_adding_inactive_raid_components(ioc, ev->channel,
+                   ev->id);
+               mutex_unlock(&ioc->sas_discovery_mutex);
                break;
-       case MPTSAS_IGNORE_EVENT:
+
        default:
                break;
        }
-
-       mutex_unlock(&ioc->sas_discovery_mutex);
        kfree(ev);
 }
 
+/**
+ *     mptsas_send_sas_event -
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @sas_event_data:
+ *
+ **/
 static void
 mptsas_send_sas_event(MPT_ADAPTER *ioc,
                EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data)
@@ -2741,15 +4399,18 @@ mptsas_send_sas_event(MPT_ADAPTER *ioc,
        case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
                ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
                if (!ev) {
-                       printk(MYIOC_s_WARN_FMT "lost hotplug event\n", ioc->name);
+                       printk(MYIOC_s_WARN_FMT
+                           "mptsas: lost hotplug event\n", ioc->name);
                        break;
                }
 
-               INIT_WORK(&ev->work, mptsas_hotplug_work,ev);
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19))
+               INIT_DELAYED_WORK(&ev->hotplug_work, mptsas_hotplug_work);
+#else
+               INIT_WORK(&ev->hotplug_work, mptsas_hotplug_work, ev);
+#endif
                ev->ioc = ioc;
                ev->handle = le16_to_cpu(sas_event_data->DevHandle);
-               ev->parent_handle =
-                   le16_to_cpu(sas_event_data->ParentDevHandle);
                ev->channel = sas_event_data->Bus;
                ev->id = sas_event_data->TargetID;
                ev->phy_id = sas_event_data->PhyNum;
@@ -2757,20 +4418,22 @@ mptsas_send_sas_event(MPT_ADAPTER *ioc,
                    sizeof(__le64));
                ev->sas_address = le64_to_cpu(sas_address);
                ev->device_info = device_info;
-
-               if (sas_event_data->ReasonCode &
-                   MPI_EVENT_SAS_DEV_STAT_RC_ADDED)
-                       ev->event_type = MPTSAS_ADD_DEVICE;
-               else
-                       ev->event_type = MPTSAS_DEL_DEVICE;
-               schedule_work(&ev->work);
+               ev->event_type = MPTSAS_ADD_DEVICE;
+               schedule_delayed_work(&ev->hotplug_work, 0);
                break;
+
        case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
        /*
         * Persistent table is full.
         */
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19))
                INIT_WORK(&ioc->sas_persist_task,
-                   mptsas_persist_clear_table,(void *)ioc);
+                   mptsas_persist_clear_table);
+#else
+               INIT_WORK(&ioc->sas_persist_task,
+                   mptsas_persist_clear_table, (void *)ioc);
+#endif
+
                schedule_work(&ioc->sas_persist_task);
                break;
        /*
@@ -2783,10 +4446,18 @@ mptsas_send_sas_event(MPT_ADAPTER *ioc,
        case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
        case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
        case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
+       case MPI_EVENT_SAS_DEV_STAT_RC_ASYNC_NOTIFICATION:
        default:
                break;
        }
 }
+
+/**
+ *     mptsas_send_raid_event -
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @raid_event_data:
+ *
+ **/
 static void
 mptsas_send_raid_event(MPT_ADAPTER *ioc,
                EVENT_DATA_RAID *raid_event_data)
@@ -2794,68 +4465,98 @@ mptsas_send_raid_event(MPT_ADAPTER *ioc,
        struct mptsas_hotplug_event *ev;
        int status = le32_to_cpu(raid_event_data->SettingsStatus);
        int state = (status >> 8) & 0xff;
+       struct scsi_device *sdev = NULL;
+       VirtDevice *vdevice = NULL;
 
        if (ioc->bus_type != SAS)
                return;
 
        ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
        if (!ev) {
-               printk(MYIOC_s_WARN_FMT "lost hotplug event\n", ioc->name);
+               printk(MYIOC_s_WARN_FMT
+                   "mptsas: lost hotplug event\n", ioc->name);
                return;
        }
-       INIT_WORK(&ev->work, mptsas_hotplug_work,ev);
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19))
+       INIT_DELAYED_WORK(&ev->hotplug_work, mptsas_hotplug_work);
+#else
+       INIT_WORK(&ev->hotplug_work, mptsas_hotplug_work, ev);
+#endif
        ev->ioc = ioc;
        ev->id = raid_event_data->VolumeID;
        ev->channel = raid_event_data->VolumeBus;
        ev->event_type = MPTSAS_IGNORE_EVENT;
+       ev->phys_disk_num = raid_event_data->PhysDiskNum;
+
+       if (raid_event_data->ReasonCode == MPI_EVENT_RAID_RC_VOLUME_DELETED ||
+           raid_event_data->ReasonCode == MPI_EVENT_RAID_RC_VOLUME_CREATED ||
+           raid_event_data->ReasonCode == MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED) {
+               sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL, ev->id, 0);
+               ev->sdev = sdev;
+               if (sdev)
+                       vdevice = sdev->hostdata;
+       }
 
        switch (raid_event_data->ReasonCode) {
        case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
-               ev->phys_disk_num_valid = 1;
-               ev->phys_disk_num = raid_event_data->PhysDiskNum;
-               ev->event_type = MPTSAS_ADD_DEVICE;
+               ev->event_type = MPTSAS_DEL_PHYSDISK_REPROBE;
                break;
        case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
-               ev->phys_disk_num_valid = 1;
-               ev->phys_disk_num = raid_event_data->PhysDiskNum;
-               ev->hidden_raid_component = 1;
-               ev->event_type = MPTSAS_DEL_DEVICE;
+               ev->event_type = MPTSAS_ADD_PHYSDISK_REPROBE;
                break;
        case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
                switch (state) {
                case MPI_PD_STATE_ONLINE:
                case MPI_PD_STATE_NOT_COMPATIBLE:
-                       ev->phys_disk_num_valid = 1;
-                       ev->phys_disk_num = raid_event_data->PhysDiskNum;
-                       ev->hidden_raid_component = 1;
-                       ev->event_type = MPTSAS_ADD_DEVICE;
+                       ev->event_type = MPTSAS_ADD_PHYSDISK;
                        break;
+               case MPI_PD_STATE_FAILED:
                case MPI_PD_STATE_MISSING:
                case MPI_PD_STATE_OFFLINE_AT_HOST_REQUEST:
                case MPI_PD_STATE_FAILED_AT_HOST_REQUEST:
                case MPI_PD_STATE_OFFLINE_FOR_ANOTHER_REASON:
-                       ev->phys_disk_num_valid = 1;
-                       ev->phys_disk_num = raid_event_data->PhysDiskNum;
-                       ev->event_type = MPTSAS_DEL_DEVICE;
+                       ev->event_type = MPTSAS_DEL_PHYSDISK;
                        break;
                default:
                        break;
                }
                break;
        case MPI_EVENT_RAID_RC_VOLUME_DELETED:
+               if (!sdev)
+                       break;
+               vdevice->vtarget->deleted = 1; /* block IO */
                ev->event_type = MPTSAS_DEL_RAID;
                break;
        case MPI_EVENT_RAID_RC_VOLUME_CREATED:
+               if (sdev) {
+                       scsi_device_put(sdev);
+                       break;
+               }
                ev->event_type = MPTSAS_ADD_RAID;
                break;
        case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
+               if (!(status & MPI_RAIDVOL0_STATUS_FLAG_ENABLED)) {
+                       if (!sdev)
+                               break;
+                       vdevice->vtarget->deleted = 1; /* block IO */
+                       ev->event_type = MPTSAS_DEL_RAID;
+                       break;
+               }
                switch (state) {
                case MPI_RAIDVOL0_STATUS_STATE_FAILED:
                case MPI_RAIDVOL0_STATUS_STATE_MISSING:
+                       if (!sdev)
+                               break;
+                       vdevice->vtarget->deleted = 1; /* block IO */
                        ev->event_type = MPTSAS_DEL_RAID;
                        break;
                case MPI_RAIDVOL0_STATUS_STATE_OPTIMAL:
                case MPI_RAIDVOL0_STATUS_STATE_DEGRADED:
+                       if (sdev) {
+                               scsi_device_put(sdev);
+                               break;
+                       }
                        ev->event_type = MPTSAS_ADD_RAID;
                        break;
                default:
@@ -2865,14 +4566,25 @@ mptsas_send_raid_event(MPT_ADAPTER *ioc,
        default:
                break;
        }
-       schedule_work(&ev->work);
+
+       if (ev->event_type == MPTSAS_IGNORE_EVENT)
+               kfree(ev);
+       else
+               schedule_delayed_work(&ev->hotplug_work, 0);
 }
 
+/**
+ *     mptsas_send_discovery_event -
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @discovery_data:
+ *
+ **/
 static void
 mptsas_send_discovery_event(MPT_ADAPTER *ioc,
        EVENT_DATA_SAS_DISCOVERY *discovery_data)
 {
        struct mptsas_discovery_event *ev;
+       u32 discovery_status = le32_to_cpu(discovery_data->DiscoveryStatus);
 
        /*
         * DiscoveryStatus
@@ -2881,47 +4593,374 @@ mptsas_send_discovery_event(MPT_ADAPTER *ioc,
         * kicks off discovery, and return to zero
         * once its completed.
         */
-       if (discovery_data->DiscoveryStatus)
+       ioc->sas_discovery_quiesce_io = discovery_status ? 1 : 0;
+       if (discovery_status)
+               return;
+
+       /* Older firmware look at discovery events to handle expanders */
+       if ((ioc->facts.HeaderVersion >> 8) >= 0xE)
                return;
 
        ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
        if (!ev)
                return;
-       INIT_WORK(&ev->work, mptsas_discovery_work,ev);
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19))
+       INIT_WORK(&ev->work, mptsas_discovery_work);
+#else
+       INIT_WORK(&ev->work, mptsas_discovery_work, ev);
+#endif
+
        ev->ioc = ioc;
        schedule_work(&ev->work);
 };
 
-/*
- * mptsas_send_ir2_event - handle exposing hidden disk when
- * an inactive raid volume is added
+/**
+ *     mptsas_issue_tm - send mptsas internal tm request
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @type
+ *     @channel
+ *     @id
+ *     @lun
+ *     @task_context
+ *     @timeout
  *
- * @ioc: Pointer to MPT_ADAPTER structure
- * @ir2_data
+ *     return:
  *
- */
+ **/
+static int
+mptsas_issue_tm(MPT_ADAPTER *ioc, u8 type, u8 channel, u8 id, u64 lun, int task_context, ulong timeout,
+       u8 *issue_reset)
+{
+       MPT_FRAME_HDR   *mf;
+       SCSITaskMgmt_t  *pScsiTm;
+       int              retval;
+       unsigned long    timeleft;
+
+       *issue_reset = 0;
+       if ((mf = mpt_get_msg_frame(mptsasDeviceResetCtx, ioc)) == NULL) {
+               retval = -1; /* return failure */
+               dtmprintk(ioc, printk(MYIOC_s_WARN_FMT "TaskMgmt request: no "
+                   "msg frames!!\n", ioc->name));
+               goto out;
+       }
+
+       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request: mr = %p, "
+           "task_type = 0x%02X,\n\t timeout = %ld, fw_channel = %d, "
+           "fw_id = %d, lun = %lld,\n\t task_context = 0x%x\n", ioc->name, mf,
+            type, timeout, channel, id, (unsigned long long)lun,
+            task_context));
+
+       pScsiTm = (SCSITaskMgmt_t *) mf;
+       memset(pScsiTm, 0, sizeof(SCSITaskMgmt_t));
+       pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
+       pScsiTm->TaskType = type;
+       pScsiTm->MsgFlags = 0;
+       pScsiTm->TargetID = id;
+       pScsiTm->Bus = channel;
+       pScsiTm->ChainOffset = 0;
+       pScsiTm->Reserved = 0;
+       pScsiTm->Reserved1 = 0;
+       pScsiTm->TaskMsgContext = task_context;
+       int_to_scsilun(lun, (struct scsi_lun *)pScsiTm->LUN);
+
+       INITIALIZE_MGMT_STATUS(ioc->taskmgmt_cmds.status)
+       CLEAR_MGMT_STATUS(ioc->internal_cmds.status)
+       retval = 0;
+       mpt_put_msg_frame_hi_pri(mptsasDeviceResetCtx, ioc, mf);
+
+       /* Now wait for the command to complete */
+       timeleft = wait_for_completion_timeout(&ioc->taskmgmt_cmds.done,
+           timeout*HZ);
+       if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
+               retval = -1; /* return failure */
+               dtmprintk(ioc, printk(MYIOC_s_ERR_FMT
+                   "TaskMgmt request: TIMED OUT!(mr=%p)\n", ioc->name, mf));
+               mpt_free_msg_frame(ioc, mf);
+               if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
+                       goto out;
+               *issue_reset = 1;
+               goto out;
+       }
+
+       if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
+               retval = -1; /* return failure */
+               dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "TaskMgmt request: failed with no reply\n", ioc->name));
+               goto out;
+       }
+
+ out:
+       CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status)
+       return retval;
+}
+
+
+/**
+ *     mptsas_broadcast_primative_work - Work queue thread to handle
+ *     broadcast primitive events
+ *     @work: work queue payload containing info describing the event
+ *
+ **/
 static void
-mptsas_send_ir2_event(MPT_ADAPTER *ioc, PTR_MPI_EVENT_DATA_IR2 ir2_data)
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19))
+mptsas_broadcast_primative_work(struct work_struct *work)
 {
-       struct mptsas_hotplug_event *ev;
+       struct mptsas_broadcast_primative_event *ev =
+               container_of(work, struct mptsas_broadcast_primative_event, aen_work.work);
+#else
+mptsas_broadcast_primative_work(void *arg)
+{
+       struct mptsas_broadcast_primative_event *ev = arg;
+#endif
+       MPT_ADAPTER             *ioc = ev->ioc;
+       MPT_FRAME_HDR           *mf;
+       VirtDevice              *vdevice;
+       int                     ii;
+       struct scsi_cmnd        *sc;
+       SCSITaskMgmtReply_t *   pScsiTmReply;
+       u8                      issue_reset;
+       int                     task_context;
+       u8                      channel, id;
+       int                      lun;
+       u32                      termination_count;
+       u32                      query_count;
+
+       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+           "%s - enter\n", ioc->name, __FUNCTION__));
+
+       mutex_lock(&ioc->taskmgmt_cmds.mutex);
+       if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) {
+               mutex_unlock(&ioc->taskmgmt_cmds.mutex);
+               dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "%s - busy, reschedule task\n", ioc->name, __FUNCTION__));
+               schedule_delayed_work(&ev->aen_work, 1*HZ);
+               return;
+       }
+
+       issue_reset = 0;
+       termination_count = 0;
+       query_count = 0;
+       mpt_findImVolumes(ioc);
+       pScsiTmReply = (SCSITaskMgmtReply_t *) ioc->taskmgmt_cmds.reply;
+
+       for (ii = 0; ii < ioc->req_depth; ii++) {
+               sc = mptscsih_get_scsi_lookup(ioc, ii);
+               if (!sc)
+                       continue;
+               mf = MPT_INDEX_2_MFPTR(ioc, ii);
+               if (!mf)
+                       continue;
+               task_context = mf->u.frame.hwhdr.msgctxu.MsgContext;
+               vdevice = sc->device->hostdata;
+               if (!vdevice || !vdevice->vtarget)
+                       continue;
+               if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
+                       continue; /* skip hidden raid components */
+               if (vdevice->vtarget->raidVolume)
+                       continue; /* skip hidden raid components */
+               channel = vdevice->vtarget->channel;
+               id = vdevice->vtarget->id;
+               lun = vdevice->lun;
+               if (mptsas_issue_tm(ioc, MPI_SCSITASKMGMT_TASKTYPE_QUERY_TASK,
+                   channel, id, (u64)lun, task_context, 30, &issue_reset))
+                       goto out;
+               query_count++;
+               termination_count +=
+                   le32_to_cpu(pScsiTmReply->TerminationCount);
+               if ((pScsiTmReply->IOCStatus == MPI_IOCSTATUS_SUCCESS) &&
+                   (pScsiTmReply->ResponseCode ==
+                   MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED ||
+                   pScsiTmReply->ResponseCode ==
+                   MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC))
+                       continue;
+               if (mptsas_issue_tm(ioc,
+                   MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET,
+                   channel, id, (u64)lun, 0, 30, &issue_reset))
+                       goto out;
+               termination_count +=
+                   le32_to_cpu(pScsiTmReply->TerminationCount);
+       }
+
+ out:
+       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+           "%s - exit, query_count = %d termination_count = %d\n",
+           ioc->name, __FUNCTION__, query_count, termination_count));
+
+       ioc->broadcast_aen_busy = 0;
+       mpt_clear_taskmgmt_in_progress_flag(ioc);
+       mutex_unlock(&ioc->taskmgmt_cmds.mutex);
+       kfree(ev);
+
+       if (issue_reset) {
+               printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
+                   ioc->name, __FUNCTION__);
+               if (mpt_SoftResetHandler(ioc, CAN_SLEEP))
+                       mpt_HardResetHandler(ioc, CAN_SLEEP);
+       }
+}
+
+/**
+ *     mptsas_send_broadcast_primative_event - processing of event data
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     broadcast_event_data: event data
+ *
+ **/
+static void
+mptsas_send_broadcast_primative_event(MPT_ADAPTER * ioc,
+       EVENT_DATA_SAS_BROADCAST_PRIMITIVE *broadcast_event_data)
+{
+       struct mptsas_broadcast_primative_event *ev;
+
+       if (ioc->broadcast_aen_busy)
+               return;
 
-       if (ir2_data->ReasonCode !=
-           MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED)
+       if (broadcast_event_data->Primitive !=
+           MPI_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT)
                return;
 
        ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
        if (!ev)
                return;
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19))
+       INIT_DELAYED_WORK(&ev->aen_work, mptsas_broadcast_primative_work);
+#else
+       INIT_WORK(&ev->aen_work, mptsas_broadcast_primative_work, ev);
+#endif
+
+       ev->ioc = ioc;
+       ioc->broadcast_aen_busy = 1;
+       schedule_delayed_work(&ev->aen_work, 0);
+}
+
+/**
+ *     mptsas_send_ir2_event - handle exposing hidden disk when an inactive raid volume is added
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @ir2_data:
+ *
+ **/
+static void
+mptsas_send_ir2_event(MPT_ADAPTER *ioc, PTR_MPI_EVENT_DATA_IR2 ir2_data)
+{
+       struct mptsas_hotplug_event *ev;
 
-       INIT_WORK(&ev->work, mptsas_hotplug_work,ev);
+       ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
+       if (!ev)
+               return;
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19))
+       INIT_DELAYED_WORK(&ev->hotplug_work, mptsas_hotplug_work);
+#else
+       INIT_WORK(&ev->hotplug_work, mptsas_hotplug_work, ev);
+#endif
        ev->ioc = ioc;
        ev->id = ir2_data->TargetID;
        ev->channel = ir2_data->Bus;
-       ev->event_type = MPTSAS_ADD_INACTIVE_VOLUME;
+       ev->event_type = MPTSAS_IGNORE_EVENT;
+       ev->phys_disk_num = ir2_data->PhysDiskNum;
 
-       schedule_work(&ev->work);
+       switch (ir2_data->ReasonCode) {
+       case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
+               ev->event_type = MPTSAS_ADD_INACTIVE_VOLUME;
+               break;
+       case MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED:
+               ev->event_type = MPTSAS_DEL_PHYSDISK;
+               break;
+       case MPI_EVENT_IR2_RC_DUAL_PORT_ADDED:
+               ev->event_type = MPTSAS_ADD_PHYSDISK;
+               break;
+       default:
+               break;
+       }
+
+       if (ev->event_type == MPTSAS_IGNORE_EVENT)
+               kfree(ev);
+       else
+               schedule_delayed_work(&ev->hotplug_work, 0);
 };
 
+/**
+ *     mptsas_send_expander_event - handle expanders coming and going
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @expander_data: event data
+ *
+ **/
+static void
+mptsas_send_expander_event(MPT_ADAPTER *ioc, PTR_EVENT_DATA_SAS_EXPANDER_STATUS_CHANGE expander_data)
+{
+       struct mptsas_portinfo *port_info;
+       __le64 sas_address;
+       int i;
+
+       port_info = kzalloc(sizeof(*port_info), GFP_ATOMIC);
+       if (!port_info)
+               return;
+       port_info->ioc = ioc;
+       port_info->num_phys = expander_data->NumPhys;
+       port_info->phy_info = kcalloc(port_info->num_phys,
+           sizeof(*port_info->phy_info),GFP_ATOMIC);
+       if (!port_info->phy_info) {
+               kfree(port_info);
+               return;
+       }
+
+       memcpy(&sas_address, &expander_data->SASAddress, sizeof(__le64));
+       for (i = 0; i < port_info->num_phys; i++) {
+               port_info->phy_info[i].portinfo = port_info;
+               port_info->phy_info[i].handle =
+                   le16_to_cpu(expander_data->DevHandle);
+               port_info->phy_info[i].identify.sas_address =
+                   le64_to_cpu(sas_address);
+               port_info->phy_info[i].identify.handle_parent =
+                   le16_to_cpu(expander_data->ParentDevHandle);
+       }
+
+       if (expander_data->ReasonCode == MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING) {
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19))
+               INIT_DELAYED_WORK(&port_info->del_work, mptsas_expander_delete_work);
+#else
+               INIT_WORK(&port_info->del_work, mptsas_expander_delete_work, port_info);
+#endif
+               schedule_delayed_work(&port_info->del_work, HZ * ioc->device_missing_delay);
+       } else {
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19))
+               INIT_DELAYED_WORK(&port_info->add_work, mptsas_expander_add_work);
+#else
+               INIT_WORK(&port_info->add_work, mptsas_expander_add_work, port_info);
+#endif
+               schedule_delayed_work(&port_info->add_work, 0);
+       }
+}
+
+/**
+ *     mptsas_send_link_status_event - handle link status change
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     link_data: event data
+ *
+ **/
+static void
+mptsas_send_link_status_event(MPT_ADAPTER *ioc, PTR_EVENT_DATA_SAS_PHY_LINK_STATUS link_data)
+{
+       struct mptsas_link_status_event *ev;
+
+       ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
+       if (!ev)
+               return;
+
+       ev->ioc = ioc;
+       memcpy(&ev->link_data, link_data, sizeof(*link_data));
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19))
+       INIT_WORK(&ev->work, mptsas_link_status_work);
+#else
+       INIT_WORK(&ev->work, mptsas_link_status_work, ev);
+#endif
+       schedule_work(&ev->work);
+}
+
+/**
+ *     mptsas_event_process -
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @reply:
+ *
+ **/
 static int
 mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply)
 {
@@ -2944,26 +4983,59 @@ mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply)
 
        switch (event) {
        case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
+#if defined(CPQ_CIM)
+       ioc->csmi_change_count++;
+#endif
                mptsas_send_sas_event(ioc,
                        (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data);
                break;
        case MPI_EVENT_INTEGRATED_RAID:
+#if defined(CPQ_CIM)
+       ioc->csmi_change_count++;
+#endif
                mptsas_send_raid_event(ioc,
                        (EVENT_DATA_RAID *)reply->Data);
                break;
        case MPI_EVENT_PERSISTENT_TABLE_FULL:
+#if defined(CPQ_CIM)
+       ioc->csmi_change_count++;
+#endif
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19))
+               INIT_WORK(&ioc->sas_persist_task,
+                   mptsas_persist_clear_table);
+#else
                INIT_WORK(&ioc->sas_persist_task,
-                   mptsas_persist_clear_table,(void *)ioc);
+                   mptsas_persist_clear_table, (void *)ioc);
+#endif
                schedule_work(&ioc->sas_persist_task);
                break;
         case MPI_EVENT_SAS_DISCOVERY:
                mptsas_send_discovery_event(ioc,
-                       (EVENT_DATA_SAS_DISCOVERY *)reply->Data);
+                   (EVENT_DATA_SAS_DISCOVERY *)reply->Data);
+               break;
+       case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE:
+               /* In 1.05.12 firmware expander events were added */
+               if ((ioc->facts.HeaderVersion >> 8) >= 0xE)
+                       mptsas_send_expander_event(ioc,
+                           (EVENT_DATA_SAS_EXPANDER_STATUS_CHANGE *)reply->Data);
+               break;
+       case MPI_EVENT_SAS_PHY_LINK_STATUS:
+               if ((ioc->facts.HeaderVersion >> 8) >= 0xE)
+                       mptsas_send_link_status_event(ioc,
+                           (EVENT_DATA_SAS_PHY_LINK_STATUS *)reply->Data);
                break;
        case MPI_EVENT_IR2:
+#if defined(CPQ_CIM)
+       ioc->csmi_change_count++;
+#endif
                mptsas_send_ir2_event(ioc,
                    (PTR_MPI_EVENT_DATA_IR2)reply->Data);
                break;
+       case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
+               mptsas_send_broadcast_primative_event(ioc,
+                       (EVENT_DATA_SAS_BROADCAST_PRIMITIVE *)reply->Data);
+               break;
        default:
                rc = mptscsih_event_process(ioc, reply);
                break;
@@ -2973,6 +5045,12 @@ mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply)
        return rc;
 }
 
+/**
+ *     mptsas_probe -
+ *     @pdev:
+ *     @id:
+ *
+ **/
 static int
 mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
@@ -3036,7 +5114,7 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
                        ioc->name);
                error = -1;
                goto out_mptsas_probe;
-        }
+       }
 
        spin_lock_irqsave(&ioc->FreeQlock, flags);
 
@@ -3050,14 +5128,11 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 
        /* set 16 byte cdb's */
        sh->max_cmd_len = 16;
-
+       sh->can_queue = min_t(int, ioc->req_depth - 10, sh->can_queue);
        sh->max_id = ioc->pfacts[0].PortSCSIID;
        sh->max_lun = max_lun;
-
        sh->transportt = mptsas_transport_template;
 
-       sh->this_id = ioc->pfacts[0].PortSCSIID;
-
        /* Required entry.
         */
        sh->unique_id = ioc->id;
@@ -3068,6 +5143,7 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        mutex_init(&ioc->sas_mgmt.mutex);
        init_completion(&ioc->sas_mgmt.done);
 
+
        /* Verify that we won't exceed the maximum
         * number of chain buffers
         * We can optimize:  ZZ = req_sz/sizeof(SGE)
@@ -3098,7 +5174,7 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
                sh->sg_tablesize = numSGE;
        }
 
-       hd = shost_priv(sh);
+       hd = shost_private(sh);
        hd->ioc = ioc;
 
        /* SCSI needs scsi_cmnd lookup table!
@@ -3115,34 +5191,19 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n",
                 ioc->name, ioc->ScsiLookup));
 
-       /* Clear the TM flags
-        */
-       hd->tmPending = 0;
-       hd->tmState = TM_STATE_NONE;
-       hd->resetPending = 0;
-       hd->abortSCpnt = NULL;
-
-       /* Clear the pointer used to store
-        * single-threaded commands, i.e., those
-        * issued during a bus scan, dv and
-        * configuration pages.
-        */
-       hd->cmdPtr = NULL;
-
-       /* Initialize this SCSI Hosts' timers
-        * To use, set the timer expires field
-        * and add_timer
-        */
-       init_timer(&hd->timer);
-       hd->timer.data = (unsigned long) hd;
-       hd->timer.function = mptscsih_timer_expired;
-
+       ioc->sdev_queue_depth = mpt_sdev_queue_depth;
        ioc->sas_data.ptClear = mpt_pt_clear;
-
-       init_waitqueue_head(&hd->scandv_waitq);
-       hd->scandv_wait_done = 0;
        hd->last_queue_full = 0;
+       ioc->disable_hotplug_remove = mpt_disable_hotplug_remove;
+       if (ioc->disable_hotplug_remove)
+               printk(MYIOC_s_INFO_FMT "disabling hotplug remove\n", ioc->name);
+
        INIT_LIST_HEAD(&hd->target_reset_list);
+#if defined(CPQ_CIM)
+       INIT_LIST_HEAD(&ioc->sas_device_info_list);
+       init_MUTEX(&ioc->sas_device_info_mutex);
+#endif
+
        spin_unlock_irqrestore(&ioc->FreeQlock, flags);
 
        if (ioc->sas_data.ptClear==1) {
@@ -3167,12 +5228,22 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        return error;
 }
 
-static void __devexit mptsas_remove(struct pci_dev *pdev)
+/**
+ *     mptsas_remove -
+ *     @pdev:
+ *
+ **/
+static void __devexit
+mptsas_remove(struct pci_dev *pdev)
 {
        MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
        struct mptsas_portinfo *p, *n;
        int i;
 
+#if defined(CPQ_CIM)
+       mptsas_del_device_components(ioc);
+#endif
+
        ioc->sas_discovery_ignore_events = 1;
        sas_remove_host(ioc->sh);
 
@@ -3181,11 +5252,16 @@ static void __devexit mptsas_remove(struct pci_dev *pdev)
                list_del(&p->list);
                for (i = 0 ; i < p->num_phys ; i++)
                        mptsas_port_delete(ioc, p->phy_info[i].port_details);
+
+               if(p->del_work_scheduled) {
+                       cancel_delayed_work(&p->del_work);
+                       p->del_work_scheduled=0;
+               }
                kfree(p->phy_info);
                kfree(p);
        }
        mutex_unlock(&ioc->sas_topology_mutex);
-
+       ioc->hba_port_info = NULL;
        mptscsih_remove(pdev);
 }
 
@@ -3217,6 +5293,10 @@ static struct pci_driver mptsas_driver = {
 #endif
 };
 
+/**
+ *     mptsas_init -
+ *
+ **/
 static int __init
 mptsas_init(void)
 {
@@ -3230,10 +5310,12 @@ mptsas_init(void)
                return -ENODEV;
 
        mptsasDoneCtx = mpt_register(mptscsih_io_done, MPTSAS_DRIVER);
-       mptsasTaskCtx = mpt_register(mptsas_taskmgmt_complete, MPTSAS_DRIVER);
+       mptsasTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSAS_DRIVER);
        mptsasInternalCtx =
                mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER);
        mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER);
+       mptsasDeviceResetCtx =
+               mpt_register(mptsas_taskmgmt_complete, MPTSAS_DRIVER);
 
        mpt_event_register(mptsasDoneCtx, mptsas_event_process);
        mpt_reset_register(mptsasDoneCtx, mptsas_ioc_reset);
@@ -3245,6 +5327,10 @@ mptsas_init(void)
        return error;
 }
 
+/**
+ *     mptsas_exit -
+ *
+ **/
 static void __exit
 mptsas_exit(void)
 {
@@ -3258,6 +5344,7 @@ mptsas_exit(void)
        mpt_deregister(mptsasInternalCtx);
        mpt_deregister(mptsasTaskCtx);
        mpt_deregister(mptsasDoneCtx);
+       mpt_deregister(mptsasDeviceResetCtx);
 }
 
 module_init(mptsas_init);
index 7c150f50629aa45d385783614fd2bb20714d5028..4f71b51caf55b174ee5cf079e31cdca0c0c9cbcb 100644 (file)
@@ -53,6 +53,7 @@ struct mptsas_target_reset_event {
        struct list_head        list;
        EVENT_DATA_SAS_DEVICE_STATUS_CHANGE sas_event_data;
        u8      target_reset_issued;
+       unsigned long    time_count;
 };
 
 enum mptsas_hotplug_action {
@@ -61,11 +62,38 @@ enum mptsas_hotplug_action {
        MPTSAS_ADD_RAID,
        MPTSAS_DEL_RAID,
        MPTSAS_ADD_INACTIVE_VOLUME,
+       MPTSAS_ADD_PHYSDISK,
+       MPTSAS_ADD_PHYSDISK_REPROBE,
+       MPTSAS_DEL_PHYSDISK,
+       MPTSAS_DEL_PHYSDISK_REPROBE,
        MPTSAS_IGNORE_EVENT,
 };
 
+#if defined(CPQ_CIM)
+struct sas_mapping{
+       u8                      id;
+       u8                      channel;
+};
+
+struct sas_device_info {
+       struct list_head        list;
+       struct sas_mapping      os;     /* operating system mapping*/
+       struct sas_mapping      fw;     /* firmware mapping */
+       u64                     sas_address; 
+       u32                     device_info; /* specific bits for devices */
+       u16                     slot;           /* enclosure slot id */
+       u64                     enclosure_logical_id; /*enclosure address */
+       u8                      is_logical_volume; /* is this logical volume */
+       u8                      is_cached;      /* cached data for a removed device */
+};
+#endif
+
 struct mptsas_hotplug_event {
-       struct work_struct      work;
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19))
+       struct delayed_work      hotplug_work;
+#else
+       struct work_struct       hotplug_work;
+#endif
        MPT_ADAPTER             *ioc;
        enum mptsas_hotplug_action event_type;
        u64                     sas_address;
@@ -73,11 +101,10 @@ struct mptsas_hotplug_event {
        u8                      id;
        u32                     device_info;
        u16                     handle;
-       u16                     parent_handle;
        u8                      phy_id;
-       u8                      phys_disk_num_valid;    /* hrc (hidden raid component) */
        u8                      phys_disk_num;          /* hrc - unique index*/
-       u8                      hidden_raid_component;  /* hrc - don't expose*/
+       u8                      retries;
+       struct scsi_device      *sdev;
 };
 
 struct mptsas_discovery_event {
@@ -85,6 +112,12 @@ struct mptsas_discovery_event {
        MPT_ADAPTER             *ioc;
 };
 
+struct mptsas_link_status_event {
+       struct work_struct      work;
+       MpiEventDataSasPhyLinkStatus_t link_data;
+       MPT_ADAPTER             *ioc;
+};
+
 /*
  * SAS topology structures
  *
@@ -107,38 +140,64 @@ struct mptsas_devinfo {
        u64     sas_address;    /* WWN of this device,
                                   SATA is assigned by HBA,expander */
        u32     device_info;    /* bitfield detailed info about this device */
+#if !defined(MPT_WIDE_PORT_API)
+       u8      wide_port_enable;       /* when set, this is part of wide port*/
+#endif
 };
 
 /*
  * Specific details on ports, wide/narrow
  */
 struct mptsas_portinfo_details{
-       u16     num_phys;       /* number of phys belong to this port */
-       u64     phy_bitmask;    /* TODO, extend support for 255 phys */
-       struct sas_rphy *rphy;  /* transport layer rphy object */
+#if !defined(MPT_WIDE_PORT_API)
+       u8      port_id;        /* port number provided to transport */
+       u8      rphy_id;        /* phy index used for reporting end device*/
+       u32     device_info;    /* bitfield detailed info about this device */
+#endif
+       u16     num_phys;       /* number of phys beloing to this port */
+       u64     phy_bitmask;    /* this needs extending to support 128 phys */
+       struct sas_rphy *rphy; /* rphy for end devices */
+#if defined(MPT_WIDE_PORT_API)
        struct sas_port *port;  /* transport layer port object */
+#endif
        struct scsi_target *starget;
        struct mptsas_portinfo *port_info;
 };
 
 struct mptsas_phyinfo {
-       u16     handle;                 /* unique id to address this */
+       u16     handle;                 /* handle for this phy */
        u8      phy_id;                 /* phy index */
-       u8      port_id;                /* firmware port identifier */
+       u8      port_id;                /* port number this phy is part of */
        u8      negotiated_link_rate;   /* nego'd link rate for this phy */
        u8      hw_link_rate;           /* hardware max/min phys link rate */
        u8      programmed_link_rate;   /* programmed max/min phy link rate */
+#if defined(MPT_WIDE_PORT_API)
        u8      sas_port_add_phy;       /* flag to request sas_port_add_phy*/
+#endif
+#if defined(CPQ_CIM)
+       u8      change_count;           /* change count of the phy */
+       u8      port_flags;             /* info wrt host sas ports */
+#endif
+       u32     phy_info;               /* various info wrt the phy */
        struct mptsas_devinfo identify; /* point to phy device info */
        struct mptsas_devinfo attached; /* point to attached device info */
-       struct sas_phy *phy;            /* transport layer phy object */
+       struct sas_phy *phy;
        struct mptsas_portinfo *portinfo;
        struct mptsas_portinfo_details * port_details;
 };
 
 struct mptsas_portinfo {
        struct list_head list;
-       u16             num_phys;       /* number of phys */
+       u16     num_phys;               /* number of phys */
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19))
+       struct delayed_work     del_work;       /* work for deleting expanders */
+       struct delayed_work     add_work;       /* work for adding expanders */
+#else
+       struct work_struct      del_work;
+       struct work_struct      add_work;
+#endif
+       void    *ioc;                   /* ioc ptr */
+       u8      del_work_scheduled;
        struct mptsas_phyinfo *phy_info;
 };
 
@@ -154,5 +213,15 @@ struct mptsas_enclosure {
        u8      sep_channel;            /* SEP channel logical channel id */
 };
 
+struct mptsas_broadcast_primative_event {
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19))
+       struct delayed_work     aen_work;
+#else
+       struct work_struct      aen_work;
+#endif
+       MPT_ADAPTER             *ioc;
+};
+
 /*}-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 #endif
+
index f3d112c936dc5cc89ac7ad4cc9412a0b2335ba18..1f4e87f69f907049b77e5fedc02315471817f202 100644 (file)
@@ -43,7 +43,7 @@
     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-
+#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
@@ -53,7 +53,9 @@
 #include <linux/delay.h>       /* for mdelay */
 #include <linux/interrupt.h>   /* needed for in_interrupt() proto */
 #include <linux/reboot.h>      /* notifier code */
+#include <linux/sched.h>
 #include <linux/workqueue.h>
+#include <linux/pci.h>
 
 #include <scsi/scsi.h>
 #include <scsi/scsi_cmnd.h>
@@ -62,6 +64,7 @@
 #include <scsi/scsi_tcq.h>
 #include <scsi/scsi_dbg.h>
 
+#include "linux_compat.h"      /* linux-2.6 tweaks */
 #include "mptbase.h"
 #include "mptscsih.h"
 #include "lsi/mpi_log_sas.h"
@@ -77,10 +80,15 @@ MODULE_LICENSE("GPL");
 MODULE_VERSION(my_VERSION);
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+typedef struct _BIG_SENSE_BUF {
+       u8              data[MPT_SENSE_BUFFER_ALLOC];
+} BIG_SENSE_BUF;
+
+
 /*
  *  Other private/forward protos...
  */
-static struct scsi_cmnd * mptscsih_get_scsi_lookup(MPT_ADAPTER *ioc, int i);
+struct scsi_cmnd * mptscsih_get_scsi_lookup(MPT_ADAPTER *ioc, int i);
 static struct scsi_cmnd * mptscsih_getclear_scsi_lookup(MPT_ADAPTER *ioc, int i);
 static void    mptscsih_set_scsi_lookup(MPT_ADAPTER *ioc, int i, struct scsi_cmnd *scmd);
 static int     SCPNT_TO_LOOKUP_IDX(MPT_ADAPTER *ioc, struct scsi_cmnd *scmd);
@@ -92,17 +100,10 @@ static int mptscsih_AddSGE(MPT_ADAPTER *ioc, struct scsi_cmnd *SCpnt,
                                 SCSIIORequest_t *pReq, int req_idx);
 static void    mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx);
 static void    mptscsih_copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply);
-static int     mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd);
-static int     mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout );
-
-static int     mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout);
 
 int            mptscsih_ioc_reset(MPT_ADAPTER *ioc, int post_reset);
 int            mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply);
-
-int            mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
-static int     mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *iocmd);
-static void    mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice);
+static void    mptscsih_synchronize_cache(struct scsi_device *sdev, MPT_SCSI_HOST *hd, VirtDevice *vdevice);
 
 void           mptscsih_remove(struct pci_dev *);
 void           mptscsih_shutdown(struct pci_dev *);
@@ -123,7 +124,7 @@ int                 mptscsih_resume(struct pci_dev *pdev);
  *
  *     This routine places a MPT request frame back on the MPT adapter's
  *     FreeQ.
- */
+ **/
 static inline void
 mptscsih_add_chain(char *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
 {
@@ -149,14 +150,14 @@ mptscsih_add_chain(char *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
 } /* mptscsih_add_chain() */
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*
+/**
  *     mptscsih_getFreeChainBuffer - Function to get a free chain
  *     from the MPT_SCSI_HOST FreeChainQ.
  *     @ioc: Pointer to MPT_ADAPTER structure
  *     @req_idx: Index of the SCSI IO request frame. (output)
  *
  *     return SUCCESS or FAILED
- */
+ **/
 static inline int
 mptscsih_getFreeChainBuffer(MPT_ADAPTER *ioc, int *retIndex)
 {
@@ -166,7 +167,7 @@ mptscsih_getFreeChainBuffer(MPT_ADAPTER *ioc, int *retIndex)
        int chain_idx;
 
        dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "getFreeChainBuffer called\n",
-           ioc->name));
+                       ioc->name));
        spin_lock_irqsave(&ioc->FreeQlock, flags);
        if (!list_empty(&ioc->FreeChainQ)) {
                int offset;
@@ -177,14 +178,13 @@ mptscsih_getFreeChainBuffer(MPT_ADAPTER *ioc, int *retIndex)
                offset = (u8 *)chainBuf - (u8 *)ioc->ChainBuffer;
                chain_idx = offset / ioc->req_sz;
                rc = SUCCESS;
-               dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT
-                   "getFreeChainBuffer chainBuf=%p ChainBuffer=%p offset=%d chain_idx=%d\n",
-                   ioc->name, chainBuf, ioc->ChainBuffer, offset, chain_idx));
+               dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "getFreeChainBuffer chainBuf=%p ChainBuffer=%p offset=%d chain_idx=%d\n",
+                       ioc->name, chainBuf, ioc->ChainBuffer, offset, chain_idx));
        } else {
                rc = FAILED;
                chain_idx = MPT_HOST_NO_CHAIN;
                dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "getFreeChainBuffer failed\n",
-                   ioc->name));
+                       ioc->name));
        }
        spin_unlock_irqrestore(&ioc->FreeQlock, flags);
 
@@ -193,7 +193,7 @@ mptscsih_getFreeChainBuffer(MPT_ADAPTER *ioc, int *retIndex)
 } /* mptscsih_getFreeChainBuffer() */
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*
+/**
  *     mptscsih_AddSGE - Add a SGE (plus chain buffers) to the
  *     SCSIIORequest_t Message Frame.
  *     @ioc: Pointer to MPT_ADAPTER structure
@@ -201,7 +201,7 @@ mptscsih_getFreeChainBuffer(MPT_ADAPTER *ioc, int *retIndex)
  *     @pReq: Pointer to SCSIIORequest_t structure
  *
  *     Returns ...
- */
+ **/
 static int
 mptscsih_AddSGE(MPT_ADAPTER *ioc, struct scsi_cmnd *SCpnt,
                SCSIIORequest_t *pReq, int req_idx)
@@ -234,11 +234,11 @@ mptscsih_AddSGE(MPT_ADAPTER *ioc, struct scsi_cmnd *SCpnt,
        /* Map the data portion, if any.
         * sges_left  = 0 if no data transfer.
         */
-       if ( (sges_left = scsi_sg_count(SCpnt)) ) {
+       if ( (sges_left = SCpnt->use_sg) ) {
                sges_left = pci_map_sg(ioc->pcidev,
-                               scsi_sglist(SCpnt),
-                               scsi_sg_count(SCpnt),
-                               SCpnt->sc_data_direction);
+                              (struct scatterlist *) SCpnt->request_buffer,
+                              SCpnt->use_sg,
+                              SCpnt->sc_data_direction);
                if (sges_left == 0)
                        return FAILED;
        } else if (SCpnt->request_bufflen) {
@@ -246,7 +246,7 @@ mptscsih_AddSGE(MPT_ADAPTER *ioc, struct scsi_cmnd *SCpnt,
                                      SCpnt->request_buffer,
                                      SCpnt->request_bufflen,
                                      SCpnt->sc_data_direction);
-               dsgprintk(ioc,printk(MYIOC_s_INFO_FMT "SG: non-SG for %p, len=%d\n",
+               dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SG: non-SG for %p, len=%d\n",
                                ioc->name, SCpnt, SCpnt->request_bufflen));
                ioc->add_sge((char *) &pReq->SGL,
                        0xD1000000|MPT_SGE_FLAGS_ADDRESSING|sgdir|SCpnt->request_bufflen,
@@ -255,10 +255,9 @@ mptscsih_AddSGE(MPT_ADAPTER *ioc, struct scsi_cmnd *SCpnt,
                return SUCCESS;
        }
 
-
        /* Handle the SG case.
         */
-       sg = scsi_sglist(SCpnt);
+       sg = (struct scatterlist *) SCpnt->request_buffer;
        sg_done  = 0;
        sgeOffset = sizeof(SCSIIORequest_t) - sizeof(SGE_IO_UNION);
        chainSge = NULL;
@@ -581,14 +580,14 @@ mptscsih_info_scsiio(MPT_ADAPTER *ioc, struct scsi_cmnd *sc, SCSIIOReply_t * pSc
        }
 
        scsi_print_command(sc);
-       printk(MYIOC_s_DEBUG_FMT "\tfw_channel = %d, fw_id = %d\n",
-           ioc->name, pScsiReply->Bus, pScsiReply->TargetID);
-       printk(MYIOC_s_DEBUG_FMT "\trequest_len = %d, underflow = %d, "
-           "resid = %d\n", ioc->name, scsi_bufflen(sc), sc->underflow,
-           scsi_get_resid(sc));
-       printk(MYIOC_s_DEBUG_FMT "\ttag = %d, transfer_count = %d, "
-           "sc->result = %08X\n", ioc->name, le16_to_cpu(pScsiReply->TaskTag),
+       printk(MYIOC_s_DEBUG_FMT "\tfw_channel = %d, fw_id = %d, lun = %d\n",
+           ioc->name, pScsiReply->Bus, pScsiReply->TargetID, sc->device->lun);
+       printk(MYIOC_s_DEBUG_FMT "\trequest_len = %d, underflow = %d, resid = %d\n",
+           ioc->name, sc->request_bufflen, sc->underflow, sc->resid);
+       printk(MYIOC_s_DEBUG_FMT "\ttag = %d, transfer_count = %d, sc->result = %08X\n",
+           ioc->name, le16_to_cpu(pScsiReply->TaskTag),
            le32_to_cpu(pScsiReply->TransferCount), sc->result);
+
        printk(MYIOC_s_DEBUG_FMT "\tiocstatus = %s (0x%04x), "
            "scsi_status = %s (0x%02x), scsi_state = (0x%02x)\n",
            ioc->name, desc, ioc_status, desc1, pScsiReply->SCSIStatus,
@@ -614,7 +613,7 @@ mptscsih_info_scsiio(MPT_ADAPTER *ioc, struct scsi_cmnd *sc, SCSIIOReply_t * pSc
 #endif
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*
+/**
  *     mptscsih_io_done - Main SCSI IO callback routine registered to
  *     Fusion MPT (base) driver
  *     @ioc: Pointer to MPT_ADAPTER structure
@@ -627,7 +626,7 @@ mptscsih_info_scsiio(MPT_ADAPTER *ioc, struct scsi_cmnd *sc, SCSIIOReply_t * pSc
  *     load/init time via the mpt_register() API call.
  *
  *     Returns 1 indicating alloc'd request frame ptr should be freed.
- */
+ **/
 int
 mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
 {
@@ -639,15 +638,16 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
        VirtDevice       *vdevice;
        VirtTarget       *vtarget;
 
-       hd = shost_priv(ioc->sh);
+       hd = shost_private(ioc->sh);
+
        req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
        req_idx_MR = (mr != NULL) ?
            le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx) : req_idx;
        if ((req_idx != req_idx_MR) ||
-           (mf->u.frame.linkage.arg1 == 0xdeadbeaf)) {
-               printk(MYIOC_s_ERR_FMT "Received a mf that was already freed\n",
-                   ioc->name);
-               printk (MYIOC_s_ERR_FMT
+           (le32_to_cpu(mf->u.frame.linkage.arg1) == 0xdeadbeaf)) {
+               printk(MYIOC_s_WARN_FMT
+                   "Received a mf that was already freed\n", ioc->name);
+               printk (MYIOC_s_WARN_FMT
                    "req_idx=%x req_idx_MR=%x mf=%p mr=%p sc=%p\n",
                    ioc->name, req_idx, req_idx_MR, mf, mr,
                    mptscsih_get_scsi_lookup(ioc, req_idx_MR));
@@ -682,7 +682,7 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
 
        if((ioc->facts.MsgVersion >= MPI_VERSION_01_05) && pScsiReply){
                dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT
-                       "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d,task-tag=%d)\n",
+                       "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d,task_tag=%d)\n",
                        ioc->name, mf, mr, sc, req_idx, pScsiReply->TaskTag));
        }else{
                dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT
@@ -695,6 +695,7 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
                ;
        } else {
                u32      xfer_cnt;
+               u32      difftransfer;
                u16      status;
                u8       scsi_state, scsi_status;
                u32      log_info;
@@ -703,8 +704,9 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
                scsi_state = pScsiReply->SCSIState;
                scsi_status = pScsiReply->SCSIStatus;
                xfer_cnt = le32_to_cpu(pScsiReply->TransferCount);
-               scsi_set_resid(sc, scsi_bufflen(sc) - xfer_cnt);
+               sc->resid = sc->request_bufflen - xfer_cnt;
                log_info = le32_to_cpu(pScsiReply->IOCLogInfo);
+               vdevice = sc->device->hostdata;
 
                /*
                 *  if we get a data underrun indication, yet no data was
@@ -722,20 +724,9 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
                if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID)
                        mptscsih_copy_sense_data(sc, hd, mf, pScsiReply);
 
-               /*
-                *  Look for + dump FCP ResponseInfo[]!
-                */
-               if (scsi_state & MPI_SCSI_STATE_RESPONSE_INFO_VALID &&
-                   pScsiReply->ResponseInfo) {
-                       printk(MYIOC_s_NOTE_FMT "[%d:%d:%d:%d] "
-                       "FCP_ResponseInfo=%08xh\n", ioc->name,
-                       sc->device->host->host_no, sc->device->channel,
-                       sc->device->id, sc->device->lun,
-                       le32_to_cpu(pScsiReply->ResponseInfo));
-               }
-
                switch(status) {
                case MPI_IOCSTATUS_BUSY:                        /* 0x0002 */
+               case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES:      /* 0x0006 */
                        /* CHECKME!
                         * Maybe: DRIVER_BUSY | SUGGEST_RETRY | DID_SOFT_ERROR (retry)
                         * But not: DID_BUS_BUSY lest one risk
@@ -760,7 +751,6 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
                        if (hd->sel_timeout[pScsiReq->TargetID] < 0xFFFF)
                                hd->sel_timeout[pScsiReq->TargetID]++;
 
-                       vdevice = sc->device->hostdata;
                        if (!vdevice)
                                break;
                        vtarget = vdevice->vtarget;
@@ -782,14 +772,11 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
                                        }
                                }
                        } else if (ioc->bus_type == FC) {
-                               /*
-                                * The FC IOC may kill a request for variety of
-                                * reasons, some of which may be recovered by a
-                                * retry, some which are unlikely to be
-                                * recovered. Return DID_ERROR instead of
-                                * DID_RESET to permit retry of the command,
-                                * just not an infinite number of them
-                                */
+                               /* The FC IOC may kill a request for variety of reasons,
+                               some of which may be recovered by a retry, some which
+                               are unlikely to be recovered. Return DID_ERROR instead
+                               of DID_RESET to permit retry of the command, just not
+                               an infinite number of them */
                                sc->result = DID_ERROR << 16;
                                break;
                        }
@@ -808,14 +795,11 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
                        break;
 
                case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:      /* 0x0049 */
-                       scsi_set_resid(sc, scsi_bufflen(sc) - xfer_cnt);
+                       sc->resid = sc->request_bufflen - xfer_cnt;
                        if((xfer_cnt==0)||(sc->underflow > xfer_cnt))
                                sc->result=DID_SOFT_ERROR << 16;
                        else /* Sufficient data transfer occurred */
                                sc->result = (DID_OK << 16) | scsi_status;
-                       dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT
-                           "RESIDUAL_MISMATCH: result=%x on channel=%d id=%d\n",
-                           ioc->name, sc->result, sc->device->channel, sc->device->id));
                        break;
 
                case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN:          /* 0x0045 */
@@ -824,11 +808,34 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
                         *  precedence!
                         */
                        sc->result = (DID_OK << 16) | scsi_status;
-                       if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
-                               /* Have already saved the status and sense data
+
+                       if (!(scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID)) {
+
+                               /*
+                                * For an Errata on LSI53C1030
+                                * When the length of request data
+                                * and transfer data are different
+                                * with result of command (READ or VERIFY),
+                                * DID_SOFT_ERROR is set.
                                 */
-                               ;
-                       } else {
+                               if (ioc->bus_type == SPI && vdevice &&
+                                   vdevice->vtarget->type == TYPE_DISK) {
+                                       if (pScsiReq->CDB[0] == READ_6  ||
+                                           pScsiReq->CDB[0] == READ_10 ||
+                                           pScsiReq->CDB[0] == READ_12 ||
+                                           pScsiReq->CDB[0] == READ_16 ||
+                                           pScsiReq->CDB[0] == VERIFY  ||
+                                           pScsiReq->CDB[0] == VERIFY_16) {
+                                               if (sc->request_bufflen !=
+                                                   xfer_cnt) {
+                                                   sc->result = DID_SOFT_ERROR << 16;
+                                                   printk(MYIOC_s_WARN_FMT "Errata"
+                                                   "on LSI53C1030 occurred. sc->request_bufflen=0x%02x, "
+                                                   "xfer_cnt=0x%02x\n", ioc->name, sc->request_bufflen, xfer_cnt);
+                                               }
+                                       }
+                               }
+
                                if (xfer_cnt < sc->underflow) {
                                        if (scsi_status == SAM_STAT_BUSY)
                                                sc->result = SAM_STAT_BUSY;
@@ -846,13 +853,6 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
                                }
                        }
 
-
-                       dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT
-                           "  sc->underflow={report ERR if < %02xh bytes xfer'd}\n",
-                           ioc->name, sc->underflow));
-                       dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT
-                           "  ActBytesXferd=%02xh\n", ioc->name, xfer_cnt));
-
                        /* Report Queue Full
                         */
                        if (scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)
@@ -861,13 +861,51 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
                        break;
 
                case MPI_IOCSTATUS_SCSI_DATA_OVERRUN:           /* 0x0044 */
-                       scsi_set_resid(sc, 0);
+                       sc->resid=0;
                case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR:        /* 0x0040 */
                case MPI_IOCSTATUS_SUCCESS:                     /* 0x0000 */
                        sc->result = (DID_OK << 16) | scsi_status;
                        if (scsi_state == 0) {
                                ;
                        } else if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
+
+                               /*
+                                * For potential trouble on LSI53C1030. (date:2007.xx.)
+                                * It is checked whether the length of request data is equal to
+                                * the length of transfer and residual.
+                                * MEDIUM_ERROR is set by incorrect data.
+                                */
+                               if (ioc->bus_type == SPI && vdevice &&
+                                   vdevice->vtarget->type == TYPE_DISK) {
+                                       if (sc->sense_buffer[2] & 0x20) {
+                                           difftransfer =
+                                           sc->sense_buffer[3] << 24 |
+                                           sc->sense_buffer[4] << 16 |
+                                           sc->sense_buffer[5] << 8 |
+                                           sc->sense_buffer[6];
+                                           if ((sc->sense_buffer[3] & 0x80) == 0x80) {
+                                               if (sc->request_bufflen != xfer_cnt) {
+                                                   sc->sense_buffer[2] = MEDIUM_ERROR;
+                                                   sc->sense_buffer[12] = 0xff;
+                                                   sc->sense_buffer[13] = 0xff;
+                                                   printk(MYIOC_s_WARN_FMT "Errata on "
+                                                   "LSI53C1030 occurred. sc->request_bufflen=0x%02x,"
+                                                   "xfer_cnt=0x%02x\n", ioc->name, sc->request_bufflen, xfer_cnt);
+                                               }
+                                       } else {
+                                               if (sc->request_bufflen != xfer_cnt + difftransfer) {
+                                                   sc->sense_buffer[2] = MEDIUM_ERROR;
+                                                   sc->sense_buffer[12] = 0xff;
+                                                   sc->sense_buffer[13] = 0xff;
+                                                   printk(MYIOC_s_WARN_FMT "Errata on "
+                                                   "LSI53C1030 occurred. sc->request_bufflen=0x%02x,"
+                                                   " xfer_cnt=0x%02x, difftransfer=0x%02x\n",
+                                                   ioc->name, sc->request_bufflen , xfer_cnt, difftransfer);
+                                               }
+                                               }
+                                       }
+                               }
+
                                /*
                                 * If running against circa 200003dd 909 MPT f/w,
                                 * may get this (AUTOSENSE_VALID) for actual TASK_SET_FULL
@@ -915,7 +953,6 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
                case MPI_IOCSTATUS_INVALID_SGL:                 /* 0x0003 */
                case MPI_IOCSTATUS_INTERNAL_ERROR:              /* 0x0004 */
                case MPI_IOCSTATUS_RESERVED:                    /* 0x0005 */
-               case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES:      /* 0x0006 */
                case MPI_IOCSTATUS_INVALID_FIELD:               /* 0x0007 */
                case MPI_IOCSTATUS_INVALID_STATE:               /* 0x0008 */
                case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR:          /* 0x0046 */
@@ -938,8 +975,8 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
 
        /* Unmap the DMA buffers, if any. */
        if (sc->use_sg) {
-               pci_unmap_sg(ioc->pcidev, scsi_sglist(sc),
-                               scsi_sg_count(sc), sc->sc_data_direction);
+               pci_unmap_sg(ioc->pcidev, (struct scatterlist *) sc->request_buffer,
+                           sc->use_sg, sc->sc_data_direction);
        } else if (sc->request_bufflen) {
                pci_unmap_single(ioc->pcidev, sc->SCp.dma_handle,
                                sc->request_bufflen, sc->sc_data_direction);
@@ -952,7 +989,7 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
        return 1;
 }
 
-/*
+/**
  *     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.
@@ -961,7 +998,7 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
  *     Returns: None.
  *
  *     Must be called while new I/Os are being queued.
- */
+ **/
 static void
 mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd)
 {
@@ -986,25 +1023,23 @@ mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd)
                        continue;
                if (sc->use_sg) {
                        pci_unmap_sg(ioc->pcidev,
-                               scsi_sglist(sc),
-                               scsi_sg_count(sc),
-                               sc->sc_data_direction);
+                           (struct scatterlist *) sc->request_buffer,
+                           sc->use_sg, sc->sc_data_direction);
                } else if (sc->request_bufflen) {
                        pci_unmap_single(ioc->pcidev,
-                               sc->SCp.dma_handle,
-                               sc->request_bufflen,
-                               sc->sc_data_direction);
+                           sc->SCp.dma_handle, sc->request_bufflen,
+                           sc->sc_data_direction);
                }
                sc->result = DID_RESET << 16;
                sc->host_scribble = NULL;
-               sdev_printk(KERN_INFO, sc->device, MYIOC_s_FMT
-                   "completing cmds: fw_channel %d, fw_id %d, sc=%p,"
-                   " mf = %p, idx=%x\n", ioc->name, channel, id, sc, mf, ii);
+               dtmprintk(ioc, sdev_printk(KERN_INFO, sc->device, MYIOC_s_FMT
+                   "completing cmds: fw_channel %d, fw_id %d, sc=%p, mf = %p, "
+                   "idx=%x\n", ioc->name, channel, id, sc, mf, ii));
                sc->scsi_done(sc);
        }
 }
 
-/*
+/**
  *     mptscsih_search_running_cmds - Delete any commands associated
  *             with the specified target and lun. Function called only
  *             when a lun is disable by mid-layer.
@@ -1017,15 +1052,15 @@ mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd)
  *     Returns: None.
  *
  *     Called from slave_destroy.
- */
+ **/
 static void
 mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
 {
        SCSIIORequest_t *mf = NULL;
        int              ii;
        struct scsi_cmnd *sc;
-       struct scsi_lun  lun;
-       MPT_ADAPTER *ioc = hd->ioc;
+       struct scsi_lun lun;
+       MPT_ADAPTER     *ioc = hd->ioc;
        unsigned long   flags;
 
        spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
@@ -1035,8 +1070,11 @@ mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
                        mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(ioc, ii);
                        if (mf == NULL)
                                continue;
-                       /* If the device is a hidden raid component, then its
-                        * expected that the mf->function will be RAID_SCSI_IO
+
+                       /*
+                        * If the device is a hidden raid component,
+                        * then its expected that
+                        * the function would be raid scsi io
                         */
                        if (vdevice->vtarget->tflags &
                            MPT_TARGET_FLAGS_RAID_COMPONENT && mf->Function !=
@@ -1056,21 +1094,23 @@ mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
                        mptscsih_freeChainBuffers(ioc, ii);
                        mpt_free_msg_frame(ioc, (MPT_FRAME_HDR *)mf);
                        if (sc->use_sg) {
-                               pci_unmap_sg(hd->ioc->pcidev,
+                               pci_unmap_sg(ioc->pcidev,
                                (struct scatterlist *) sc->request_buffer,
                                        sc->use_sg,
                                        sc->sc_data_direction);
                        } else if (sc->request_bufflen) {
-                               pci_unmap_single(hd->ioc->pcidev,
+                               pci_unmap_single(ioc->pcidev,
                                        sc->SCp.dma_handle,
                                        sc->request_bufflen,
                                        sc->sc_data_direction);
                        }
                        sc->host_scribble = NULL;
                        sc->result = DID_NO_CONNECT << 16;
-                       sdev_printk(KERN_INFO, sc->device, MYIOC_s_FMT "completing cmds: fw_channel %d,"
-                          "fw_id %d, sc=%p, mf = %p, idx=%x\n", ioc->name, vdevice->vtarget->channel,
-                          vdevice->vtarget->id, sc, mf, ii);
+                       dtmprintk(ioc, sdev_printk(KERN_INFO, sc->device,
+                          MYIOC_s_FMT "completing cmds: fw_channel %d, "
+                          "fw_id %d, sc=%p, mf = %p, idx=%x\n", ioc->name,
+                          vdevice->vtarget->channel, vdevice->vtarget->id,
+                          sc, mf, ii));
                        sc->scsi_done(sc);
                        spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
                }
@@ -1082,7 +1122,7 @@ mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*
+/**
  *     mptscsih_report_queue_full - Report QUEUE_FULL status returned
  *     from a SCSI target device.
  *     @sc: Pointer to scsi_cmnd structure
@@ -1092,19 +1132,19 @@ mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
  *     This routine periodically reports QUEUE_FULL status returned from a
  *     SCSI target device.  It reports this to the console via kernel
  *     printk() API call, not more than once every 10 seconds.
- */
+ **/
 static void
 mptscsih_report_queue_full(struct scsi_cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq)
 {
        long time = jiffies;
-       MPT_SCSI_HOST           *hd;
+       MPT_SCSI_HOST   *hd;
        MPT_ADAPTER     *ioc;
 
        if (sc->device == NULL)
                return;
        if (sc->device->host == NULL)
                return;
-       if ((hd = shost_priv(sc->device->host)) == NULL)
+       if ((hd = shost_private(sc->device->host)) == NULL)
                return;
        ioc = hd->ioc;
        if (time - hd->last_queue_full > 10 * HZ) {
@@ -1115,12 +1155,12 @@ mptscsih_report_queue_full(struct scsi_cmnd *sc, SCSIIOReply_t *pScsiReply, SCSI
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*
+/**
  *     mptscsih_remove - Removed scsi devices
  *     @pdev: Pointer to pci_dev structure
  *
  *
- */
+ **/
 void
 mptscsih_remove(struct pci_dev *pdev)
 {
@@ -1136,7 +1176,7 @@ mptscsih_remove(struct pci_dev *pdev)
 
        scsi_remove_host(host);
 
-       if((hd = shost_priv(host)) == NULL)
+       if((hd = shost_private(host)) == NULL)
                return;
 
        mptscsih_shutdown(pdev);
@@ -1166,10 +1206,10 @@ mptscsih_remove(struct pci_dev *pdev)
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*
+/**
  *     mptscsih_shutdown - reboot notifier
  *
- */
+ **/
 void
 mptscsih_shutdown(struct pci_dev *pdev)
 {
@@ -1177,28 +1217,37 @@ mptscsih_shutdown(struct pci_dev *pdev)
 
 #ifdef CONFIG_PM
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*
+/**
  *     mptscsih_suspend - Fusion MPT scsi driver suspend routine.
  *
  *
- */
+ **/
 int
 mptscsih_suspend(struct pci_dev *pdev, pm_message_t state)
 {
+       MPT_ADAPTER             *ioc = pci_get_drvdata(pdev);
+
+       scsi_block_requests(ioc->sh);
+       flush_scheduled_work();
        mptscsih_shutdown(pdev);
        return mpt_suspend(pdev,state);
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*
+/**
  *     mptscsih_resume - Fusion MPT scsi driver resume routine.
  *
  *
- */
+ **/
 int
 mptscsih_resume(struct pci_dev *pdev)
 {
-       return mpt_resume(pdev);
+       MPT_ADAPTER             *ioc = pci_get_drvdata(pdev);
+       int rc;
+
+       rc = mpt_resume(pdev);
+       scsi_unblock_requests(ioc->sh);
+       return rc;
 }
 
 #endif
@@ -1211,14 +1260,14 @@ mptscsih_resume(struct pci_dev *pdev)
  *     (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;
 
-       h = shost_priv(SChost);
+       h = shost_private(SChost);
 
        if (h) {
                if (h->info_kbuf == NULL)
@@ -1312,7 +1361,7 @@ int
 mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
                        int length, int func)
 {
-       MPT_SCSI_HOST   *hd = shost_priv(host);
+       MPT_SCSI_HOST   *hd = shost_private(host);
        MPT_ADAPTER     *ioc = hd->ioc;
        int size = 0;
 
@@ -1344,7 +1393,7 @@ mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t off
  *     from a linux scsi_cmnd request and send it to the IOC.
  *
  *     Returns 0. (rtn value discarded by linux scsi mid-layer)
- */
+ **/
 int
 mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
 {
@@ -1352,7 +1401,6 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
        MPT_FRAME_HDR           *mf;
        SCSIIORequest_t         *pScsiReq;
        VirtDevice              *vdevice = SCpnt->device->hostdata;
-       int      lun;
        u32      datalen;
        u32      scsictl;
        u32      scsidir;
@@ -1361,26 +1409,23 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
        int      ii;
        MPT_ADAPTER *ioc;
 
-       hd = shost_priv(SCpnt->device->host);
+       hd = shost_private(SCpnt->device->host);
        ioc = hd->ioc;
-       lun = SCpnt->device->lun;
        SCpnt->scsi_done = done;
 
        dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "qcmd: SCpnt=%p, done()=%p\n",
                ioc->name, SCpnt, done));
 
-       if (hd->resetPending) {
-               dtmprintk(ioc, printk(MYIOC_s_WARN_FMT "qcmd: SCpnt=%p timeout + 60HZ\n",
-                       ioc->name, SCpnt));
+       if ((ioc->bus_type == SAS && ioc->sas_discovery_quiesce_io) ||
+           ioc->taskmgmt_quiesce_io)
                return SCSI_MLQUEUE_HOST_BUSY;
-       }
 
        /*
         *  Put together a MPT SCSI request...
         */
        if ((mf = mpt_get_msg_frame(ioc->DoneCtx, ioc)) == NULL) {
                dprintk(ioc, printk(MYIOC_s_WARN_FMT "QueueCmd, no msg frames!!\n",
-                               ioc->name));
+                       ioc->name));
                return SCSI_MLQUEUE_HOST_BUSY;
        }
 
@@ -1395,10 +1440,10 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
         *    will be no data transfer!  GRRRRR...
         */
        if (SCpnt->sc_data_direction == DMA_FROM_DEVICE) {
-               datalen = scsi_bufflen(SCpnt);
+               datalen = SCpnt->request_bufflen;
                scsidir = MPI_SCSIIO_CONTROL_READ;      /* DATA IN  (host<--ioc<--dev) */
        } else if (SCpnt->sc_data_direction == DMA_TO_DEVICE) {
-               datalen = scsi_bufflen(SCpnt);
+               datalen = SCpnt->request_bufflen;
                scsidir = MPI_SCSIIO_CONTROL_WRITE;     /* DATA OUT (host-->ioc-->dev) */
        } else {
                datalen = 0;
@@ -1454,8 +1499,8 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
         */
        if (datalen == 0) {
                /* Add a NULL SGE */
-               ioc->add_sge((char *)&pScsiReq->SGL,
-                       MPT_SGE_FLAGS_SSIMPLE_READ | 0, (dma_addr_t) -1);
+               ioc->add_sge((char *)&pScsiReq->SGL, MPT_SGE_FLAGS_SSIMPLE_READ | 0,
+                       (dma_addr_t) -1);
        } else {
                /* Add a 32 or 64 bit SGE */
                if (mptscsih_AddSGE(ioc, SCpnt, pScsiReq, my_idx) != SUCCESS)
@@ -1478,7 +1523,7 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*
+/**
  *     mptscsih_freeChainBuffers - Function to free chain buffers associated
  *     with a SCSI IO request
  *     @hd: Pointer to the MPT_SCSI_HOST instance
@@ -1486,7 +1531,7 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
  *
  *     Called if SG chain buffer allocation fails and mptscsih callbacks.
  *     No return.
- */
+ **/
 static void
 mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx)
 {
@@ -1533,243 +1578,457 @@ mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx)
  */
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/**
- *     mptscsih_TMHandler - Generic handler for SCSI Task Management.
- *     @hd: Pointer to MPT SCSI HOST structure
- *     @type: Task Management type
- *     @channel: channel number for task management
- *     @id: Logical Target ID for reset (if appropriate)
- *     @lun: Logical Unit for reset (if appropriate)
- *     @ctx2abort: Context for the task to be aborted (if appropriate)
- *     @timeout: timeout for task management control
- *
- *     Fall through to mpt_HardResetHandler if: not operational, too many
- *     failed TM requests or handshake failure.
- *
- *     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 %FAILED.
- **/
-int
-mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout)
-{
-       MPT_ADAPTER     *ioc;
-       int              rc = -1;
-       u32              ioc_raw_state;
-       unsigned long    flags;
-
-       ioc = hd->ioc;
-       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TMHandler Entered!\n", ioc->name));
-
-       // 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 FAILED;
-       }
-       spin_unlock_irqrestore(&ioc->diagLock, flags);
-
-       /*  Wait a fixed amount of time for the TM pending flag to be cleared.
-        *  If we time out and not bus reset, then we return a FAILED status
-        *  to the caller.
-        *  The call to mptscsih_tm_pending_wait() will set the pending flag
-        *  if we are
-        *  successful. Otherwise, reload the FW.
-        */
-       if (mptscsih_tm_pending_wait(hd) == FAILED) {
-               if (type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {
-                       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TMHandler abort: "
-                          "Timed out waiting for last TM (%d) to complete! \n",
-                          ioc->name, hd->tmPending));
-                       return FAILED;
-               } else if (type == MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET) {
-                       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TMHandler target "
-                               "reset: Timed out waiting for last TM (%d) "
-                               "to complete! \n", ioc->name,
-                               hd->tmPending));
-                       return FAILED;
-               } else if (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) {
-                       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TMHandler bus reset: "
-                          "Timed out waiting for last TM (%d) to complete! \n",
-                         ioc->name, hd->tmPending));
-                       return FAILED;
-               }
-       } else {
-               spin_lock_irqsave(&ioc->FreeQlock, flags);
-               hd->tmPending |=  (1 << type);
-               spin_unlock_irqrestore(&ioc->FreeQlock, flags);
-       }
-
-       ioc_raw_state = mpt_GetIocState(ioc, 0);
-
-       if ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL) {
-               printk(MYIOC_s_WARN_FMT
-                       "TM Handler for type=%x: IOC Not operational (0x%x)!\n",
-                       ioc->name, type, ioc_raw_state);
-               printk(MYIOC_s_WARN_FMT " Issuing HardReset!!\n", ioc->name);
-               if (mpt_HardResetHandler(ioc, CAN_SLEEP) < 0)
-                       printk(MYIOC_s_WARN_FMT "TMHandler: HardReset "
-                           "FAILED!!\n", ioc->name);
-               return FAILED;
-       }
-
-       if (ioc_raw_state & MPI_DOORBELL_ACTIVE) {
-               printk(MYIOC_s_WARN_FMT
-                       "TM Handler for type=%x: ioc_state: "
-                       "DOORBELL_ACTIVE (0x%x)!\n",
-                       ioc->name, type, ioc_raw_state);
-               return FAILED;
-       }
-
-       /* Isse the Task Mgmt request.
-        */
-       if (hd->hard_resets < -1)
-               hd->hard_resets++;
-
-       rc = mptscsih_IssueTaskMgmt(hd, type, channel, id, lun,
-           ctx2abort, timeout);
-       if (rc)
-               printk(MYIOC_s_INFO_FMT "Issue of TaskMgmt failed!\n",
-                      ioc->name);
-       else
-               dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Issue of TaskMgmt Successful!\n",
-                          ioc->name));
-
-       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
-                       "TMHandler rc = %d!\n", ioc->name, rc));
-
-       return rc;
-}
-
-
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/**
- *     mptscsih_IssueTaskMgmt - Generic send Task Management function.
- *     @hd: Pointer to MPT_SCSI_HOST structure
- *     @type: Task Management type
- *     @channel: channel number for task management
- *     @id: Logical Target ID for reset (if appropriate)
- *     @lun: Logical Unit for reset (if appropriate)
- *     @ctx2abort: Context for the task to be aborted (if appropriate)
- *     @timeout: timeout for task management control
- *
- *     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, or FAILED.
- *
- **/
+
 static int
-mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout)
+mptscsih_scandv_bus_reset(MPT_ADAPTER *ioc)
 {
        MPT_FRAME_HDR   *mf;
        SCSITaskMgmt_t  *pScsiTm;
+       SCSITaskMgmtReply_t *pScsiTmReply;
        int              ii;
        int              retval;
-       MPT_ADAPTER     *ioc = hd->ioc;
+       unsigned long    timeout;
+       unsigned long    time_count;
+       u16              iocstatus;
 
-       /* Return Fail to calling function if no message frames available.
+       mutex_lock(&ioc->taskmgmt_cmds.mutex);
+       if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) {
+               mutex_unlock(&ioc->taskmgmt_cmds.mutex);
+               return -EPERM;
+       }
+
+       /* Send request
         */
        if ((mf = mpt_get_msg_frame(ioc->TaskCtx, ioc)) == NULL) {
-               dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "IssueTaskMgmt, no msg frames!!\n",
+               dtmprintk(ioc, printk(MYIOC_s_WARN_FMT "TaskMgmt, no msg frames!!\n",
                                ioc->name));
-               return FAILED;
+               mpt_clear_taskmgmt_in_progress_flag(ioc);
+               retval = -ENOMEM;
+               goto out;
        }
-       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IssueTaskMgmt request @ %p\n",
-                       ioc->name, mf));
 
-       /* Format the Request
-        */
+       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request (mf=%p)\n",
+               ioc->name, mf));
+
        pScsiTm = (SCSITaskMgmt_t *) mf;
-       pScsiTm->TargetID = id;
-       pScsiTm->Bus = channel;
-       pScsiTm->ChainOffset = 0;
+       memset(pScsiTm, 0, sizeof(SCSITaskMgmt_t));
        pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
-
+       pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS;
+       pScsiTm->MsgFlags = MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION;
+       pScsiTm->TargetID = 0;
+       pScsiTm->Bus = 0;
+       pScsiTm->ChainOffset = 0;
        pScsiTm->Reserved = 0;
-       pScsiTm->TaskType = type;
        pScsiTm->Reserved1 = 0;
-       pScsiTm->MsgFlags = (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS)
-                    ? MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION : 0;
-
-       int_to_scsilun(lun, (struct scsi_lun *)pScsiTm->LUN);
-
+       pScsiTm->TaskMsgContext = 0;
+       for (ii= 0; ii < 8; ii++)
+               pScsiTm->LUN[ii] = 0;
        for (ii=0; ii < 7; ii++)
                pScsiTm->Reserved2[ii] = 0;
 
-       pScsiTm->TaskMsgContext = ctx2abort;
-
-       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IssueTaskMgmt: ctx2abort (0x%08x) "
-               "type=%d\n", ioc->name, ctx2abort, type));
+       switch (ioc->bus_type) {
+               case FC:
+                       timeout = 40;
+                       break;
+               case SAS:
+                       timeout = 30;
+                       break;
+               case SPI:
+               default:
+                       timeout = 2;
+                       break;
+       }
 
-       DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)pScsiTm);
+       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt type=%d timeout=%ld\n",
+           ioc->name, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS, timeout));
 
+       INITIALIZE_MGMT_STATUS(ioc->taskmgmt_cmds.status)
+       CLEAR_MGMT_STATUS(ioc->internal_cmds.status)
+       retval = 0;
+       time_count = jiffies;
        if ((ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q) &&
            (ioc->facts.MsgVersion >= MPI_VERSION_01_05))
                mpt_put_msg_frame_hi_pri(ioc->TaskCtx, ioc, mf);
        else {
                retval = mpt_send_handshake_request(ioc->TaskCtx, ioc,
-                       sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP);
-               if (retval) {
-                       dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "send_handshake FAILED!"
-                       " (hd %p, ioc %p, mf %p, rc=%d) \n", ioc->name, hd,
-                       ioc, mf, retval));
-                       goto fail_out;
+                   sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP);
+               if (retval != 0) {
+                       dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "TaskMgmt send_handshake FAILED!"
+                               " (ioc %p, mf %p, rc=%d) \n", ioc->name,
+                               ioc, mf, retval));
+                       mpt_clear_taskmgmt_in_progress_flag(ioc);
+                       goto out;
                }
        }
 
-       if(mptscsih_tm_wait_for_completion(hd, timeout) == FAILED) {
-               dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "task management request TIMED OUT!"
-                       " (hd %p, ioc %p, mf %p) \n", ioc->name, hd,
-                       ioc, mf));
-               dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling HardReset! \n",
-                        ioc->name));
-               retval = mpt_HardResetHandler(ioc, CAN_SLEEP);
-               dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "rc=%d \n",
-                        ioc->name, retval));
-               goto fail_out;
+       /* Now wait for the command to complete */
+       ii = wait_for_completion_timeout(&ioc->taskmgmt_cmds.done, timeout*HZ);
+       if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
+               dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "TaskMgmt failed\n", ioc->name));
+               mpt_free_msg_frame(ioc, mf);
+               mpt_clear_taskmgmt_in_progress_flag(ioc);
+               retval = -1; /* return failure */
+               goto out;
        }
 
-       /*
-        * Handle success case, see if theres a non-zero ioc_status.
-        */
-       if (hd->tm_iocstatus == MPI_IOCSTATUS_SUCCESS ||
-          hd->tm_iocstatus == MPI_IOCSTATUS_SCSI_TASK_TERMINATED ||
-          hd->tm_iocstatus == MPI_IOCSTATUS_SCSI_IOC_TERMINATED)
+       if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
+               dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "TaskMgmt failed\n", ioc->name));
+               retval = -1; /* return failure */
+               goto out;
+       }
+
+       pScsiTmReply = (SCSITaskMgmtReply_t *) ioc->taskmgmt_cmds.reply;
+       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+           "TaskMgmt fw_channel = %d, fw_id = %d, task_type = 0x%02X,\n"
+           "\tiocstatus = 0x%04X, loginfo = 0x%08X, response_code = 0x%02X,\n"
+           "\tterm_cmnds = %d\n", ioc->name, pScsiTmReply->Bus,
+           pScsiTmReply->TargetID, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
+           le16_to_cpu(pScsiTmReply->IOCStatus),
+           le32_to_cpu(pScsiTmReply->IOCLogInfo),
+           pScsiTmReply->ResponseCode,
+           le32_to_cpu(pScsiTmReply->TerminationCount)));
+
+       iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK;
+
+       if (iocstatus == MPI_IOCSTATUS_SCSI_TASK_TERMINATED ||
+          iocstatus == MPI_IOCSTATUS_SCSI_IOC_TERMINATED ||
+          iocstatus == MPI_IOCSTATUS_SUCCESS)
                retval = 0;
-       else
-               retval = FAILED;
+       else {
+               dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "TaskMgmt failed\n", ioc->name));
+               retval = -1; /* return failure */
+       }
 
+ out:
+       mutex_unlock(&ioc->taskmgmt_cmds.mutex);
+       CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status)
        return retval;
+}
+
+int
+mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
+{
+       MPT_SCSI_HOST   *hd;
 
- fail_out:
+       if ((ioc->sh == NULL) || (ioc->sh->hostdata == NULL))
+               return 0;
 
-       /*
-        * Free task managment mf, and corresponding tm flags
-        */
-       mpt_free_msg_frame(ioc, mf);
-       hd->tmPending = 0;
-       hd->tmState = TM_STATE_NONE;
-       return FAILED;
+       switch (reset_phase) {
+       case MPT_IOC_SETUP_RESET:
+               dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __FUNCTION__));
+               break;
+       case MPT_IOC_PRE_RESET:
+               dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "%s: MPT_IOC_PRE_RESET\n", ioc->name, __FUNCTION__));
+               hd = shost_private(ioc->sh);
+               mptscsih_flush_running_cmds(hd);
+               break;
+       case MPT_IOC_POST_RESET:
+               dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "%s: MPT_IOC_POST_RESET\n", ioc->name, __FUNCTION__));
+               if (ioc->internal_cmds.status & MPT_MGMT_STATUS_PENDING) {
+                       ioc->internal_cmds.status |= MPT_MGMT_STATUS_DID_IOCRESET;
+                       complete(&ioc->internal_cmds.done);
+               }
+               break;
+       default:
+               break;
+       }
+       return 1;               /* currently means nothing really */
 }
 
-static int
-mptscsih_get_tm_timeout(MPT_ADAPTER *ioc)
+void
+mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code)
+{
+       char *desc;
+
+       switch (response_code) {
+       case MPI_SCSITASKMGMT_RSP_TM_COMPLETE:
+               desc = "The task completed.";
+               break;
+       case MPI_SCSITASKMGMT_RSP_INVALID_FRAME:
+               desc = "The IOC received an invalid frame status.";
+               break;
+       case MPI_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED:
+               desc = "The task type is not supported.";
+               break;
+       case MPI_SCSITASKMGMT_RSP_TM_FAILED:
+               desc = "The requested task failed.";
+               break;
+       case MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED:
+               desc = "The task completed successfully.";
+               break;
+       case MPI_SCSITASKMGMT_RSP_TM_INVALID_LUN:
+               desc = "The LUN request is invalid.";
+               break;
+       case MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC:
+               desc = "The task is in the IOC queue and has not been sent to target.";
+               break;
+       default:
+               desc = "unknown";
+               break;
+       }
+       printk(MYIOC_s_DEBUG_FMT "Response Code(0x%08x): F/W: %s\n",
+               ioc->name, response_code, desc);
+}
+
+static int
+mptscsih_taskmgmt_reply(MPT_ADAPTER *ioc, u8 type, SCSITaskMgmtReply_t *pScsiTmReply)
+{
+       u16                      iocstatus;
+       u32                      termination_count;
+       int                      retval;
+
+       if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
+               retval = FAILED;
+               goto out;
+       }
+
+       DBG_DUMP_TM_REPLY_FRAME(ioc, (u32 *)pScsiTmReply);
+
+       iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK;
+       termination_count = le32_to_cpu(pScsiTmReply->TerminationCount);
+
+       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+           "TaskMgmt fw_channel = %d, fw_id = %d, task_type = 0x%02X,\n"
+           "\tiocstatus = 0x%04X, loginfo = 0x%08X, response_code = 0x%02X,\n"
+           "\tterm_cmnds = %d\n", ioc->name, pScsiTmReply->Bus,
+           pScsiTmReply->TargetID, type, le16_to_cpu(pScsiTmReply->IOCStatus),
+           le32_to_cpu(pScsiTmReply->IOCLogInfo), pScsiTmReply->ResponseCode,
+           termination_count));
+
+       if (ioc->facts.MsgVersion >= MPI_VERSION_01_05 &&
+           pScsiTmReply->ResponseCode)
+               mptscsih_taskmgmt_response_code(ioc,
+                   pScsiTmReply->ResponseCode);
+
+       if (iocstatus == MPI_IOCSTATUS_SUCCESS) {
+               retval = 0;
+               goto out;
+       }
+
+       retval = FAILED;
+       if (type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {
+               if (termination_count == 1)
+                       retval = 0;
+               goto out;
+       }
+
+       if (iocstatus == MPI_IOCSTATUS_SCSI_TASK_TERMINATED ||
+          iocstatus == MPI_IOCSTATUS_SCSI_IOC_TERMINATED)
+               retval = 0;
+
+ out:
+       return retval;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     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.
+ **/
+int
+mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
+{
+       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt completed (mf=%p, mr=%p)\n",
+           ioc->name, mf, mr));
+
+       ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
+
+       if (!mr)
+               goto out;
+
+       ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
+       memcpy(ioc->taskmgmt_cmds.reply, mr,
+           min(MPT_DEFAULT_FRAME_SIZE, 4 * mr->u.reply.MsgLength));
+ out:
+       if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) {
+               mpt_clear_taskmgmt_in_progress_flag(ioc);
+               ioc->taskmgmt_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
+               complete(&ioc->taskmgmt_cmds.done);
+               return 1;
+       }
+       return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mptscsih_IssueTaskMgmt - Generic send Task Management function.
+ *     @hd: Pointer to MPT_SCSI_HOST structure
+ *     @type: Task Management type
+ *     @channel: channel number for task management
+ *     @id: Logical Target ID for reset (if appropriate)
+ *     @lun: Logical Unit for reset (if appropriate)
+ *     @ctx2abort: Context for the task to be aborted (if appropriate)
+ *     @timeout: timeout for task management control
+ *
+ *     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, or FAILED.
+ *
+ **/
+int
+mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout)
+{
+       MPT_FRAME_HDR   *mf;
+       SCSITaskMgmt_t  *pScsiTm;
+       int              ii;
+       int              retval;
+       MPT_ADAPTER     *ioc = hd->ioc;
+       unsigned long    timeleft;
+       u8               issue_hard_reset;
+       u32              ioc_raw_state;
+       unsigned long    time_count;
+
+       issue_hard_reset = 0;
+       ioc_raw_state = mpt_GetIocState(ioc, 0);
+
+       if ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL) {
+               printk(MYIOC_s_WARN_FMT
+                       "TaskMgmt type=%x: IOC Not operational (0x%x)!\n",
+                       ioc->name, type, ioc_raw_state);
+               printk(MYIOC_s_WARN_FMT "Issuing HardReset from %s!!\n",
+                   ioc->name, __FUNCTION__);
+               if (mpt_HardResetHandler(ioc, CAN_SLEEP) < 0)
+                       printk(MYIOC_s_WARN_FMT "TaskMgmt HardReset "
+                           "FAILED!!\n", ioc->name);
+               return 0;
+       }
+
+       if (ioc_raw_state & MPI_DOORBELL_ACTIVE) {
+               printk(MYIOC_s_WARN_FMT
+                       "TaskMgmt type=%x: ioc_state: "
+                       "DOORBELL_ACTIVE (0x%x)!\n",
+                       ioc->name, type, ioc_raw_state);
+               return FAILED;
+       }
+
+       mutex_lock(&ioc->taskmgmt_cmds.mutex);
+       if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) {
+       mutex_unlock(&ioc->taskmgmt_cmds.mutex);
+               retval = FAILED;
+               goto out;
+       }
+
+       /* Return Fail to calling function if no message frames available.
+        */
+       if ((mf = mpt_get_msg_frame(ioc->TaskCtx, ioc)) == NULL) {
+               dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "TaskMgmt no msg frames!!\n",
+                               ioc->name));
+               retval = FAILED;
+               mpt_clear_taskmgmt_in_progress_flag(ioc);
+               goto out;
+       }
+       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request (mf=%p)\n",
+                       ioc->name, mf));
+
+       /* Format the Request
+        */
+       pScsiTm = (SCSITaskMgmt_t *) mf;
+       pScsiTm->TargetID = id;
+       pScsiTm->Bus = channel;
+       pScsiTm->ChainOffset = 0;
+       pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
+
+       pScsiTm->Reserved = 0;
+       pScsiTm->TaskType = type;
+       pScsiTm->Reserved1 = 0;
+       pScsiTm->MsgFlags = (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS)
+                    ? MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION : 0;
+
+       int_to_scsilun(lun, (struct scsi_lun *)pScsiTm->LUN);
+
+       for (ii=0; ii < 7; ii++)
+               pScsiTm->Reserved2[ii] = 0;
+
+       pScsiTm->TaskMsgContext = ctx2abort;
+
+       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt: ctx2abort (0x%08x) "
+           "task_type = 0x%02X, timeout = %ld\n", ioc->name, ctx2abort,
+           type, timeout));
+
+       DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)pScsiTm);
+
+       INITIALIZE_MGMT_STATUS(ioc->taskmgmt_cmds.status)
+       time_count = jiffies;
+       if ((ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q) &&
+           (ioc->facts.MsgVersion >= MPI_VERSION_01_05))
+               mpt_put_msg_frame_hi_pri(ioc->TaskCtx, ioc, mf);
+       else {
+               retval = mpt_send_handshake_request(ioc->TaskCtx, ioc,
+                       sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP);
+               if (retval) {
+                       dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "TaskMgmt handshake FAILED!"
+                           " (mf=%p, rc=%d) \n", ioc->name, mf, retval));
+                       mpt_free_msg_frame(ioc, mf);
+                       mpt_clear_taskmgmt_in_progress_flag(ioc);
+                       goto out;
+               }
+       }
+
+       timeleft = wait_for_completion_timeout(&ioc->taskmgmt_cmds.done, timeout*HZ);
+       if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
+               retval = FAILED;
+               dtmprintk(ioc, printk(MYIOC_s_ERR_FMT
+                   "TaskMgmt TIMED OUT!(mf=%p)\n", ioc->name, mf));
+               mpt_clear_taskmgmt_in_progress_flag(ioc);
+               if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
+                       goto out;
+               issue_hard_reset = 1;
+               goto out;
+       }
+
+       retval = mptscsih_taskmgmt_reply(ioc, type,
+           (SCSITaskMgmtReply_t *) ioc->taskmgmt_cmds.reply);
+
+       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+           "TaskMgmt completed (%d seconds)\n",
+           ioc->name, jiffies_to_msecs(jiffies - time_count)/1000));
+
+ out:
+
+       CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status)
+       if(issue_hard_reset) {
+               printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
+                   ioc->name, __FUNCTION__);
+               if ((retval = mpt_SoftResetHandler(ioc, CAN_SLEEP)) != 0)
+                       retval = mpt_HardResetHandler(ioc, CAN_SLEEP);
+               mpt_free_msg_frame(ioc, mf);
+       }
+
+       retval = (retval == 0) ? 0 : FAILED;
+       mutex_unlock(&ioc->taskmgmt_cmds.mutex);
+       return retval;
+}
+
+static int
+mptscsih_get_tm_timeout(MPT_ADAPTER *ioc)
 {
        switch (ioc->bus_type) {
        case FC:
                return 40;
        case SAS:
-               return 10;
+               return 30;
        case SPI:
        default:
-               return 2;
+               return 10;
        }
 }
 
@@ -1792,11 +2051,11 @@ mptscsih_abort(struct scsi_cmnd * SCpnt)
        int              retval;
        VirtDevice       *vdevice;
        ulong            sn = SCpnt->serial_number;
-       MPT_ADAPTER     *ioc;
+       MPT_ADAPTER     *ioc;
 
        /* If we can't locate our host adapter structure, return FAILED status.
         */
-       if ((hd = shost_priv(SCpnt->device->host)) == NULL) {
+       if ((hd = shost_private(SCpnt->device->host)) == NULL) {
                SCpnt->result = DID_RESET << 16;
                SCpnt->scsi_done(SCpnt);
                printk(KERN_ERR MYNAM ": task abort: "
@@ -1816,7 +2075,21 @@ mptscsih_abort(struct scsi_cmnd * SCpnt)
                    ioc->name, SCpnt));
                SCpnt->result = DID_NO_CONNECT << 16;
                SCpnt->scsi_done(SCpnt);
-               retval = 0;
+               retval = SUCCESS;
+               goto out;
+       }
+
+       /* Find this command
+        */
+       if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(ioc, SCpnt)) < 0) {
+               /* Cmd not found in ScsiLookup.
+                * Do OS callback.
+                */
+               SCpnt->result = DID_RESET << 16;
+               dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "task abort: command not in the active list! (sc=%p)\n",
+                   ioc->name, SCpnt));
+               retval = SUCCESS;
                goto out;
        }
 
@@ -1831,27 +2104,23 @@ mptscsih_abort(struct scsi_cmnd * SCpnt)
                goto out;
        }
 
-       /* Find this command
+       /* Task aborts are not supported for volumes.
         */
-       if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(ioc, SCpnt)) < 0) {
-               /* Cmd not found in ScsiLookup.
-                * Do OS callback.
-                */
+       if (vdevice->vtarget->raidVolume) {
+               dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "task abort: raid volume (sc=%p)\n",
+                   ioc->name, SCpnt));
                SCpnt->result = DID_RESET << 16;
-               dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "task abort: "
-                  "Command not in the active list! (sc=%p)\n", ioc->name,
-                  SCpnt));
-               retval = 0;
-               goto out;
-       }
-
-       if (hd->resetPending) {
                retval = FAILED;
                goto out;
        }
 
-       if (hd->timeouts < -1)
-               hd->timeouts++;
+       if(mpt_fwfault_debug)
+               mpt_halt_firmware(ioc);
+
+       if (ioc->timeouts < -1)
+               ioc->timeouts++;
+
 
        /* Most important!  Set TaskMsgContext to SCpnt's MsgContext!
         * (the IO to be ABORT'd)
@@ -1862,25 +2131,31 @@ mptscsih_abort(struct scsi_cmnd * SCpnt)
         */
        mf = MPT_INDEX_2_MFPTR(ioc, scpnt_idx);
        ctx2abort = mf->u.frame.hwhdr.msgctxu.MsgContext;
-
-       hd->abortSCpnt = SCpnt;
-
-       retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK,
+       mptscsih_IssueTaskMgmt(hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK,
            vdevice->vtarget->channel, vdevice->vtarget->id, vdevice->lun,
            ctx2abort, mptscsih_get_tm_timeout(ioc));
 
+       /* check to see whether command actually completed and/or
+        * terminated
+        */
        if (SCPNT_TO_LOOKUP_IDX(ioc, SCpnt) == scpnt_idx &&
-           SCpnt->serial_number == sn)
+           SCpnt->serial_number == sn) {
+               dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "task abort: command still in active list! (sc=%p)\n",
+                   ioc->name, SCpnt));
                retval = FAILED;
+       } else {
+               dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "task abort: command cleared from active list! (sc=%p)\n",
+                   ioc->name, SCpnt));
+               retval = SUCCESS;
+       }
 
  out:
        printk(MYIOC_s_INFO_FMT "task abort: %s (sc=%p)\n",
-           ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
+           ioc->name, ((retval == SUCCESS) ? "SUCCESS" : "FAILED" ), SCpnt);
 
-       if (retval == 0)
-               return SUCCESS;
-       else
-               return FAILED;
+       return retval;
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -1902,7 +2177,7 @@ mptscsih_dev_reset(struct scsi_cmnd * SCpnt)
 
        /* If we can't locate our host adapter structure, return FAILED status.
         */
-       if ((hd = shost_priv(SCpnt->device->host)) == NULL){
+       if ((hd = shost_private(SCpnt->device->host)) == NULL){
                printk(KERN_ERR MYNAM ": target reset: "
                   "Can't locate host! (sc=%p)\n", SCpnt);
                return FAILED;
@@ -1913,14 +2188,9 @@ mptscsih_dev_reset(struct scsi_cmnd * SCpnt)
               ioc->name, SCpnt);
        scsi_print_command(SCpnt);
 
-       if (hd->resetPending) {
-               retval = FAILED;
-               goto out;
-       }
-
        vdevice = SCpnt->device->hostdata;
        if (!vdevice || !vdevice->vtarget) {
-               retval = 0;
+               retval = SUCCESS;
                goto out;
        }
 
@@ -1931,12 +2201,12 @@ mptscsih_dev_reset(struct scsi_cmnd * SCpnt)
                goto out;
        }
 
-       retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
-           vdevice->vtarget->channel, vdevice->vtarget->id, 0, 0,
-           mptscsih_get_tm_timeout(ioc));
+       retval = mptscsih_IssueTaskMgmt(hd,
+           MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET, vdevice->vtarget->channel,
+           vdevice->vtarget->id, 0, 0, mptscsih_get_tm_timeout(ioc));
 
  out:
-       printk (MYIOC_s_INFO_FMT "target reset: %s (sc=%p)\n",
+       printk(MYIOC_s_INFO_FMT "target reset: %s (sc=%p)\n",
            ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
 
        if (retval == 0)
@@ -1961,12 +2231,12 @@ mptscsih_bus_reset(struct scsi_cmnd * SCpnt)
        MPT_SCSI_HOST   *hd;
        int              retval;
        VirtDevice       *vdevice;
-       MPT_ADAPTER     *ioc;
+       MPT_ADAPTER *ioc;
 
        /* If we can't locate our host adapter structure, return FAILED status.
         */
-       if ((hd = shost_priv(SCpnt->device->host)) == NULL){
-               printk(KERN_ERR MYNAM ": bus reset: "
+       if ((hd = shost_private(SCpnt->device->host)) == NULL){
+               printk(KERN_ERR MYNAM ": bus_reset: "
                   "Can't locate host! (sc=%p)\n", SCpnt);
                return FAILED;
        }
@@ -1976,11 +2246,13 @@ mptscsih_bus_reset(struct scsi_cmnd * SCpnt)
               ioc->name, SCpnt);
        scsi_print_command(SCpnt);
 
-       if (hd->timeouts < -1)
-               hd->timeouts++;
+       if (ioc->timeouts < -1)
+               ioc->timeouts++;
 
        vdevice = SCpnt->device->hostdata;
-       retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
+       if (!vdevice || !vdevice->vtarget)
+               return SUCCESS;
+       retval = mptscsih_IssueTaskMgmt(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
            vdevice->vtarget->channel, 0, 0, 0, mptscsih_get_tm_timeout(ioc));
 
        printk(MYIOC_s_INFO_FMT "bus reset: %s (sc=%p)\n",
@@ -2005,11 +2277,12 @@ int
 mptscsih_host_reset(struct scsi_cmnd *SCpnt)
 {
        MPT_SCSI_HOST *  hd;
-       int              retval;
-       MPT_ADAPTER     *ioc;
+       int              status = SUCCESS;
+       MPT_ADAPTER     *ioc;
+       int             retval;
 
        /*  If we can't locate the host to reset, then we failed. */
-       if ((hd = shost_priv(SCpnt->device->host)) == NULL){
+       if ((hd = shost_private(SCpnt->device->host)) == NULL){
                printk(KERN_ERR MYNAM ": host reset: "
                    "Can't locate host! (sc=%p)\n", SCpnt);
                return FAILED;
@@ -2017,237 +2290,29 @@ mptscsih_host_reset(struct scsi_cmnd *SCpnt)
 
        ioc = hd->ioc;
        printk(MYIOC_s_INFO_FMT "attempting host reset! (sc=%p)\n",
-           ioc->name, SCpnt);
+              ioc->name, SCpnt);
 
        /*  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(ioc, CAN_SLEEP) < 0) {
-               retval = FAILED;
-       } else {
-               /*  Make sure TM pending is cleared and TM state is set to
-                *  NONE.
-                */
-               retval = 0;
-               hd->tmPending = 0;
-               hd->tmState = TM_STATE_NONE;
-       }
+       if ((retval = mpt_SoftResetHandler(ioc, CAN_SLEEP)) != 0)
+               retval = mpt_HardResetHandler(ioc, CAN_SLEEP);
+
+       if (retval < 0)
+               status = FAILED;
+       else
+               status = SUCCESS;
 
        printk(MYIOC_s_INFO_FMT "host reset: %s (sc=%p)\n",
            ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
 
-       return retval;
-}
-
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/**
- *     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 = 4 * 10;  /* Wait 10 seconds */
-       int            status = FAILED;
-       MPT_ADAPTER     *ioc = hd->ioc;
-
-       do {
-               spin_lock_irqsave(&ioc->FreeQlock, flags);
-               if (hd->tmState == TM_STATE_NONE) {
-                       hd->tmState = TM_STATE_IN_PROGRESS;
-                       hd->tmPending = 1;
-                       spin_unlock_irqrestore(&ioc->FreeQlock, flags);
-                       status = SUCCESS;
-                       break;
-               }
-               spin_unlock_irqrestore(&ioc->FreeQlock, flags);
-               msleep(250);
-       } while (--loop_count);
-
-       return status;
-}
-
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/**
- *     mptscsih_tm_wait_for_completion - wait for completion of TM task
- *     @hd: Pointer to MPT host structure.
- *     @timeout: timeout value
- *
- *     Returns {SUCCESS,FAILED}.
- */
-static int
-mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout )
-{
-       unsigned long  flags;
-       int            loop_count = 4 * timeout;
-       int            status = FAILED;
-       MPT_ADAPTER     *ioc = hd->ioc;
-
-       do {
-               spin_lock_irqsave(&ioc->FreeQlock, flags);
-               if(hd->tmPending == 0) {
-                       status = SUCCESS;
-                       spin_unlock_irqrestore(&ioc->FreeQlock, flags);
-                       break;
-               }
-               spin_unlock_irqrestore(&ioc->FreeQlock, flags);
-               msleep(250);
-       } while (--loop_count);
-
        return status;
 }
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-static void
-mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code)
-{
-       char *desc;
-
-       switch (response_code) {
-       case MPI_SCSITASKMGMT_RSP_TM_COMPLETE:
-               desc = "The task completed.";
-               break;
-       case MPI_SCSITASKMGMT_RSP_INVALID_FRAME:
-               desc = "The IOC received an invalid frame status.";
-               break;
-       case MPI_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED:
-               desc = "The task type is not supported.";
-               break;
-       case MPI_SCSITASKMGMT_RSP_TM_FAILED:
-               desc = "The requested task failed.";
-               break;
-       case MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED:
-               desc = "The task completed successfully.";
-               break;
-       case MPI_SCSITASKMGMT_RSP_TM_INVALID_LUN:
-               desc = "The LUN request is invalid.";
-               break;
-       case MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC:
-               desc = "The task is in the IOC queue and has not been sent to target.";
-               break;
-       default:
-               desc = "unknown";
-               break;
-       }
-       printk(MYIOC_s_INFO_FMT "Response Code(0x%08x): F/W: %s\n",
-               ioc->name, response_code, desc);
-}
-
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
- *     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.
- **/
-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;
-       unsigned long            flags;
-       u16                      iocstatus;
-       u8                       tmType;
-       u32                      termination_count;
-
-       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt completed (mf=%p,mr=%p)\n",
-           ioc->name, mf, mr));
-       if (!ioc->sh) {
-               dtmprintk(ioc, printk(MYIOC_s_WARN_FMT
-                   "TaskMgmt Complete: NULL Scsi Host Ptr\n", ioc->name));
-               return 1;
-       }
-
-       if (mr == NULL) {
-               dtmprintk(ioc, printk(MYIOC_s_WARN_FMT
-                   "ERROR! TaskMgmt Reply: NULL Request %p\n", ioc->name, mf));
-               return 1;
-       }
-
-       hd = shost_priv(ioc->sh);
-       pScsiTmReply = (SCSITaskMgmtReply_t*)mr;
-       pScsiTmReq = (SCSITaskMgmt_t*)mf;
-       tmType = pScsiTmReq->TaskType;
-       iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK;
-       termination_count = le32_to_cpu(pScsiTmReply->TerminationCount);
-
-       if (ioc->facts.MsgVersion >= MPI_VERSION_01_05 &&
-           pScsiTmReply->ResponseCode)
-               mptscsih_taskmgmt_response_code(ioc,
-                   pScsiTmReply->ResponseCode);
-       DBG_DUMP_TM_REPLY_FRAME(ioc, (u32 *)pScsiTmReply);
-
-#ifdef CONFIG_FUSION_LOGGING
-       if ((ioc->debug_level & MPT_DEBUG_REPLY) ||
-                               (ioc->debug_level & MPT_DEBUG_TM ))
-               printk("%s: ha=%d [%d:%d:0] task_type=0x%02X "
-                       "iocstatus=0x%04X\n\tloginfo=0x%08X response_code=0x%02X "
-                       "term_cmnds=%d\n", __FUNCTION__, ioc->id, pScsiTmReply->Bus,
-                        pScsiTmReply->TargetID, pScsiTmReq->TaskType,
-                       le16_to_cpu(pScsiTmReply->IOCStatus),
-                       le32_to_cpu(pScsiTmReply->IOCLogInfo),pScsiTmReply->ResponseCode,
-                       le32_to_cpu(pScsiTmReply->TerminationCount));
-#endif
-       if (!iocstatus) {
-               dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT " TaskMgmt SUCCESS\n", ioc->name));
-                       hd->abortSCpnt = NULL;
-               goto out;
-       }
-
-       /* Error?  (anything non-zero?) */
-
-       /* clear flags and continue.
-        */
-       switch (tmType) {
-
-       case MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK:
-               if (termination_count == 1)
-                       iocstatus = MPI_IOCSTATUS_SCSI_TASK_TERMINATED;
-               hd->abortSCpnt = NULL;
-               break;
-
-       case MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS:
-
-               /* If an internal command is present
-                * or the TM failed - reload the FW.
-                * FC FW may respond FAILED to an ABORT
-                */
-               if (iocstatus == MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED ||
-                   hd->cmdPtr)
-                       if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0)
-                               printk(MYIOC_s_WARN_FMT " Firmware Reload FAILED!!\n", ioc->name);
-               break;
-
-       case MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET:
-       default:
-               break;
-       }
-
- out:
-       spin_lock_irqsave(&ioc->FreeQlock, flags);
-       hd->tmPending = 0;
-       hd->tmState = TM_STATE_NONE;
-       hd->tm_iocstatus = iocstatus;
-       spin_unlock_irqrestore(&ioc->FreeQlock, flags);
-
-       return 1;
-}
-
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*
  *     This is anyones guess quite frankly.
- */
+ **/
 int
 mptscsih_bios_param(struct scsi_device * sdev, struct block_device *bdev,
                sector_t capacity, int geom[])
@@ -2284,26 +2349,68 @@ mptscsih_bios_param(struct scsi_device * sdev, struct block_device *bdev,
        return 0;
 }
 
-/* Search IOC page 3 to determine if this is hidden physical disk
+/**
+ * Search IOC page 3 to determine if this is hidden physical disk
  *
- */
+ **/
 int
 mptscsih_is_phys_disk(MPT_ADAPTER *ioc, u8 channel, u8 id)
 {
        struct inactive_raid_component_info *component_info;
-       int i;
+       u8 i, j;
+       RaidPhysDiskPage1_t *phys_disk;
        int rc = 0;
+       int num_paths;
 
        if (!ioc->raid_data.pIocPg3)
                goto out;
        for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
                if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) &&
-                   (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) {
+                   (channel ==
+                    ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) {
                        rc = 1;
                        goto out;
                }
        }
 
+       if (ioc->bus_type != SAS)
+               goto out;
+
+       /*
+        * Check if dual path
+        */
+       for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
+               num_paths = mpt_raid_phys_disk_get_num_paths(ioc,
+                   ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum);
+               if (num_paths < 2)
+                       continue;
+               phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t,Path) +
+                  (num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL);
+               if (!phys_disk)
+                       continue;
+               if ((mpt_raid_phys_disk_pg1(ioc,
+                   ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum,
+                   phys_disk))) {
+                       kfree(phys_disk);
+                       continue;
+               }
+               for (j = 0; j < num_paths; j++) {
+                       if ((phys_disk->Path[j].Flags &
+                           MPI_RAID_PHYSDISK1_FLAG_INVALID))
+                               continue;
+                       if ((phys_disk->Path[j].Flags &
+                           MPI_RAID_PHYSDISK1_FLAG_BROKEN))
+                               continue;
+                       if ((id == phys_disk->Path[j].PhysDiskID) &&
+                           (channel == phys_disk->Path[j].PhysDiskBus)) {
+                               rc = 1;
+                               kfree(phys_disk);
+                               goto out;
+                       }
+               }
+               kfree(phys_disk);
+       }
+
        /*
         * Check inactive list for matching phys disks
         */
@@ -2328,19 +2435,60 @@ u8
 mptscsih_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id)
 {
        struct inactive_raid_component_info *component_info;
-       int i;
+       int i,j;
+       RaidPhysDiskPage1_t *phys_disk;
        int rc = -ENXIO;
+       u8 num_paths;
 
        if (!ioc->raid_data.pIocPg3)
                goto out;
        for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
                if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) &&
-                   (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) {
+                   (channel ==
+                    ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) {
                        rc = ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum;
                        goto out;
                }
        }
 
+       if (ioc->bus_type != SAS)
+               goto out;
+
+       /*
+        * Check if dual path
+        */
+       for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
+               num_paths = mpt_raid_phys_disk_get_num_paths(ioc,
+                   ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum);
+               if (num_paths < 2)
+                       continue;
+               phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t,Path) +
+                  (num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL);
+               if (!phys_disk)
+                       continue;
+               if ((mpt_raid_phys_disk_pg1(ioc,
+                   ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum,
+                   phys_disk))) {
+                       kfree(phys_disk);
+                       continue;
+               }
+               for (j = 0; j < num_paths; j++) {
+                       if ((phys_disk->Path[j].Flags &
+                           MPI_RAID_PHYSDISK1_FLAG_INVALID))
+                               continue;
+                       if ((phys_disk->Path[j].Flags &
+                           MPI_RAID_PHYSDISK1_FLAG_BROKEN))
+                               continue;
+                       if ((id == phys_disk->Path[j].PhysDiskID) &&
+                           (channel == phys_disk->Path[j].PhysDiskBus)) {
+                               rc = phys_disk->PhysDiskNum;
+                               kfree(phys_disk);
+                               goto out;
+                       }
+               }
+               kfree(phys_disk);
+       }
+
        /*
         * Check inactive list for matching phys disks
         */
@@ -2361,42 +2509,44 @@ mptscsih_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id)
 }
 EXPORT_SYMBOL(mptscsih_raid_id_to_num);
 
-/*
+/**
  *     OS entry point to allow for host driver to free allocated memory
  *     Called if no device present or device being unloaded
- */
+ **/
 void
 mptscsih_slave_destroy(struct scsi_device *sdev)
 {
        struct Scsi_Host        *host = sdev->host;
-       MPT_SCSI_HOST           *hd = shost_priv(host);
+       MPT_SCSI_HOST           *hd = shost_private(host);
        VirtTarget              *vtarget;
        VirtDevice              *vdevice;
        struct scsi_target      *starget;
 
        starget = scsi_target(sdev);
        vtarget = starget->hostdata;
+       vtarget->num_luns--;
        vdevice = sdev->hostdata;
+       if (!vdevice)
+               return;
 
        mptscsih_search_running_cmds(hd, vdevice);
-       vtarget->num_luns--;
-       mptscsih_synchronize_cache(hd, vdevice);
+       mptscsih_synchronize_cache(sdev, hd, vdevice);
        kfree(vdevice);
        sdev->hostdata = NULL;
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*
+/**
  *     mptscsih_change_queue_depth - This function will set a devices queue depth
  *     @sdev: per scsi_device pointer
  *     @qdepth: requested queue depth
  *
  *     Adding support for new 'change_queue_depth' api.
-*/
+ **/
 int
 mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
 {
-       MPT_SCSI_HOST           *hd = shost_priv(sdev->host);
+       MPT_SCSI_HOST           *hd = shost_private(sdev->host);
        VirtTarget              *vtarget;
        struct scsi_target      *starget;
        int                     max_depth;
@@ -2407,15 +2557,16 @@ mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
        vtarget = starget->hostdata;
 
        if (ioc->bus_type == SPI) {
-               if (!(vtarget->tflags & MPT_TARGET_FLAGS_Q_YES))
-                       max_depth = 1;
-               else if (sdev->type == TYPE_DISK &&
-                        vtarget->minSyncFactor <= MPT_ULTRA160)
+               if (sdev->type == TYPE_DISK &&
+                   vtarget->minSyncFactor <= MPT_ULTRA160)
                        max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
                else
                        max_depth = MPT_SCSI_CMD_PER_DEV_LOW;
        } else
-               max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
+               max_depth = ioc->sh->can_queue;
+
+       if (!sdev->tagged_supported)
+               max_depth = 1;
 
        if (qdepth > max_depth)
                qdepth = max_depth;
@@ -2425,15 +2576,24 @@ mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
                tagged = MSG_SIMPLE_TAG;
 
        scsi_adjust_queue_depth(sdev, tagged, qdepth);
+
+       if (sdev->inquiry_len > 7)
+               sdev_printk(KERN_INFO, sdev, MYIOC_s_FMT "qdepth=%d, "
+                   "tagged=%d, simple=%d, ordered=%d, scsi_level=%d, "
+                   "cmd_que=%d\n", ioc->name, sdev->queue_depth,
+                   sdev->tagged_supported, sdev->simple_tags,
+                   sdev->ordered_tags, sdev->scsi_level,
+                   (sdev->inquiry[7] & 2) >> 1);
+
        return sdev->queue_depth;
 }
 
-/*
+/**
  *     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.
  *     Return non-zero if fails.
- */
+ **/
 int
 mptscsih_slave_configure(struct scsi_device *sdev)
 {
@@ -2441,61 +2601,38 @@ mptscsih_slave_configure(struct scsi_device *sdev)
        VirtTarget              *vtarget;
        VirtDevice              *vdevice;
        struct scsi_target      *starget;
-       MPT_SCSI_HOST           *hd = shost_priv(sh);
-       MPT_ADAPTER             *ioc = hd->ioc;
+       MPT_SCSI_HOST           *hd = shost_private(sh);
+       MPT_ADAPTER             *ioc = hd->ioc;
 
        starget = scsi_target(sdev);
        vtarget = starget->hostdata;
        vdevice = sdev->hostdata;
+       vdevice->configured_lun = 1;
 
-       dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
-               "device @ %p, channel=%d, id=%d, lun=%d\n",
-               ioc->name, sdev, sdev->channel, sdev->id, sdev->lun));
-       if (ioc->bus_type == SPI)
-               dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
-                   "sdtr %d wdtr %d ppr %d inq length=%d\n",
-                   ioc->name, sdev->sdtr, sdev->wdtr,
-                   sdev->ppr, sdev->inquiry_len));
-
-       if (sdev->id > sh->max_id) {
+       if ((ioc->bus_type != SAS) && (sdev->id > sh->max_id)) {
                /* error case, should never happen */
                scsi_adjust_queue_depth(sdev, 0, 1);
                goto slave_configure_exit;
        }
 
-       vdevice->configured_lun = 1;
-       mptscsih_change_queue_depth(sdev, MPT_SCSI_CMD_PER_DEV_HIGH);
-
-       dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
-               "Queue depth=%d, tflags=%x\n",
-               ioc->name, sdev->queue_depth, vtarget->tflags));
-
-       if (ioc->bus_type == SPI)
-               dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
-                   "negoFlags=%x, maxOffset=%x, SyncFactor=%x\n",
-                   ioc->name, vtarget->negoFlags, vtarget->maxOffset,
-                   vtarget->minSyncFactor));
+       mptscsih_change_queue_depth(sdev, ioc->sdev_queue_depth);
 
 slave_configure_exit:
 
-       dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
-               "tagged %d, simple %d, ordered %d\n",
-               ioc->name,sdev->tagged_supported, sdev->simple_tags,
-               sdev->ordered_tags));
-
        return 0;
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*
+/**
  *  Private routines...
  */
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/* Utility function to copy sense data from the scsi_cmnd buffer
+/**
+ * Utility function to copy sense data from the scsi_cmnd buffer
  * to the FC and SCSI target structures.
  *
- */
+ **/
 static void
 mptscsih_copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply)
 {
@@ -2535,18 +2672,16 @@ mptscsih_copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR
                                ioc->events[idx].data[1] = (sense_data[13] << 8) | sense_data[12];
 
                                ioc->eventContext++;
-                               if (ioc->pcidev->vendor ==
-                                   PCI_VENDOR_ID_IBM) {
-                                       mptscsih_issue_sep_command(ioc,
-                                           vdevice->vtarget, MPI_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT);
-                                       vdevice->vtarget->tflags |=
-                                           MPT_TARGET_FLAGS_LED_ON;
+                               if (ioc->pcidev->vendor == PCI_VENDOR_ID_IBM) {
+                                       mptscsih_issue_sep_command(ioc, vdevice->vtarget,
+                                           MPI_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT);
+                                       vdevice->vtarget->tflags |= MPT_TARGET_FLAGS_LED_ON;
                                }
                        }
                }
        } else {
                dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Hmmm... SenseData len=0! (?)\n",
-                               ioc->name));
+                   ioc->name));
        }
 }
 
@@ -2561,7 +2696,7 @@ mptscsih_copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR
  * Returns the scsi_cmd pointer
  *
  **/
-static struct scsi_cmnd *
+struct scsi_cmnd *
 mptscsih_get_scsi_lookup(MPT_ADAPTER *ioc, int i)
 {
        unsigned long   flags;
@@ -2620,10 +2755,14 @@ mptscsih_set_scsi_lookup(MPT_ADAPTER *ioc, int i, struct scsi_cmnd *scmd)
 }
 
 /**
- * SCPNT_TO_LOOKUP_IDX - searches for a given scmd in the ScsiLookup[] array list
+ * SCPNT_TO_LOOKUP_IDX
+ *
+ * search's for a given scmd in the ScsiLookup[] array list
+ *
  * @ioc: Pointer to MPT_ADAPTER structure
- * @sc: scsi_cmnd pointer
- */
+ * @scmd: scsi_cmnd pointer
+ *
+ **/
 static int
 SCPNT_TO_LOOKUP_IDX(MPT_ADAPTER *ioc, struct scsi_cmnd *sc)
 {
@@ -2645,379 +2784,225 @@ SCPNT_TO_LOOKUP_IDX(MPT_ADAPTER *ioc, struct scsi_cmnd *sc)
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 int
-mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
+mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
 {
-       MPT_SCSI_HOST   *hd;
-       unsigned long    flags;
-
-       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
-           ": IOC %s_reset routed to SCSI host driver!\n",
-           ioc->name, reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
-           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 || shost_priv(ioc->sh) == NULL)
-               return 0;
-       else
-               hd = shost_priv(ioc->sh);
-
-       if (reset_phase == MPT_IOC_SETUP_RESET) {
-               dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Setup-Diag Reset\n", ioc->name));
-
-               /* Clean Up:
-                * 1. Set Hard Reset Pending Flag
-                * All new commands go to doneQ
-                */
-               hd->resetPending = 1;
-
-       } else if (reset_phase == MPT_IOC_PRE_RESET) {
-               dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Pre-Diag Reset\n", ioc->name));
-
-               /* 2. Flush running commands
-                *      Clean ScsiLookup (and associated memory)
-                *      AND clean mytaskQ
-                */
-
-               /* 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(ioc, hd->cmdPtr);
-               }
-
-               dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Pre-Reset complete.\n", ioc->name));
+       u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
 
-       } else {
-               dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Post-Diag Reset\n", ioc->name));
+       devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+           "MPT event (=%02Xh) routed to SCSI host driver!\n",
+           ioc->name, event));
 
-               /* Once a FW reload begins, all new OS commands are
-                * redirected to the doneQ w/ a reset status.
-                * Init all control structures.
-                */
+       if ((event == MPI_EVENT_IOC_BUS_RESET ||
+           event == MPI_EVENT_EXT_BUS_RESET) &&
+           (ioc->bus_type == SPI) && (ioc->soft_resets < -1))
+                       ioc->soft_resets++;
 
-               /* 2. Chain Buffer initialization
-                */
+       return 1;               /* currently means nothing really */
+}
 
-               /* 4. Renegotiate to all devices, if SPI
-                */
+int
+mptscsih_quiesce_raid(MPT_SCSI_HOST *hd, int quiesce, u8 channel, u8 id)
+{
+       MPT_ADAPTER             *ioc = hd->ioc;
+       MpiRaidActionRequest_t  *pReq;
+       MPT_FRAME_HDR           *mf;
+       int                     ret;
+       unsigned long           timeleft;
 
-               /* 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->tmState = TM_STATE_NONE;
+       mutex_lock(&ioc->internal_cmds.mutex);
 
-               /* 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;
-                       hd->scandv_wait_done = 1;
-                       wake_up(&hd->scandv_waitq);
-                       hd->cmdPtr = NULL;
+       /* Get and Populate a free Frame
+        */
+       if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
+               dfailprintk(hd->ioc, printk(MYIOC_s_WARN_FMT "%s: no msg frames!\n",
+                       ioc->name, __FUNCTION__));
+               ret = -EAGAIN;
+               goto out;
+       }
+       pReq = (MpiRaidActionRequest_t *)mf;
+       if (quiesce)
+               pReq->Action = MPI_RAID_ACTION_QUIESCE_PHYS_IO;
+       else
+               pReq->Action = MPI_RAID_ACTION_ENABLE_PHYS_IO;
+       pReq->Reserved1 = 0;
+       pReq->ChainOffset = 0;
+       pReq->Function = MPI_FUNCTION_RAID_ACTION;
+       pReq->VolumeID = id;
+       pReq->VolumeBus = channel;
+       pReq->PhysDiskNum = 0;
+       pReq->MsgFlags = 0;
+       pReq->Reserved2 = 0;
+       pReq->ActionDataWord = 0; /* Reserved for this action */
+
+       ioc->add_sge((char *)&pReq->ActionDataSGE,
+               MPT_SGE_FLAGS_SSIMPLE_READ | 0, (dma_addr_t) -1);
+
+       ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RAID Volume action=%x channel=%d id=%d\n",
+                       ioc->name, pReq->Action, channel, id));
+
+       INITIALIZE_MGMT_STATUS(ioc->internal_cmds.status)
+       mpt_put_msg_frame(ioc->InternalCtx, ioc, mf);
+       timeleft = wait_for_completion_timeout(&ioc->internal_cmds.done, 10*HZ);
+       if (!(ioc->internal_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
+               ret = -ETIME;
+               dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: TIMED OUT!\n",
+                   ioc->name, __FUNCTION__));
+               if (ioc->internal_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
+                       goto out;
+               if (!timeleft) {
+                       printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
+                           ioc->name, __FUNCTION__);
+                       if (mpt_SoftResetHandler(ioc, CAN_SLEEP) != 0)
+                               mpt_HardResetHandler(ioc, CAN_SLEEP);
+                       mpt_free_msg_frame(ioc, mf);
                }
-
-               dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Post-Reset complete.\n", ioc->name));
-
+               goto out;
        }
 
-       return 1;               /* currently means nothing really */
+       ret = ioc->internal_cmds.completion_code;
+
+ out:
+       CLEAR_MGMT_STATUS(ioc->internal_cmds.status)
+       mutex_unlock(&ioc->internal_cmds.mutex);
+       return ret;
 }
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-int
-mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
+/**
+ *     mptscsih_get_completion_code -
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @reply:
+ *     @cmd:
+ *
+ **/
+static int
+mptscsih_get_completion_code(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply)
 {
-       MPT_SCSI_HOST *hd;
-       u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
+       SCSIIOReply_t   *pReply;
+       MpiRaidActionReply_t *pr;
+       u8               scsi_status;
+       u16              status;
+       int              completion_code;
 
-       devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n",
-                       ioc->name, event));
+       pReply = (SCSIIOReply_t *)reply;
+       status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
+       scsi_status = pReply->SCSIStatus;
 
-       if (ioc->sh == NULL ||
-               ((hd = shost_priv(ioc->sh)) == NULL))
-               return 1;
+       devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+           "IOCStatus=%04xh, SCSIState=%02xh, SCSIStatus=%02xh, IOCLogInfo=%08xh\n",
+            ioc->name, status, pReply->SCSIState, scsi_status, le32_to_cpu(pReply->IOCLogInfo)));
 
-       switch (event) {
-       case MPI_EVENT_UNIT_ATTENTION:                  /* 03 */
-               /* FIXME! */
-               break;
-       case MPI_EVENT_IOC_BUS_RESET:                   /* 04 */
-       case MPI_EVENT_EXT_BUS_RESET:                   /* 05 */
-               if (hd && (ioc->bus_type == SPI) && (hd->soft_resets < -1))
-                       hd->soft_resets++;
-               break;
-       case MPI_EVENT_LOGOUT:                          /* 09 */
-               /* FIXME! */
+       switch(status) {
+
+       case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE:       /* 0x0043 */
+               completion_code = MPT_SCANDV_SELECTION_TIMEOUT;
                break;
 
-       case MPI_EVENT_RESCAN:                          /* 06 */
+       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 */
+               completion_code = MPT_SCANDV_DID_RESET;
                break;
 
-               /*
-                *  CHECKME! Don't think we need to do
-                *  anything for these, but...
-                */
-       case MPI_EVENT_LINK_STATUS_CHANGE:              /* 07 */
-       case MPI_EVENT_LOOP_STATE_CHANGE:               /* 08 */
-               /*
-                *  CHECKME!  Falling thru...
-                */
+       case MPI_IOCSTATUS_BUSY:
+       case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES:
+               completion_code = MPT_SCANDV_BUSY;
                break;
 
-       case MPI_EVENT_INTEGRATED_RAID:                 /* 0B */
+       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) {
+                       completion_code = MPT_SCANDV_GOOD;
+               } else if (pReply->Function == MPI_FUNCTION_RAID_ACTION) {
+                       pr = (MpiRaidActionReply_t *)reply;
+                       if (le16_to_cpu(pr->ActionStatus) == MPI_RAID_ACTION_ASTATUS_SUCCESS)
+                               completion_code = MPT_SCANDV_GOOD;
+                       else
+                               completion_code = MPT_SCANDV_SOME_ERROR;
+               } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID)
+                       completion_code = MPT_SCANDV_SENSE;
+               else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) {
+                       if (req->u.scsireq.CDB[0] == INQUIRY)
+                               completion_code = MPT_SCANDV_ISSUE_SENSE;
+                       else
+                               completion_code = MPT_SCANDV_DID_RESET;
+               }
+               else if (pReply->SCSIState & MPI_SCSI_STATE_NO_SCSI_STATUS)
+                       completion_code = MPT_SCANDV_DID_RESET;
+               else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
+                       completion_code = MPT_SCANDV_DID_RESET;
+               else if (scsi_status == MPI_SCSI_STATUS_BUSY)
+                       completion_code = MPT_SCANDV_BUSY;
+               else
+                       completion_code = MPT_SCANDV_GOOD;
                break;
 
-       case MPI_EVENT_NONE:                            /* 00 */
-       case MPI_EVENT_LOG_DATA:                        /* 01 */
-       case MPI_EVENT_STATE_CHANGE:                    /* 02 */
-       case MPI_EVENT_EVENT_CHANGE:                    /* 0A */
+       case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR:         /* 0x0047 */
+               if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
+                       completion_code = MPT_SCANDV_DID_RESET;
+               else
+                       completion_code = MPT_SCANDV_SOME_ERROR;
+               break;
        default:
-               dprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": Ignoring event (=%02Xh)\n",
-                   ioc->name, event));
+               completion_code = MPT_SCANDV_SOME_ERROR;
                break;
-       }
 
-       return 1;               /* currently means nothing really */
-}
+       }       /* switch(status) */
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*
- *  Bus Scan and Domain Validation functionality ...
- */
+       devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+           "  completionCode set to %08xh\n", ioc->name, completion_code));
+       return completion_code;
+}
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*
- *     mptscsih_scandv_complete - Scan and DV callback routine registered
- *     to Fustion MPT (base) driver.
- *
+/**
+ *     mptscsih_scandv_complete -
  *     @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.
+ *     @req:
+ *     @reply:
  *
- *     Remark: Sets a completion code and (possibly) saves sense data
- *     in the IOC member localReply structure.
- *     Used ONLY for DV and other internal commands.
- */
+ **/
 int
-mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
+mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply)
 {
-       MPT_SCSI_HOST   *hd;
        SCSIIORequest_t *pReq;
-       int              completionCode;
+       SCSIIOReply_t   *pReply;
+       u8               cmd;
        u16              req_idx;
+       u8              *sense_data;
+       int              sz;
 
-       hd = shost_priv(ioc->sh);
-
-       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;
-       }
-
-       del_timer(&hd->timer);
-       req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
-       mptscsih_set_scsi_lookup(ioc, req_idx, NULL);
-       pReq = (SCSIIORequest_t *) mf;
+       ioc->internal_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
+       ioc->internal_cmds.completion_code = MPT_SCANDV_GOOD;
+       if (!reply)
+               goto out;
 
-       if (mf != hd->cmdPtr) {
-               printk(MYIOC_s_WARN_FMT "ScanDvComplete (mf=%p, cmdPtr=%p, idx=%d)\n",
-                               ioc->name, (void *)mf, (void *) hd->cmdPtr, req_idx);
+       pReply = (SCSIIOReply_t *) reply;
+       pReq = (SCSIIORequest_t *) req;
+       ioc->internal_cmds.completion_code =
+           mptscsih_get_completion_code(ioc, req, reply);
+       ioc->internal_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
+       memcpy(ioc->internal_cmds.reply, reply,
+           min(MPT_DEFAULT_FRAME_SIZE, 4 * reply->u.reply.MsgLength));
+       cmd = reply->u.hdr.Function;
+       if (((cmd == MPI_FUNCTION_SCSI_IO_REQUEST) ||
+           (cmd == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) &&
+           (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID)) {
+               req_idx = le16_to_cpu(req->u.frame.hwhdr.msgctxu.fld.req_idx);
+               sense_data = ((u8 *)ioc->sense_buf_pool +
+                   (req_idx * MPT_SENSE_BUFFER_ALLOC));
+               sz = min_t(int, pReq->SenseBufferLength,
+                   MPT_SENSE_BUFFER_ALLOC);
+               memcpy(ioc->internal_cmds.sense, sense_data, sz);
        }
-       hd->cmdPtr = NULL;
-
-       ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScanDvComplete (mf=%p,mr=%p,idx=%d)\n",
-                       ioc->name, mf, mr, req_idx));
-
-       hd->pLocal = &hd->localReply;
-       hd->pLocal->scsiStatus = 0;
-
-       /* If target struct exists, clear sense valid flag.
-        */
-       if (mr == NULL) {
-               completionCode = MPT_SCANDV_GOOD;
-       } else {
-               SCSIIOReply_t   *pReply;
-               u16              status;
-               u8               scsi_status;
-
-               pReply = (SCSIIOReply_t *) mr;
-
-               status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
-               scsi_status = pReply->SCSIStatus;
-
-
-               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 (le16_to_cpu(pr->ActionStatus) == MPI_RAID_ACTION_ASTATUS_SUCCESS)
-                                       completionCode = MPT_SCANDV_GOOD;
-                               else
-                                       completionCode = MPT_SCANDV_SOME_ERROR;
-                               memcpy(hd->pLocal->sense, pr, sizeof(hd->pLocal->sense));
-
-                       } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
-                               u8              *sense_data;
-                               int              sz;
-
-                               /* save sense data in global structure
-                                */
-                               completionCode = MPT_SCANDV_SENSE;
-                               hd->pLocal->scsiStatus = scsi_status;
-                               sense_data = ((u8 *)ioc->sense_buf_pool +
-                                       (req_idx * MPT_SENSE_BUFFER_ALLOC));
-
-                               sz = min_t(int, pReq->SenseBufferLength,
-                                                       SCSI_STD_SENSE_BYTES);
-                               memcpy(hd->pLocal->sense, sense_data, sz);
-
-                               ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "  Check Condition, sense ptr %p\n",
-                                   ioc->name, sense_data));
-                       } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) {
-                               if (pReq->CDB[0] == INQUIRY)
-                                       completionCode = MPT_SCANDV_ISSUE_SENSE;
-                               else
-                                       completionCode = MPT_SCANDV_DID_RESET;
-                       }
-                       else if (pReply->SCSIState & 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 {
-                               completionCode = MPT_SCANDV_GOOD;
-                               hd->pLocal->scsiStatus = scsi_status;
-                       }
-                       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) */
-
-       } /* 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(ioc, req_idx);
-
-       /*
-        * Wake up the original calling thread
-        */
-       hd->scandv_wait_done = 1;
-       wake_up(&hd->scandv_waitq);
-
+ out:
+       if (!(ioc->internal_cmds.status & MPT_MGMT_STATUS_PENDING))
+               return 0;
+       ioc->internal_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
+       complete(&ioc->internal_cmds.done);
        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
- *
- */
-void
-mptscsih_timer_expired(unsigned long data)
-{
-       MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *) data;
-       MPT_ADAPTER     *ioc = hd->ioc;
-
-       ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Timer Expired! Cmd %p\n", 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.
-                        */
-               } else {
-                       /* Perform a FW reload */
-                       if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0) {
-                               printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", ioc->name);
-                       }
-               }
-       } else {
-               /* This should NEVER happen */
-               printk(MYIOC_s_WARN_FMT "Null cmdPtr!!!!\n", 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(ioc, printk(MYIOC_s_DEBUG_FMT "Timer Expired Complete!\n", ioc->name));
-
-       return;
-}
-
-
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *     mptscsih_do_cmd - Do internal command.
@@ -3037,28 +3022,33 @@ mptscsih_timer_expired(unsigned long data)
  *                0 if good
  *
  *              > 0 if command complete but some type of completion error.
- */
-static int
+ **/
+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;
+       int              timeout;
        char             cmdLen;
        char             CDB[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
-       char             cmd = io->cmd;
-       MPT_ADAPTER     *ioc = hd->ioc;
+       u8               cmd = io->cmd;
+       MPT_ADAPTER *ioc = hd->ioc;
+       int              ret = 0;
+       unsigned long    timeleft;
+       unsigned long    flags;
 
-       in_isr = in_interrupt();
-       if (in_isr) {
-               dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Internal SCSI IO request not allowed in ISR context!\n",
-                                       ioc->name));
-               return -EPERM;
+       /* don't send internal command during diag reset */
+       spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
+       if (ioc->ioc_reset_in_progress) {
+               spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
+               dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "%s: busy with host reset\n", ioc->name, __FUNCTION__));
+               return MPT_SCANDV_BUSY;
        }
+       spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
 
+       mutex_lock(&ioc->internal_cmds.mutex);
 
        /* Set command specific information
         */
@@ -3068,13 +3058,13 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
                dir = MPI_SCSIIO_CONTROL_READ;
                CDB[0] = cmd;
                CDB[4] = io->size;
-               cmdTimeout = 10;
+               timeout = 10;
                break;
 
        case TEST_UNIT_READY:
                cmdLen = 6;
                dir = MPI_SCSIIO_CONTROL_READ;
-               cmdTimeout = 10;
+               timeout = 10;
                break;
 
        case START_STOP:
@@ -3082,7 +3072,7 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
                dir = MPI_SCSIIO_CONTROL_READ;
                CDB[0] = cmd;
                CDB[4] = 1;     /*Spin up the disk */
-               cmdTimeout = 15;
+               timeout = 15;
                break;
 
        case REQUEST_SENSE:
@@ -3090,7 +3080,7 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
                CDB[0] = cmd;
                CDB[4] = io->size;
                dir = MPI_SCSIIO_CONTROL_READ;
-               cmdTimeout = 10;
+               timeout = 10;
                break;
 
        case READ_BUFFER:
@@ -3109,7 +3099,7 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
                CDB[6] = (io->size >> 16) & 0xFF;
                CDB[7] = (io->size >>  8) & 0xFF;
                CDB[8] = io->size & 0xFF;
-               cmdTimeout = 10;
+               timeout = 10;
                break;
 
        case WRITE_BUFFER:
@@ -3124,21 +3114,21 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
                CDB[6] = (io->size >> 16) & 0xFF;
                CDB[7] = (io->size >>  8) & 0xFF;
                CDB[8] = io->size & 0xFF;
-               cmdTimeout = 10;
+               timeout = 10;
                break;
 
        case RESERVE:
                cmdLen = 6;
                dir = MPI_SCSIIO_CONTROL_READ;
                CDB[0] = cmd;
-               cmdTimeout = 10;
+               timeout = 10;
                break;
 
        case RELEASE:
                cmdLen = 6;
                dir = MPI_SCSIIO_CONTROL_READ;
                CDB[0] = cmd;
-               cmdTimeout = 10;
+               timeout = 10;
                break;
 
        case SYNCHRONIZE_CACHE:
@@ -3146,20 +3136,42 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
                dir = MPI_SCSIIO_CONTROL_READ;
                CDB[0] = cmd;
 //             CDB[1] = 0x02;  /* set immediate bit */
-               cmdTimeout = 10;
+               timeout = 10;
+               break;
+
+       case REPORT_LUNS:
+               cmdLen = 12;
+               dir = MPI_SCSIIO_CONTROL_READ;
+               CDB[0] = cmd;
+               CDB[6] = (io->size >> 24) & 0xFF;
+               CDB[7] = (io->size >> 16) & 0xFF;
+               CDB[8] = (io->size >>  8) & 0xFF;
+               CDB[9] = io->size & 0xFF;
+               timeout = 10;
+               break;
+
+       case TRANSPORT_LAYER_RETRIES:
+               CDB[0] = cmd;
+               CDB[1] = 0x01;
+               cmdLen = 6;
+               dir = MPI_SCSIIO_CONTROL_READ;
+               timeout = 10;
                break;
 
        default:
                /* Error Case */
-               return -EFAULT;
+               ret = -EFAULT;
+               goto out;
        }
 
        /* Get and Populate a free Frame
+        * MsgContext set in mpt_get_msg_frame call
         */
        if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
-               dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "No msg frames!\n",
-                   ioc->name));
-               return -EBUSY;
+               dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: No msg frames!\n",
+                   ioc->name, __FUNCTION__));
+               ret = MPT_SCANDV_BUSY;
+               goto out;
        }
 
        pScsiReq = (SCSIIORequest_t *) mf;
@@ -3182,14 +3194,10 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
 
        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  */
 
        int_to_scsilun(io->lun, (struct scsi_lun *)pScsiReq->LUN);
-
        if (io->flags & MPT_ICFLAG_TAGGED_CMD)
                pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_SIMPLEQ);
        else
@@ -3197,74 +3205,61 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
 
        if (cmd == REQUEST_SENSE) {
                pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
-               ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Untagged! 0x%2x\n",
-                       ioc->name, cmd));
+               devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "%s: Untagged! 0x%02x\n", ioc->name, __FUNCTION__, cmd));
        }
 
-       for (ii=0; ii < 16; ii++)
-               pScsiReq->CDB[ii] = CDB[ii];
+       for (ii = 0; ii < 16; ii++)
+           pScsiReq->CDB[ii] = CDB[ii];
 
        pScsiReq->DataLength = cpu_to_le32(io->size);
        pScsiReq->SenseBufferLowAddr = cpu_to_le32(ioc->sense_buf_low_dma
                                           + (my_idx * MPT_SENSE_BUFFER_ALLOC));
 
-       ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Command 0x%x for (%d:%d:%d)\n",
-                       ioc->name, cmd, io->channel, io->id, io->lun));
+       devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+           "%s: Sending Command 0x%02x for fw_channel=%d fw_id=%d lun=%d\n",
+           ioc->name, __FUNCTION__, cmd, io->channel, io->id, io->lun));
 
-       if (dir == MPI_SCSIIO_CONTROL_READ) {
+       if (dir == MPI_SCSIIO_CONTROL_READ)
                ioc->add_sge((char *) &pScsiReq->SGL,
-                       MPT_SGE_FLAGS_SSIMPLE_READ | io->size,
-                       io->data_dma);
-       } else {
+                   MPT_SGE_FLAGS_SSIMPLE_READ | io->size, io->data_dma);
+       else
                ioc->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;
-       hd->scandv_wait_done = 0;
-
-       /* Save cmd pointer, for resource free if timeout or
-        * FW reload occurs
-        */
-       hd->cmdPtr = mf;
+                   MPT_SGE_FLAGS_SSIMPLE_WRITE | io->size, io->data_dma);
 
-       add_timer(&hd->timer);
+       INITIALIZE_MGMT_STATUS(ioc->internal_cmds.status)
        mpt_put_msg_frame(ioc->InternalCtx, ioc, mf);
-       wait_event(hd->scandv_waitq, hd->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(ioc, printk(MYIOC_s_DEBUG_FMT "_do_cmd: Null pLocal!!!\n",
-                               ioc->name));
+       timeleft = wait_for_completion_timeout(&ioc->internal_cmds.done,
+           timeout*HZ);
+       if (!(ioc->internal_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
+               ret = -ETIME;
+               dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "%s: TIMED OUT for cmd=0x%02x\n", ioc->name, __FUNCTION__,
+                   cmd));
+               if (ioc->internal_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) {
+                       mpt_free_msg_frame(ioc, mf);
+                       goto out;
+               }
+               if (!timeleft) {
+                       if (!mptscsih_scandv_bus_reset(ioc))
+                               goto out;
+                       printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
+                           ioc->name, __FUNCTION__);
+                       if (mpt_SoftResetHandler(ioc, CAN_SLEEP) != 0)
+                               mpt_HardResetHandler(ioc, CAN_SLEEP);
+                       mpt_free_msg_frame(ioc, mf);
+               }
+               goto out;
        }
 
-       return rc;
+       ret = ioc->internal_cmds.completion_code;
+       devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: success, rc=0x%02x\n",
+                       ioc->name, __FUNCTION__, ret));
+
+ out:
+       CLEAR_MGMT_STATUS(ioc->internal_cmds.status)
+       mutex_unlock(&ioc->internal_cmds.mutex);
+       return ret;
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -3278,9 +3273,10 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
  *
  */
 static void
-mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
+mptscsih_synchronize_cache(struct scsi_device *sdev, MPT_SCSI_HOST *hd, VirtDevice *vdevice)
 {
        INTERNAL_CMD             iocmd;
+       MPT_ADAPTER *ioc = hd->ioc;
 
        /* Ignore hidden raid components, this is handled when the command
         * is sent to the volume
@@ -3292,28 +3288,28 @@ mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
            !vdevice->configured_lun)
                return;
 
-       /* Following parameters will not change
-        * in this routine.
-        */
+       memset(&iocmd, 0, sizeof(INTERNAL_CMD));
        iocmd.cmd = SYNCHRONIZE_CACHE;
-       iocmd.flags = 0;
        iocmd.physDiskNum = -1;
        iocmd.data = NULL;
        iocmd.data_dma = -1;
-       iocmd.size = 0;
-       iocmd.rsvd = iocmd.rsvd2 = 0;
        iocmd.channel = vdevice->vtarget->channel;
        iocmd.id = vdevice->vtarget->id;
        iocmd.lun = vdevice->lun;
 
+       sdev_printk(KERN_INFO, sdev, MYIOC_s_FMT "SYNCHRONIZE_CACHE: fw_channel %d,"
+           " fw_id %d\n", ioc->name, vdevice->vtarget->channel, vdevice->vtarget->id);
        mptscsih_do_cmd(hd, &iocmd);
 }
 
+/*
+ * shost attributes
+ */
 static ssize_t
 mptscsih_version_fw_show(struct class_device *cdev, char *buf)
 {
        struct Scsi_Host *host = class_to_shost(cdev);
-       MPT_SCSI_HOST   *hd = shost_priv(host);
+       MPT_SCSI_HOST   *hd = shost_private(host);
        MPT_ADAPTER *ioc = hd->ioc;
 
        return snprintf(buf, PAGE_SIZE, "%02d.%02d.%02d.%02d\n",
@@ -3328,10 +3324,10 @@ static ssize_t
 mptscsih_version_bios_show(struct class_device *cdev, char *buf)
 {
        struct Scsi_Host *host = class_to_shost(cdev);
-       MPT_SCSI_HOST   *hd = shost_priv(host);
+       MPT_SCSI_HOST   *hd = shost_private(host);
        MPT_ADAPTER *ioc = hd->ioc;
 
-       return snprintf(buf, PAGE_SIZE, "%02x.%02x.%02x.%02x\n",
+       return snprintf(buf, PAGE_SIZE, "%02d.%02d.%02d.%02d\n",
            (ioc->biosVersion & 0xFF000000) >> 24,
            (ioc->biosVersion & 0x00FF0000) >> 16,
            (ioc->biosVersion & 0x0000FF00) >> 8,
@@ -3343,10 +3339,15 @@ static ssize_t
 mptscsih_version_mpi_show(struct class_device *cdev, char *buf)
 {
        struct Scsi_Host *host = class_to_shost(cdev);
-       MPT_SCSI_HOST   *hd = shost_priv(host);
+       MPT_SCSI_HOST   *hd = shost_private(host);
        MPT_ADAPTER *ioc = hd->ioc;
 
-       return snprintf(buf, PAGE_SIZE, "%03x\n", ioc->facts.MsgVersion);
+       if (ioc->facts.MsgVersion >= MPI_VERSION_01_05)
+               return snprintf(buf, PAGE_SIZE, "%03x.%02x\n",
+                   ioc->facts.MsgVersion, ioc->facts.HeaderVersion >> 8);
+       else
+               return snprintf(buf, PAGE_SIZE, "%03x\n",
+                   ioc->facts.MsgVersion);
 }
 static CLASS_DEVICE_ATTR(version_mpi, S_IRUGO, mptscsih_version_mpi_show, NULL);
 
@@ -3354,7 +3355,7 @@ static ssize_t
 mptscsih_version_product_show(struct class_device *cdev, char *buf)
 {
        struct Scsi_Host *host = class_to_shost(cdev);
-       MPT_SCSI_HOST   *hd = shost_priv(host);
+       MPT_SCSI_HOST   *hd = shost_private(host);
        MPT_ADAPTER *ioc = hd->ioc;
 
        return snprintf(buf, PAGE_SIZE, "%s\n", ioc->prod_name);
@@ -3366,7 +3367,7 @@ static ssize_t
 mptscsih_version_nvdata_persistent_show(struct class_device *cdev, char *buf)
 {
        struct Scsi_Host *host = class_to_shost(cdev);
-       MPT_SCSI_HOST   *hd = shost_priv(host);
+       MPT_SCSI_HOST   *hd = shost_private(host);
        MPT_ADAPTER *ioc = hd->ioc;
 
        return snprintf(buf, PAGE_SIZE, "%02xh\n",
@@ -3379,7 +3380,7 @@ static ssize_t
 mptscsih_version_nvdata_default_show(struct class_device *cdev, char *buf)
 {
        struct Scsi_Host *host = class_to_shost(cdev);
-       MPT_SCSI_HOST   *hd = shost_priv(host);
+       MPT_SCSI_HOST   *hd = shost_private(host);
        MPT_ADAPTER *ioc = hd->ioc;
 
        return snprintf(buf, PAGE_SIZE, "%02xh\n",ioc->nvdata_version_default);
@@ -3391,7 +3392,7 @@ static ssize_t
 mptscsih_board_name_show(struct class_device *cdev, char *buf)
 {
        struct Scsi_Host *host = class_to_shost(cdev);
-       MPT_SCSI_HOST   *hd = shost_priv(host);
+       MPT_SCSI_HOST   *hd = shost_private(host);
        MPT_ADAPTER *ioc = hd->ioc;
 
        return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_name);
@@ -3402,7 +3403,7 @@ static ssize_t
 mptscsih_board_assembly_show(struct class_device *cdev, char *buf)
 {
        struct Scsi_Host *host = class_to_shost(cdev);
-       MPT_SCSI_HOST   *hd = shost_priv(host);
+       MPT_SCSI_HOST   *hd = shost_private(host);
        MPT_ADAPTER *ioc = hd->ioc;
 
        return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_assembly);
@@ -3414,7 +3415,7 @@ static ssize_t
 mptscsih_board_tracer_show(struct class_device *cdev, char *buf)
 {
        struct Scsi_Host *host = class_to_shost(cdev);
-       MPT_SCSI_HOST   *hd = shost_priv(host);
+       MPT_SCSI_HOST   *hd = shost_private(host);
        MPT_ADAPTER *ioc = hd->ioc;
 
        return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_tracer);
@@ -3426,7 +3427,7 @@ static ssize_t
 mptscsih_io_delay_show(struct class_device *cdev, char *buf)
 {
        struct Scsi_Host *host = class_to_shost(cdev);
-       MPT_SCSI_HOST   *hd = shost_priv(host);
+       MPT_SCSI_HOST   *hd = shost_private(host);
        MPT_ADAPTER *ioc = hd->ioc;
 
        return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->io_missing_delay);
@@ -3438,7 +3439,7 @@ static ssize_t
 mptscsih_device_delay_show(struct class_device *cdev, char *buf)
 {
        struct Scsi_Host *host = class_to_shost(cdev);
-       MPT_SCSI_HOST   *hd = shost_priv(host);
+       MPT_SCSI_HOST   *hd = shost_private(host);
        MPT_ADAPTER *ioc = hd->ioc;
 
        return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->device_missing_delay);
@@ -3450,17 +3451,16 @@ static ssize_t
 mptscsih_debug_level_show(struct class_device *cdev, char *buf)
 {
        struct Scsi_Host *host = class_to_shost(cdev);
-       MPT_SCSI_HOST   *hd = shost_priv(host);
+       MPT_SCSI_HOST   *hd = shost_private(host);
        MPT_ADAPTER *ioc = hd->ioc;
 
        return snprintf(buf, PAGE_SIZE, "%08xh\n", ioc->debug_level);
 }
 static ssize_t
-mptscsih_debug_level_store(struct class_device *cdev, const char *buf,
-                                                               size_t count)
+mptscsih_debug_level_store(struct class_device *cdev, const char *buf, size_t count)
 {
        struct Scsi_Host *host = class_to_shost(cdev);
-       MPT_SCSI_HOST   *hd = shost_priv(host);
+       MPT_SCSI_HOST   *hd = shost_private(host);
        MPT_ADAPTER *ioc = hd->ioc;
        int val = 0;
 
@@ -3468,13 +3468,44 @@ mptscsih_debug_level_store(struct class_device *cdev, const char *buf,
                return -EINVAL;
 
        ioc->debug_level = val;
-       printk(MYIOC_s_INFO_FMT "debug_level=%08xh\n",
-                               ioc->name, ioc->debug_level);
+       printk(MYIOC_s_INFO_FMT "debug_level=%08xh\n", ioc->name,
+           ioc->debug_level);
        return strlen(buf);
 }
 static CLASS_DEVICE_ATTR(debug_level, S_IRUGO | S_IWUSR,
     mptscsih_debug_level_show, mptscsih_debug_level_store);
 
+static ssize_t
+mptscsih_disable_hotplug_remove_show(struct class_device *cdev, char *buf)
+{
+       struct Scsi_Host *host = class_to_shost(cdev);
+       MPT_SCSI_HOST   *hd = shost_private(host);
+       MPT_ADAPTER *ioc = hd->ioc;
+
+       return snprintf(buf, PAGE_SIZE, "%02xh\n", ioc->disable_hotplug_remove);
+}
+static ssize_t
+mptscsih_disable_hotplug_remove_store(struct class_device *cdev, const char *buf, size_t count)
+{
+       struct Scsi_Host *host = class_to_shost(cdev);
+       MPT_SCSI_HOST   *hd = shost_private(host);
+       MPT_ADAPTER *ioc = hd->ioc;
+       int val = 0;
+
+       if (sscanf(buf, "%x", &val) != 1)
+               return -EINVAL;
+
+       ioc->disable_hotplug_remove = val;
+       if (ioc->disable_hotplug_remove)
+               printk(MYIOC_s_INFO_FMT "disabling hotplug remove\n",
+                   ioc->name);
+       else
+               printk(MYIOC_s_INFO_FMT "eanbling hotplug remove\n", ioc->name);
+       return strlen(buf);
+}
+static CLASS_DEVICE_ATTR(disable_hotplug_remove, S_IRUGO | S_IWUSR,
+    mptscsih_disable_hotplug_remove_show, mptscsih_disable_hotplug_remove_store);
+
 struct class_device_attribute *mptscsih_host_attrs[] = {
        &class_device_attr_version_fw,
        &class_device_attr_version_bios,
@@ -3488,6 +3519,7 @@ struct class_device_attribute *mptscsih_host_attrs[] = {
        &class_device_attr_io_delay,
        &class_device_attr_device_delay,
        &class_device_attr_debug_level,
+       &class_device_attr_disable_hotplug_remove,
        NULL,
 };
 EXPORT_SYMBOL(mptscsih_host_attrs);
@@ -3514,7 +3546,9 @@ EXPORT_SYMBOL(mptscsih_scandv_complete);
 EXPORT_SYMBOL(mptscsih_event_process);
 EXPORT_SYMBOL(mptscsih_ioc_reset);
 EXPORT_SYMBOL(mptscsih_change_queue_depth);
-EXPORT_SYMBOL(mptscsih_timer_expired);
-EXPORT_SYMBOL(mptscsih_TMHandler);
-
+EXPORT_SYMBOL(mptscsih_IssueTaskMgmt);
+EXPORT_SYMBOL(mptscsih_do_cmd);
+EXPORT_SYMBOL(mptscsih_quiesce_raid);
+EXPORT_SYMBOL(mptscsih_get_scsi_lookup);
+EXPORT_SYMBOL(mptscsih_taskmgmt_response_code);
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
index d289e97cfe8b2b781734454fee76ee8426ac3050..6676beda9be818b09084d06dfc7c94456ee715e0 100644 (file)
@@ -60,6 +60,7 @@
 #define MPT_SCANDV_SELECTION_TIMEOUT   (0x00000008)
 #define MPT_SCANDV_ISSUE_SENSE         (0x00000010)
 #define MPT_SCANDV_FALLBACK            (0x00000020)
+#define MPT_SCANDV_BUSY                        (0x00000040)
 
 #define MPT_SCANDV_MAX_RETRIES         (10)
 
@@ -71,6 +72,7 @@
 #define MPT_ICFLAG_DID_RESET   0x20    /* Bus Reset occurred with this command */
 #define MPT_ICFLAG_RESERVED    0x40    /* Reserved has been issued */
 
+
 #define MPT_SCSI_CMD_PER_DEV_HIGH      64
 #define MPT_SCSI_CMD_PER_DEV_LOW       32
 
 #define MPTSCSIH_DOMAIN_VALIDATION      1
 #define MPTSCSIH_MAX_WIDTH              1
 #define MPTSCSIH_MIN_SYNC               0x08
+#define MPTSCSIH_QAS                    1
 #define MPTSCSIH_SAF_TE                 0
 #define MPTSCSIH_PT_CLEAR               0
 
+#define TRANSPORT_LAYER_RETRIES                0xC2
 #endif
 
 typedef struct _internal_cmd {
@@ -112,7 +116,7 @@ extern int mptscsih_resume(struct pci_dev *pdev);
 extern int mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, int length, int func);
 extern const char * mptscsih_info(struct Scsi_Host *SChost);
 extern int mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *));
-extern void mptscsih_slave_destroy(struct scsi_device *device);
+extern void mptscsih_slave_destroy(struct scsi_device *sdev);
 extern int mptscsih_slave_configure(struct scsi_device *device);
 extern int mptscsih_abort(struct scsi_cmnd * SCpnt);
 extern int mptscsih_dev_reset(struct scsi_cmnd * SCpnt);
@@ -125,8 +129,11 @@ extern int mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRA
 extern int mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply);
 extern int mptscsih_ioc_reset(MPT_ADAPTER *ioc, int post_reset);
 extern int mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth);
-extern void mptscsih_timer_expired(unsigned long data);
-extern int mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout);
+extern int mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout);
 extern u8 mptscsih_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id);
 extern int mptscsih_is_phys_disk(MPT_ADAPTER *ioc, u8 channel, u8 id);
+extern int mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *iocmd);
 extern struct class_device_attribute *mptscsih_host_attrs[];
+extern int mptscsih_quiesce_raid(MPT_SCSI_HOST *hd, int quiesce, u8 channel, u8 id);
+extern struct scsi_cmnd * mptscsih_get_scsi_lookup(MPT_ADAPTER *ioc, int i);
+extern void mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code);
index 5624d72764bc86656b6e70d27401083e11d3cc5f..2fa16365262e36fdc8ec99b7bab5b2de3c6fc2be 100644 (file)
@@ -43,7 +43,7 @@
     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-
+#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/delay.h>       /* for mdelay */
 #include <linux/interrupt.h>   /* needed for in_interrupt() proto */
 #include <linux/reboot.h>      /* notifier code */
+#include <linux/sched.h>
 #include <linux/workqueue.h>
 #include <linux/raid_class.h>
+#include <linux/pci.h>
 
 #include <scsi/scsi.h>
 #include <scsi/scsi_cmnd.h>
@@ -65,9 +67,9 @@
 #include <scsi/scsi_transport_spi.h>
 #include <scsi/scsi_dbg.h>
 
+#include "linux_compat.h"      /* linux-2.6 tweaks */
 #include "mptbase.h"
 #include "mptscsih.h"
-#include "linux_compat.h"
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 #define my_NAME                "Fusion MPT SPI Host driver"
@@ -84,6 +86,10 @@ static int mpt_saf_te = MPTSCSIH_SAF_TE;
 module_param(mpt_saf_te, int, 0);
 MODULE_PARM_DESC(mpt_saf_te, " Force enabling SEP Processor: enable=1  (default=MPTSCSIH_SAF_TE=0)");
 
+static int mpt_qas = MPTSCSIH_QAS;
+module_param(mpt_qas, int, 1);
+MODULE_PARM_DESC(mpt_qas, " Quick Arbitration and Selection (QAS) enabled=1, disabled=0 (default=MPTSCSIH_QAS=1)");
+
 static void mptspi_write_offset(struct scsi_target *, int);
 static void mptspi_write_width(struct scsi_target *, int);
 static int mptspi_write_spi_device_pg1(struct scsi_target *,
@@ -96,12 +102,12 @@ static u8  mptspiTaskCtx = MPT_MAX_PROTOCOL_DRIVERS;
 static u8      mptspiInternalCtx = MPT_MAX_PROTOCOL_DRIVERS; /* Used only for internal commands */
 
 /**
- *     mptspi_setTargetNegoParms  - Update the target negotiation parameters
+ *     mptspi_setTargetNegoParms  - Update the target negotiation parameters
  *     @hd: Pointer to a SCSI Host Structure
  *     @target: per target private data
  *     @sdev: SCSI device
  *
- *     Update the target negotiation parameters based on the the Inquiry
+ *     Update the target negotiation parameters based on the the Inquiry
  *     data, adapter capabilities, and NVRAM settings.
  **/
 static void
@@ -132,7 +138,7 @@ mptspi_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtTarget *target,
                if (scsi_device_sync(sdev)) {
                        factor = pspi_data->minSyncFactor;
                        if (!scsi_device_dt(sdev))
-                                       factor = MPT_ULTRA2;
+                               factor = MPT_ULTRA2;
                        else {
                                if (!scsi_device_ius(sdev) &&
                                    !scsi_device_qas(sdev))
@@ -210,6 +216,10 @@ mptspi_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtTarget *target,
        target->maxOffset = offset;
        target->maxWidth = width;
 
+       spi_min_period(scsi_target(sdev)) = factor;
+       spi_max_offset(scsi_target(sdev)) = offset;
+       spi_max_width(scsi_target(sdev)) = width;
+
        target->tflags |= MPT_TARGET_FLAGS_VALID_NEGO;
 
        /* Disable unused features.
@@ -231,7 +241,7 @@ mptspi_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtTarget *target,
                 */
 
                ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
-                       "Disabling QAS due to noQas=%02x on id=%d!\n", ioc->name, noQas, id));
+               "Disabling QAS due to noQas=%02x on id=%d!\n", ioc->name, noQas, id));
        }
 }
 
@@ -263,7 +273,7 @@ mptspi_writeIOCPage4(MPT_SCSI_HOST *hd, u8 channel , u8 id)
         */
        if ((mf = mpt_get_msg_frame(ioc->DoneCtx, ioc)) == NULL) {
                dfailprintk(ioc, printk(MYIOC_s_WARN_FMT
-                               "writeIOCPage4 : no msg frames!\n",ioc->name));
+                   "writeIOCPage4 : no msg frames!\n", ioc->name));
                return -EAGAIN;
        }
 
@@ -305,7 +315,7 @@ mptspi_writeIOCPage4(MPT_SCSI_HOST *hd, u8 channel , u8 id)
 
        ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
                "writeIOCPage4: MaxSEP=%d ActiveSEP=%d id=%d bus=%d\n",
-               ioc->name, IOCPage4Ptr->MaxSEP, IOCPage4Ptr->ActiveSEP, id, channel));
+                       ioc->name, IOCPage4Ptr->MaxSEP, IOCPage4Ptr->ActiveSEP, id, channel));
 
        mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
 
@@ -372,7 +382,7 @@ mptspi_initTarget(MPT_SCSI_HOST *hd, VirtTarget *vtarget,
  *             non-zero = true
  *             zero = false
  *
- */
+ **/
 static int
 mptspi_is_raid(struct _MPT_SCSI_HOST *hd, u32 id)
 {
@@ -398,14 +408,13 @@ mptspi_is_raid(struct _MPT_SCSI_HOST *hd, u32 id)
 static int mptspi_target_alloc(struct scsi_target *starget)
 {
        struct Scsi_Host *shost = dev_to_shost(&starget->dev);
-       struct _MPT_SCSI_HOST *hd = shost_priv(shost);
+       struct _MPT_SCSI_HOST *hd = shost_private(shost);
        VirtTarget              *vtarget;
-       MPT_ADAPTER *ioc;
+       MPT_ADAPTER *ioc = hd->ioc;
 
        if (hd == NULL)
                return -ENODEV;
 
-       ioc = hd->ioc;
        vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL);
        if (!vtarget)
                return -ENOMEM;
@@ -448,6 +457,7 @@ static int mptspi_target_alloc(struct scsi_target *starget)
        spi_max_offset(starget) = ioc->spi_data.maxSyncOffset;
 
        spi_offset(starget) = 0;
+       spi_period(starget) = 0xFF;
        mptspi_write_width(starget, 0);
 
        return 0;
@@ -471,9 +481,12 @@ mptspi_target_destroy(struct scsi_target *starget)
 static void
 mptspi_print_write_nego(struct _MPT_SCSI_HOST *hd, struct scsi_target *starget, u32 ii)
 {
-       ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "id=%d Requested = 0x%08x"
+       if (!(hd->ioc->debug_level & MPT_DEBUG_DV))
+               return;
+
+       starget_printk(KERN_DEBUG, starget, MYIOC_s_FMT "Wrote = 0x%08x"
            " ( %s factor = 0x%02x @ offset = 0x%02x %s%s%s%s%s%s%s%s)\n",
-           hd->ioc->name, starget->id, ii,
+           hd->ioc->name, ii,
            ii & MPI_SCSIDEVPAGE0_NP_WIDE ? "Wide ": "",
            ((ii >> 8) & 0xFF), ((ii >> 16) & 0xFF),
            ii & MPI_SCSIDEVPAGE0_NP_IU ? "IU ": "",
@@ -483,7 +496,7 @@ mptspi_print_write_nego(struct _MPT_SCSI_HOST *hd, struct scsi_target *starget,
            ii & MPI_SCSIDEVPAGE0_NP_WR_FLOW ? "WRFLOW ": "",
            ii & MPI_SCSIDEVPAGE0_NP_RD_STRM ? "RDSTRM ": "",
            ii & MPI_SCSIDEVPAGE0_NP_RTI ? "RTI ": "",
-           ii & MPI_SCSIDEVPAGE0_NP_PCOMP_EN ? "PCOMP ": ""));
+           ii & MPI_SCSIDEVPAGE0_NP_PCOMP_EN ? "PCOMP ": "");
 }
 
 /**
@@ -496,9 +509,12 @@ mptspi_print_write_nego(struct _MPT_SCSI_HOST *hd, struct scsi_target *starget,
 static void
 mptspi_print_read_nego(struct _MPT_SCSI_HOST *hd, struct scsi_target *starget, u32 ii)
 {
-       ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "id=%d Read = 0x%08x"
+       if (!(hd->ioc->debug_level & MPT_DEBUG_DV))
+               return;
+
+       starget_printk(KERN_DEBUG, starget, MYIOC_s_FMT "Read = 0x%08x"
            " ( %s factor = 0x%02x @ offset = 0x%02x %s%s%s%s%s%s%s%s)\n",
-           hd->ioc->name, starget->id, ii,
+           hd->ioc->name, ii,
            ii & MPI_SCSIDEVPAGE0_NP_WIDE ? "Wide ": "",
            ((ii >> 8) & 0xFF), ((ii >> 16) & 0xFF),
            ii & MPI_SCSIDEVPAGE0_NP_IU ? "IU ": "",
@@ -508,14 +524,14 @@ mptspi_print_read_nego(struct _MPT_SCSI_HOST *hd, struct scsi_target *starget, u
            ii & MPI_SCSIDEVPAGE0_NP_WR_FLOW ? "WRFLOW ": "",
            ii & MPI_SCSIDEVPAGE0_NP_RD_STRM ? "RDSTRM ": "",
            ii & MPI_SCSIDEVPAGE0_NP_RTI ? "RTI ": "",
-           ii & MPI_SCSIDEVPAGE0_NP_PCOMP_EN ? "PCOMP ": ""));
+           ii & MPI_SCSIDEVPAGE0_NP_PCOMP_EN ? "PCOMP ": "");
 }
 
 static int mptspi_read_spi_device_pg0(struct scsi_target *starget,
                             struct _CONFIG_PAGE_SCSI_DEVICE_0 *pass_pg0)
 {
        struct Scsi_Host *shost = dev_to_shost(&starget->dev);
-       struct _MPT_SCSI_HOST *hd = shost_priv(shost);
+       struct _MPT_SCSI_HOST *hd = shost_private(shost);
        struct _MPT_ADAPTER *ioc = hd->ioc;
        struct _CONFIG_PAGE_SCSI_DEVICE_0 *spi_dev_pg0;
        dma_addr_t spi_dev_pg0_dma;
@@ -557,9 +573,11 @@ static int mptspi_read_spi_device_pg0(struct scsi_target *starget,
        cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
        cfg.dir = 0;
        cfg.pageAddr = starget->id;
+       cfg.timeout = 60;
 
        if (mpt_config(ioc, &cfg)) {
-               starget_printk(KERN_ERR, starget, MYIOC_s_FMT "mpt_config failed\n", ioc->name);
+               starget_printk(KERN_ERR, starget,
+                   MYIOC_s_FMT "mpt_config failed\n", ioc->name);
                goto out_free;
        }
        err = 0;
@@ -614,64 +632,11 @@ static void mptspi_read_parameters(struct scsi_target *starget)
        spi_width(starget) = (nego & MPI_SCSIDEVPAGE0_NP_WIDE) ? 1 : 0;
 }
 
-static int
-mptscsih_quiesce_raid(MPT_SCSI_HOST *hd, int quiesce, u8 channel, u8 id)
-{
-       MpiRaidActionRequest_t  *pReq;
-       MPT_FRAME_HDR           *mf;
-       MPT_ADAPTER *ioc = hd->ioc;
-
-       /* Get and Populate a free Frame
-        */
-       if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
-               ddvprintk(ioc, printk(MYIOC_s_WARN_FMT "_do_raid: no msg frames!\n",
-                                       ioc->name));
-               return -EAGAIN;
-       }
-       pReq = (MpiRaidActionRequest_t *)mf;
-       if (quiesce)
-               pReq->Action = MPI_RAID_ACTION_QUIESCE_PHYS_IO;
-       else
-               pReq->Action = MPI_RAID_ACTION_ENABLE_PHYS_IO;
-       pReq->Reserved1 = 0;
-       pReq->ChainOffset = 0;
-       pReq->Function = MPI_FUNCTION_RAID_ACTION;
-       pReq->VolumeID = id;
-       pReq->VolumeBus = channel;
-       pReq->PhysDiskNum = 0;
-       pReq->MsgFlags = 0;
-       pReq->Reserved2 = 0;
-       pReq->ActionDataWord = 0; /* Reserved for this action */
-
-       ioc->add_sge((char *)&pReq->ActionDataSGE,
-               MPT_SGE_FLAGS_SSIMPLE_READ | 0, (dma_addr_t) -1);
-
-       ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RAID Volume action=%x channel=%d id=%d\n",
-                       ioc->name, pReq->Action, channel, id));
-
-       hd->pLocal = NULL;
-       hd->timer.expires = jiffies + HZ*10; /* 10 second timeout */
-       hd->scandv_wait_done = 0;
-
-       /* Save cmd pointer, for resource free if timeout or
-        * FW reload occurs
-        */
-       hd->cmdPtr = mf;
-
-       add_timer(&hd->timer);
-       mpt_put_msg_frame(ioc->InternalCtx, ioc, mf);
-       wait_event(hd->scandv_waitq, hd->scandv_wait_done);
-
-       if ((hd->pLocal == NULL) || (hd->pLocal->completion != 0))
-               return -1;
-
-       return 0;
-}
-
 static void mptspi_dv_device(struct _MPT_SCSI_HOST *hd,
                             struct scsi_device *sdev)
 {
        VirtTarget *vtarget = scsi_target(sdev)->hostdata;
+       struct scsi_target *starget = scsi_target(sdev);
        MPT_ADAPTER *ioc = hd->ioc;
 
        /* no DV on RAID devices */
@@ -679,11 +644,20 @@ static void mptspi_dv_device(struct _MPT_SCSI_HOST *hd,
            mptspi_is_raid(hd, sdev->id))
                return;
 
+       if (ioc->debug_level & MPT_DEBUG_DV)
+               starget_printk(KERN_DEBUG, starget, MYIOC_s_FMT
+                   "sdtr=%d, wdtr=%d, ppr=%d, min_period=0x%02x, "
+                   "max_offset=0x%02x, max_width=%d, nego_flags=0x%02x, "
+                   "tflags=0x%02x\n", ioc->name, sdev->sdtr, sdev->wdtr,
+                   sdev->ppr, spi_min_period(starget),
+                   spi_max_offset(starget), spi_max_width(starget),
+                   vtarget->negoFlags, vtarget->tflags);
+
        /* If this is a piece of a RAID, then quiesce first */
        if (sdev->channel == 1 &&
            mptscsih_quiesce_raid(hd, 1, vtarget->channel, vtarget->id) < 0) {
-               starget_printk(KERN_ERR, scsi_target(sdev), MYIOC_s_FMT
-                   "Integrated RAID quiesce failed\n", ioc->name);
+               starget_printk(KERN_ERR, scsi_target(sdev),
+                   MYIOC_s_FMT "Integrated RAID quiesce failed\n", ioc->name);
                return;
        }
 
@@ -693,8 +667,8 @@ static void mptspi_dv_device(struct _MPT_SCSI_HOST *hd,
 
        if (sdev->channel == 1 &&
            mptscsih_quiesce_raid(hd, 0, vtarget->channel, vtarget->id) < 0)
-               starget_printk(KERN_ERR, scsi_target(sdev), MYIOC_s_FMT
-                   "Integrated RAID resume failed\n", ioc->name);
+               starget_printk(KERN_ERR, scsi_target(sdev),
+                   MYIOC_s_FMT "Integrated RAID resume failed\n", ioc->name);
 
        mptspi_read_parameters(sdev->sdev_target);
        spi_display_xfer_agreement(sdev->sdev_target);
@@ -703,7 +677,7 @@ static void mptspi_dv_device(struct _MPT_SCSI_HOST *hd,
 
 static int mptspi_slave_alloc(struct scsi_device *sdev)
 {
-       MPT_SCSI_HOST *hd = shost_priv(sdev->host);
+       MPT_SCSI_HOST *hd = shost_private(sdev->host);
        VirtTarget              *vtarget;
        VirtDevice              *vdevice;
        struct scsi_target      *starget;
@@ -716,7 +690,7 @@ static int mptspi_slave_alloc(struct scsi_device *sdev)
        vdevice = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
        if (!vdevice) {
                printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n",
-                               ioc->name, sizeof(VirtDevice));
+                   ioc->name, sizeof(VirtDevice));
                return -ENOMEM;
        }
 
@@ -736,23 +710,15 @@ static int mptspi_slave_alloc(struct scsi_device *sdev)
 
 static int mptspi_slave_configure(struct scsi_device *sdev)
 {
-       struct _MPT_SCSI_HOST *hd = shost_priv(sdev->host);
+       struct _MPT_SCSI_HOST *hd = shost_private(sdev->host);
        VirtTarget *vtarget = scsi_target(sdev)->hostdata;
-       int ret;
+       int     ret;
 
        mptspi_initTarget(hd, vtarget, sdev);
-
        ret = mptscsih_slave_configure(sdev);
-
        if (ret)
                return ret;
 
-       ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "id=%d min_period=0x%02x"
-               " max_offset=0x%02x max_width=%d\n", hd->ioc->name,
-               sdev->id, spi_min_period(scsi_target(sdev)),
-               spi_max_offset(scsi_target(sdev)),
-               spi_max_width(scsi_target(sdev))));
-
        if ((sdev->channel == 1 ||
             !(mptspi_is_raid(hd, sdev->id))) &&
            !spi_initial_dv(sdev->sdev_target))
@@ -764,7 +730,7 @@ static int mptspi_slave_configure(struct scsi_device *sdev)
 static int
 mptspi_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
 {
-       struct _MPT_SCSI_HOST *hd = shost_priv(SCpnt->device->host);
+       struct _MPT_SCSI_HOST *hd = shost_private(SCpnt->device->host);
        VirtDevice      *vdevice = SCpnt->device->hostdata;
        MPT_ADAPTER *ioc = hd->ioc;
 
@@ -839,7 +805,7 @@ static int mptspi_write_spi_device_pg1(struct scsi_target *starget,
                               struct _CONFIG_PAGE_SCSI_DEVICE_1 *pass_pg1)
 {
        struct Scsi_Host *shost = dev_to_shost(&starget->dev);
-       struct _MPT_SCSI_HOST *hd = shost_priv(shost);
+       struct _MPT_SCSI_HOST *hd = shost_private(shost);
        struct _MPT_ADAPTER *ioc = hd->ioc;
        struct _CONFIG_PAGE_SCSI_DEVICE_1 *pg1;
        dma_addr_t pg1_dma;
@@ -857,8 +823,8 @@ static int mptspi_write_spi_device_pg1(struct scsi_target *starget,
 
        pg1 = dma_alloc_coherent(&ioc->pcidev->dev, size, &pg1_dma, GFP_KERNEL);
        if (pg1 == NULL) {
-               starget_printk(KERN_ERR, starget, MYIOC_s_FMT
-                   "dma_alloc_coherent for parameters failed\n", ioc->name);
+               starget_printk(KERN_ERR, starget,
+                   MYIOC_s_FMT "dma_alloc_coherent for parameters failed\n", ioc->name);
                return -EINVAL;
        }
 
@@ -887,8 +853,8 @@ static int mptspi_write_spi_device_pg1(struct scsi_target *starget,
        mptspi_print_write_nego(hd, starget, le32_to_cpu(pg1->RequestedParameters));
 
        if (mpt_config(ioc, &cfg)) {
-               starget_printk(KERN_ERR, starget, MYIOC_s_FMT
-                   "mpt_config failed\n", ioc->name);
+               starget_printk(KERN_ERR, starget,
+                   MYIOC_s_FMT "mpt_config failed\n", ioc->name);
                goto out_free;
        }
        err = 0;
@@ -963,14 +929,15 @@ static void mptspi_write_dt(struct scsi_target *starget, int dt)
        if (spi_period(starget) == -1)
                mptspi_read_parameters(starget);
 
-       if (!dt && spi_period(starget) < 10)
-               spi_period(starget) = 10;
+       if (!dt) {
+               spi_qas(starget) = 0;
+               spi_iu(starget) = 0;
+       }
 
        spi_dt(starget) = dt;
 
        nego = mptspi_getRP(starget);
 
-
        pg1.RequestedParameters = cpu_to_le32(nego);
        pg1.Reserved = 0;
        pg1.Configuration = 0;
@@ -986,9 +953,6 @@ static void mptspi_write_iu(struct scsi_target *starget, int iu)
        if (spi_period(starget) == -1)
                mptspi_read_parameters(starget);
 
-       if (!iu && spi_period(starget) < 9)
-               spi_period(starget) = 9;
-
        spi_iu(starget) = iu;
 
        nego = mptspi_getRP(starget);
@@ -1027,12 +991,14 @@ static void mptspi_write_qas(struct scsi_target *starget, int qas)
 {
        struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1;
        struct Scsi_Host *shost = dev_to_shost(&starget->dev);
-       struct _MPT_SCSI_HOST *hd = shost_priv(shost);
+       struct _MPT_SCSI_HOST *hd = shost_private(shost);
        VirtTarget *vtarget = starget->hostdata;
        u32 nego;
+       MPT_ADAPTER *ioc = hd->ioc;
 
-       if ((vtarget->negoFlags & MPT_TARGET_NO_NEGO_QAS) ||
-           hd->ioc->spi_data.noQas)
+       if (!mpt_qas ||
+           (vtarget->negoFlags & MPT_TARGET_NO_NEGO_QAS) ||
+           ioc->spi_data.noQas)
                spi_qas(starget) = 0;
        else
                spi_qas(starget) = qas;
@@ -1053,8 +1019,8 @@ static void mptspi_write_width(struct scsi_target *starget, int width)
 
        if (!width) {
                spi_dt(starget) = 0;
-               if (spi_period(starget) < 10)
-                       spi_period(starget) = 10;
+               spi_qas(starget) = 0;
+               spi_iu(starget) = 0;
        }
 
        spi_width(starget) = width;
@@ -1075,9 +1041,16 @@ struct work_queue_wrapper {
 };
 
 static void
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19))
+mpt_work_wrapper(struct work_struct *work)
+{
+       struct work_queue_wrapper *wqw =
+               container_of(work, struct work_queue_wrapper, work);
+#else
 mpt_work_wrapper(void *data)
 {
        struct work_queue_wrapper *wqw = (struct work_queue_wrapper *)data;
+#endif
        struct _MPT_SCSI_HOST *hd = wqw->hd;
        MPT_ADAPTER *ioc = hd->ioc;
        struct Scsi_Host *shost = ioc->sh;
@@ -1105,12 +1078,12 @@ mpt_work_wrapper(void *data)
                if(vtarget->id != disk)
                        continue;
 
-               starget_printk(KERN_INFO, vtarget->starget, MYIOC_s_FMT
-                   "Integrated RAID requests DV of new device\n", ioc->name);
+               starget_printk(KERN_INFO, vtarget->starget,
+                   MYIOC_s_FMT "Integrated RAID requests DV of new device\n", ioc->name);
                mptspi_dv_device(hd, sdev);
        }
-       shost_printk(KERN_INFO, shost, MYIOC_s_FMT
-           "Integrated RAID detects new device %d\n", ioc->name, disk);
+       shost_printk(KERN_INFO, shost,
+           MYIOC_s_FMT "Integrated RAID detects new device %d\n", ioc->name, disk);
        scsi_scan_target(&ioc->sh->shost_gendev, 1, disk, 0, 1);
 }
 
@@ -1121,12 +1094,16 @@ static void mpt_dv_raid(struct _MPT_SCSI_HOST *hd, int disk)
        MPT_ADAPTER *ioc = hd->ioc;
 
        if (!wqw) {
-               shost_printk(KERN_ERR, ioc->sh, MYIOC_s_FMT
-                   "Failed to act on RAID event for physical disk %d\n",
+               shost_printk(KERN_ERR, ioc->sh,
+                   MYIOC_s_FMT "Failed to act on RAID event for physical disk %d\n",
                    ioc->name, disk);
                return;
        }
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19))
+       INIT_WORK(&wqw->work, mpt_work_wrapper);
+#else
        INIT_WORK(&wqw->work, mpt_work_wrapper, wqw);
+#endif
        wqw->hd = hd;
        wqw->disk = disk;
 
@@ -1137,7 +1114,7 @@ static int
 mptspi_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
 {
        u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
-       struct _MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
+       struct _MPT_SCSI_HOST *hd = shost_private(ioc->sh);
 
        if (hd && event ==  MPI_EVENT_INTEGRATED_RAID) {
                int reason
@@ -1213,13 +1190,20 @@ static struct pci_device_id mptspi_pci_table[] = {
 MODULE_DEVICE_TABLE(pci, mptspi_pci_table);
 
 
-/*
+/**
  * renegotiate for a given target
- */
+ **/
 static void
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19))
+mptspi_dv_renegotiate_work(struct work_struct *work)
+{
+       struct work_queue_wrapper *wqw =
+               container_of(work, struct work_queue_wrapper, work);
+#else
 mptspi_dv_renegotiate_work(void *data)
 {
        struct work_queue_wrapper *wqw = (struct work_queue_wrapper *)data;
+#endif
        struct _MPT_SCSI_HOST *hd = wqw->hd;
        struct scsi_device *sdev;
        struct scsi_target *starget;
@@ -1254,38 +1238,48 @@ mptspi_dv_renegotiate(struct _MPT_SCSI_HOST *hd)
        if (!wqw)
                return;
 
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19))
+       INIT_WORK(&wqw->work, mptspi_dv_renegotiate_work);
+#else
        INIT_WORK(&wqw->work, mptspi_dv_renegotiate_work, wqw);
+#endif
        wqw->hd = hd;
 
        schedule_work(&wqw->work);
 }
 
-/*
+/**
  * spi module reset handler
- */
+ **/
 static int
 mptspi_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
 {
-       struct _MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
+       struct _MPT_SCSI_HOST *hd = NULL;
        int rc;
 
        rc = mptscsih_ioc_reset(ioc, reset_phase);
+       if ((ioc->bus_type != SPI) || (!rc))
+               goto out;
 
-       if (reset_phase == MPT_IOC_POST_RESET)
-               mptspi_dv_renegotiate(hd);
+       hd = shost_private(ioc->sh);
+       if (!hd->ioc)
+               goto out;
 
+       if (ioc->active && reset_phase == MPT_IOC_POST_RESET)
+               mptspi_dv_renegotiate(hd);
+ out:
        return rc;
 }
 
 #ifdef CONFIG_PM
-/*
+/**
  * spi module resume handler
- */
+ **/
 static int
 mptspi_resume(struct pci_dev *pdev)
 {
        MPT_ADAPTER     *ioc = pci_get_drvdata(pdev);
-       struct _MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
+       struct _MPT_SCSI_HOST *hd = shost_private(ioc->sh);
        int rc;
 
        rc = mptscsih_resume(pdev);
@@ -1297,13 +1291,13 @@ mptspi_resume(struct pci_dev *pdev)
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*
+/**
  *     mptspi_probe - Installs scsi devices per bus.
  *     @pdev: Pointer to pci_dev structure
  *
  *     Returns 0 for success, non-zero for failure.
  *
- */
+ **/
 static int
 mptspi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
@@ -1438,11 +1432,11 @@ mptspi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
                sh->sg_tablesize = numSGE;
        }
 
-       spin_unlock_irqrestore(&ioc->FreeQlock, flags);
-
-       hd = shost_priv(sh);
+       hd = shost_private(sh);
        hd->ioc = ioc;
 
+       spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+
        /* SCSI needs scsi_cmnd lookup table!
         * (with size equal to req_depth*PtrSz!)
         */
@@ -1456,39 +1450,12 @@ mptspi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n",
                 ioc->name, ioc->ScsiLookup));
 
-       /* Clear the TM flags
-        */
-       hd->tmPending = 0;
-       hd->tmState = TM_STATE_NONE;
-       hd->resetPending = 0;
-       hd->abortSCpnt = NULL;
-
-       /* Clear the pointer used to store
-        * single-threaded commands, i.e., those
-        * issued during a bus scan, dv and
-        * configuration pages.
-        */
-       hd->cmdPtr = NULL;
-
-       /* Initialize this SCSI Hosts' timers
-        * To use, set the timer expires field
-        * and add_timer
-        */
-       init_timer(&hd->timer);
-       hd->timer.data = (unsigned long) hd;
-       hd->timer.function = mptscsih_timer_expired;
-
+       ioc->sdev_queue_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
        ioc->spi_data.Saf_Te = mpt_saf_te;
-
-       hd->negoNvram = MPT_SCSICFG_USE_NVRAM;
        ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
-               "saf_te %x\n",
-               ioc->name,
-               mpt_saf_te));
-       ioc->spi_data.noQas = 0;
+           "saf_te %x\n", ioc->name, mpt_saf_te));
+       ioc->spi_data.noQas = mpt_qas ? 0 : MPT_TARGET_NO_NEGO_QAS;
 
-       init_waitqueue_head(&hd->scandv_waitq);
-       hd->scandv_wait_done = 0;
        hd->last_queue_full = 0;
        hd->spi_pending = 0;
 
@@ -1508,7 +1475,7 @@ mptspi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
         * issue internal bus reset
         */
        if (ioc->spi_data.bus_reset)
-               mptscsih_TMHandler(hd,
+               mptscsih_IssueTaskMgmt(hd,
                    MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
                    0, 0, 0, 0, 5);
 
@@ -1538,7 +1505,7 @@ static struct pci_driver mptspi_driver = {
  *     mptspi_init - Register MPT adapter(s) as SCSI host(s) with SCSI mid-layer.
  *
  *     Returns 0 for success, non-zero for failure.
- */
+ **/
 static int __init
 mptspi_init(void)
 {
@@ -1568,7 +1535,8 @@ mptspi_init(void)
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *     mptspi_exit - Unregisters MPT adapter(s)
- */
+ *
+ **/
 static void __exit
 mptspi_exit(void)
 {
@@ -1576,7 +1544,6 @@ mptspi_exit(void)
 
        mpt_reset_deregister(mptspiDoneCtx);
        mpt_event_deregister(mptspiDoneCtx);
-
        mpt_deregister(mptspiInternalCtx);
        mpt_deregister(mptspiTaskCtx);
        mpt_deregister(mptspiDoneCtx);
diff --git a/drivers/message/fusion/rejected_ioctls/diag_buffer.c b/drivers/message/fusion/rejected_ioctls/diag_buffer.c
new file mode 100644 (file)
index 0000000..36fc08d
--- /dev/null
@@ -0,0 +1,667 @@
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/* REGISTER DIAG BUFFER Routine.
+ *
+ * Outputs:    None.
+ * Return:     0 if successful
+ *             -EFAULT if data unavailable
+ *             -EBUSY  if previous command timout and IOC reset is not complete.
+ *             -ENODEV if no such device/adapter
+ *             -ETIME  if timer expires
+ *             -ENOMEM if memory allocation error
+ */
+static int
+mptctl_register_diag_buffer (unsigned long arg)
+{
+       mpt_diag_register_t     __user *uarg = (void __user *) arg;
+       mpt_diag_register_t     karg;
+       MPT_ADAPTER             *ioc;
+       int                     iocnum, rc, ii;
+       void *                  request_data;
+       dma_addr_t              request_data_dma;
+       u32                     request_data_sz;
+       MPT_FRAME_HDR           *mf;
+       DiagBufferPostRequest_t *diag_buffer_post_request;
+       DiagBufferPostReply_t   *diag_buffer_post_reply;
+       u32                     tmp;
+       u8                      buffer_type;
+       unsigned long           timeleft;
+
+       rc = 0;
+       if (copy_from_user(&karg, uarg, sizeof(mpt_diag_register_t))) {
+               printk(KERN_ERR "%s@%d::%s - "
+               "Unable to read in mpt_diag_register_t struct @ %p\n",
+                   __FILE__, __LINE__, __FUNCTION__, uarg);
+               return -EFAULT;
+       }
+
+       if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
+               (ioc == NULL)) {
+               printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n",
+                   __FILE__, __FUNCTION__, __LINE__, iocnum);
+               return -ENODEV;
+       }
+
+       dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s enter.\n", ioc->name,
+               __FUNCTION__));
+       buffer_type = karg.data.BufferType;
+       if (!(ioc->facts.IOCCapabilities & MPT_DIAG_CAPABILITY(buffer_type))) {
+               printk(MYIOC_s_DEBUG_FMT "%s: doesn't have Capability for "
+                   "buffer_type=%x\n", ioc->name, __FUNCTION__, buffer_type);
+               return -ENODEV;
+       }
+
+       if (ioc->DiagBuffer_Status[buffer_type] &
+           MPT_DIAG_BUFFER_IS_REGISTERED) {
+               printk(MYIOC_s_DEBUG_FMT "%s: already has a Registered "
+                   "buffer for buffer_type=%x\n", ioc->name, __FUNCTION__,
+                   buffer_type);
+               return -EFAULT;
+       }
+
+       /* Get a free request frame and save the message context.
+        */
+       if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL)
+               return -EAGAIN;
+
+       request_data = ioc->DiagBuffer[buffer_type];
+       request_data_sz = karg.data.RequestedBufferSize;
+
+       if (request_data) {
+               request_data_dma = ioc->DiagBuffer_dma[buffer_type];
+               if (request_data_sz != ioc->DiagBuffer_sz[buffer_type]) {
+                       pci_free_consistent(ioc->pcidev,
+                           ioc->DiagBuffer_sz[buffer_type],
+                           request_data, request_data_dma);
+                       request_data = NULL;
+               }
+       }
+
+       if (request_data == NULL) {
+               ioc->DiagBuffer_sz[buffer_type] = 0;
+               ioc->DiagBuffer_dma[buffer_type] = 0;
+               ioc->DataSize[buffer_type] = 0;
+               request_data = pci_alloc_consistent(
+                       ioc->pcidev, request_data_sz, &request_data_dma);
+               if (request_data == NULL) {
+                       printk(MYIOC_s_DEBUG_FMT "%s: pci_alloc_consistent"
+                           " FAILED, (request_sz=%d)\n", ioc->name,
+                           __FUNCTION__, request_data_sz);
+                       mpt_free_msg_frame(ioc, mf);
+                       return -EAGAIN;
+               }
+               ioc->DiagBuffer[buffer_type] = request_data;
+               ioc->DiagBuffer_sz[buffer_type] = request_data_sz;
+               ioc->DiagBuffer_dma[buffer_type] = request_data_dma;
+       }
+
+       ioc->DiagBuffer_Status[buffer_type] = 0;
+       diag_buffer_post_request = (DiagBufferPostRequest_t *)mf;
+       diag_buffer_post_request->Function = MPI_FUNCTION_DIAG_BUFFER_POST;
+       diag_buffer_post_request->ChainOffset = 0;
+       diag_buffer_post_request->BufferType = karg.data.BufferType;
+       diag_buffer_post_request->TraceLevel = ioc->TraceLevel[buffer_type] =
+           karg.data.TraceLevel;
+       diag_buffer_post_request->MsgFlags = 0;
+       diag_buffer_post_request->Reserved1 = 0;
+       diag_buffer_post_request->Reserved2 = 0;
+       diag_buffer_post_request->Reserved3 = 0;
+       diag_buffer_post_request->BufferAddress.High = 0;
+       if (buffer_type == MPI_DIAG_BUF_TYPE_EXTENDED)
+               ioc->ExtendedType[buffer_type] = karg.data.ExtendedType;
+       else
+               ioc->ExtendedType[buffer_type] = 0;
+       diag_buffer_post_request->ExtendedType =
+           cpu_to_le32(ioc->ExtendedType[buffer_type]);
+       ioc->UniqueId[buffer_type] = karg.data.UniqueId;
+       diag_buffer_post_request->BufferLength = cpu_to_le32(request_data_sz);
+       for (ii = 0; ii < 4; ii++) {
+               ioc->ProductSpecific[buffer_type][ii] =
+                       karg.data.ProductSpecific[ii];
+               diag_buffer_post_request->ProductSpecific[ii] =
+                       cpu_to_le32(ioc->ProductSpecific[buffer_type][ii]);
+       }
+
+       tmp = request_data_dma & 0xFFFFFFFF;
+       diag_buffer_post_request->BufferAddress.Low = cpu_to_le32(tmp);
+       if (sizeof(dma_addr_t) == sizeof(u64)) {
+               tmp = (u32)((u64)request_data_dma >> 32);
+               diag_buffer_post_request->BufferAddress.High = cpu_to_le32(tmp);
+       }
+
+       SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context,
+           diag_buffer_post_request->MsgContext);
+       INITIALIZE_MGMT_STATUS(ioc->ioctl_cmds.status)
+       mpt_put_msg_frame(mptctl_id, ioc, mf);
+       timeleft = wait_for_completion_timeout(&ioc->ioctl_cmds.done,
+           MPT_IOCTL_DEFAULT_TIMEOUT*HZ);
+       if (!(ioc->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
+               rc = -ETIME;
+               printk(MYIOC_s_WARN_FMT "%s: failed\n", ioc->name,
+                   __FUNCTION__);
+               if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) {
+                       mpt_free_msg_frame(ioc, mf);
+                       goto out;
+               }
+               if (!timeleft)
+                       mptctl_timeout_expired(ioc, mf);
+               goto out;
+       }
+
+       /* process the completed Reply Message Frame */
+       if ((ioc->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID) == 0) {
+               dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: status=%x\n",
+                   ioc->name, __FUNCTION__, ioc->ioctl_cmds.status));
+               rc = -EFAULT;
+               goto out;
+       }
+
+       diag_buffer_post_reply = (DiagBufferPostReply_t *)ioc->ioctl_cmds.reply;
+       if (le16_to_cpu(diag_buffer_post_reply->IOCStatus) ==
+           MPI_IOCSTATUS_SUCCESS) {
+               if (diag_buffer_post_reply->MsgLength > 5)
+                       ioc->DataSize[buffer_type] =
+                            le32_to_cpu(diag_buffer_post_reply->TransferLength);
+               ioc->DiagBuffer_Status[buffer_type] |=
+                       MPT_DIAG_BUFFER_IS_REGISTERED;
+       } else {
+               dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: IOCStatus=%x "
+                   "IOCLogInfo=%x\n", ioc->name, __FUNCTION__,
+                   diag_buffer_post_reply->IOCStatus,
+                   diag_buffer_post_reply->IOCLogInfo));
+               rc = -EFAULT;
+       }
+
+ out:
+
+       CLEAR_MGMT_STATUS(ioc->ioctl_cmds.status)
+       SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context, 0);
+       if (rc)
+               pci_free_consistent(ioc->pcidev, request_data_sz,
+                   request_data, request_data_dma);
+       return rc;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/* RELEASE DIAG BUFFER Routine.
+ *
+ * Outputs:    None.
+ * Return:     0 if successful
+ *             -EFAULT if data unavailable
+ *             -EBUSY  if previous command timout and IOC reset is not complete.
+ *             -ENODEV if no such device/adapter
+ *             -ETIME  if timer expires
+ *             -ENOMEM if memory allocation error
+ */
+static int
+mptctl_release_diag_buffer (unsigned long arg)
+{
+       mpt_diag_release_t      __user *uarg = (void __user *) arg;
+       mpt_diag_release_t      karg;
+       MPT_ADAPTER             *ioc;
+       void *                  request_data;
+       int                     iocnum, rc;
+       MPT_FRAME_HDR           *mf;
+       DiagReleaseRequest_t    *diag_release;
+       DiagReleaseReply_t      *diag_release_reply;
+       u8                      buffer_type;
+       unsigned long           timeleft;
+
+       rc = 0;
+       if (copy_from_user(&karg, uarg, sizeof(mpt_diag_release_t))) {
+               printk(KERN_ERR "%s@%d::%s - "
+               "Unable to read in mpt_diag_release_t struct @ %p\n",
+                   __FILE__, __LINE__, __FUNCTION__, uarg);
+               return -EFAULT;
+       }
+
+       if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
+               (ioc == NULL)) {
+               printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n",
+                   __FILE__, __FUNCTION__, __LINE__, iocnum);
+               return -ENODEV;
+       }
+
+       dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s enter.\n", ioc->name,
+               __FUNCTION__));
+       buffer_type = karg.data.UniqueId & 0x000000ff;
+       if (!(ioc->facts.IOCCapabilities & MPT_DIAG_CAPABILITY(buffer_type))) {
+               printk(MYIOC_s_DEBUG_FMT "%s: doesn't have Capability for "
+                   "buffer_type=%x\n", ioc->name, __FUNCTION__, buffer_type);
+               return -ENODEV;
+       }
+
+       if ((ioc->DiagBuffer_Status[buffer_type] &
+               MPT_DIAG_BUFFER_IS_REGISTERED) == 0 ) {
+               printk(MYIOC_s_DEBUG_FMT "%s: buffer_type=%x is not "
+                   "registered\n", ioc->name, __FUNCTION__, buffer_type);
+               return -EFAULT;
+       }
+
+       if (karg.data.UniqueId != ioc->UniqueId[buffer_type]) {
+               printk(MYIOC_s_DEBUG_FMT "%s: unique_id=%x is not registered\n",
+                   ioc->name, __FUNCTION__, karg.data.UniqueId);
+               return -EFAULT;
+       }
+
+       if (ioc->DiagBuffer_Status[buffer_type] & MPT_DIAG_BUFFER_IS_RELEASED) {
+               dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: buffer_type=%x "
+                   "is already released\n", ioc->name, __FUNCTION__,
+                   buffer_type));
+               return rc;
+       }
+
+       request_data = ioc->DiagBuffer[buffer_type];
+
+       if (request_data == NULL) {
+               printk(MYIOC_s_DEBUG_FMT "%s: doesn't have buffer for "
+                   "buffer_type=%x\n", ioc->name, __FUNCTION__, buffer_type);
+               return -ENODEV;
+       }
+
+       /* Get a free request frame and save the message context.
+        */
+       if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL)
+               return -EAGAIN;
+
+       diag_release = (DiagReleaseRequest_t *)mf;
+       diag_release->Function = MPI_FUNCTION_DIAG_RELEASE;
+       diag_release->BufferType = buffer_type;
+       diag_release->ChainOffset = 0;
+       diag_release->Reserved1 = 0;
+       diag_release->Reserved2 = 0;
+       diag_release->Reserved3 = 0;
+       diag_release->MsgFlags = 0;
+
+       SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context,
+           diag_release->MsgContext);
+       INITIALIZE_MGMT_STATUS(ioc->ioctl_cmds.status)
+       mpt_put_msg_frame(mptctl_id, ioc, mf);
+       timeleft = wait_for_completion_timeout(&ioc->ioctl_cmds.done,
+           MPT_IOCTL_DEFAULT_TIMEOUT*HZ);
+       if (!(ioc->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
+               rc = -ETIME;
+               printk(MYIOC_s_WARN_FMT "%s: failed\n", ioc->name,
+                   __FUNCTION__);
+               if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) {
+                       mpt_free_msg_frame(ioc, mf);
+                       goto out;
+               }
+               if (!timeleft)
+                       mptctl_timeout_expired(ioc, mf);
+               goto out;
+       }
+
+       /* process the completed Reply Message Frame */
+       if ((ioc->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID) == 0) {
+               dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: status=%x\n",
+                   ioc->name, __FUNCTION__, ioc->ioctl_cmds.status));
+               rc = -EFAULT;
+               goto out;
+       }
+
+       diag_release_reply = (DiagReleaseReply_t *)ioc->ioctl_cmds.reply;
+       if (le16_to_cpu(diag_release_reply->IOCStatus) !=
+           MPI_IOCSTATUS_SUCCESS) {
+               dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: IOCStatus=%x "
+                       "IOCLogInfo=%x\n",
+                   ioc->name, __FUNCTION__, diag_release_reply->IOCStatus,
+                   diag_release_reply->IOCLogInfo));
+               rc = -EFAULT;
+       } else
+               ioc->DiagBuffer_Status[buffer_type] |=
+                   MPT_DIAG_BUFFER_IS_RELEASED;
+
+ out:
+
+       CLEAR_MGMT_STATUS(ioc->ioctl_cmds.status)
+       SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context, 0);
+       return rc;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/* UNREGISTER DIAG BUFFER Routine.
+ *
+ * Outputs:    None.
+ * Return:     0 if successful
+ *             -EFAULT if data unavailable
+ *             -EBUSY  if previous command timout and IOC reset is not complete.
+ *             -ENODEV if no such device/adapter
+ *             -ETIME  if timer expires
+ *             -ENOMEM if memory allocation error
+ */
+static int
+mptctl_unregister_diag_buffer (unsigned long arg)
+{
+       mpt_diag_unregister_t   __user *uarg = (void __user *) arg;
+       mpt_diag_unregister_t   karg;
+       MPT_ADAPTER             *ioc;
+       int                     iocnum;
+       void *                  request_data;
+       dma_addr_t              request_data_dma;
+       u32                     request_data_sz;
+       u8                      buffer_type;
+
+       if (copy_from_user(&karg, uarg, sizeof(mpt_diag_unregister_t))) {
+               printk(KERN_ERR "%s@%d::%s - "
+               "Unable to read in mpt_diag_unregister_t struct @ %p\n",
+                   __FILE__, __LINE__, __FUNCTION__, uarg);
+               return -EFAULT;
+       }
+
+       if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
+               (ioc == NULL)) {
+               printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n",
+                   __FILE__, __FUNCTION__, __LINE__, iocnum);
+               return -ENODEV;
+       }
+
+       dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s enter.\n", ioc->name,
+               __FUNCTION__));
+       buffer_type = karg.data.UniqueId & 0x000000ff;
+       if (!(ioc->facts.IOCCapabilities & MPT_DIAG_CAPABILITY(buffer_type))) {
+               printk(MYIOC_s_DEBUG_FMT "%s: doesn't have Capability for "
+                   "buffer_type=%x\n", ioc->name, __FUNCTION__, buffer_type);
+               return -ENODEV;
+       }
+
+       if ((ioc->DiagBuffer_Status[buffer_type] &
+               MPT_DIAG_BUFFER_IS_REGISTERED) == 0) {
+               printk(MYIOC_s_DEBUG_FMT "%s: buffer_type=%x is not "
+                   "registered\n", ioc->name, __FUNCTION__, buffer_type);
+               return -EFAULT;
+       }
+       if ((ioc->DiagBuffer_Status[buffer_type] &
+               MPT_DIAG_BUFFER_IS_RELEASED) == 0) {
+               printk(MYIOC_s_DEBUG_FMT "%s: buffer_type=%x has not been "
+                   "released\n", ioc->name, __FUNCTION__, buffer_type);
+               return -EFAULT;
+       }
+
+       if (karg.data.UniqueId != ioc->UniqueId[buffer_type]) {
+               printk(MYIOC_s_DEBUG_FMT "%s: unique_id=%x is not registered\n",
+                   ioc->name, __FUNCTION__, karg.data.UniqueId);
+               return -EFAULT;
+       }
+
+       request_data = ioc->DiagBuffer[buffer_type];
+       if (!request_data) {
+               printk(MYIOC_s_DEBUG_FMT "%s: doesn't have buffer for "
+                   "buffer_type=%x\n", ioc->name, __FUNCTION__, buffer_type);
+               return -ENODEV;
+       }
+
+       request_data_sz = ioc->DiagBuffer_sz[buffer_type];
+       request_data_dma = ioc->DiagBuffer_dma[buffer_type];
+       pci_free_consistent(ioc->pcidev, request_data_sz,
+           request_data, request_data_dma);
+       ioc->DiagBuffer[buffer_type] = NULL;
+       ioc->DiagBuffer_Status[buffer_type] = 0;
+       return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/* QUERY DIAG BUFFER Routine.
+ *
+ * Outputs:    None.
+ * Return:     0 if successful
+ *             -EFAULT if data unavailable
+ *             -EBUSY  if previous command timout and IOC reset is not complete.
+ *             -ENODEV if no such device/adapter
+ *             -ETIME  if timer expires
+ *             -ENOMEM if memory allocation error
+ */
+static int
+mptctl_query_diag_buffer (unsigned long arg)
+{
+       mpt_diag_query_t        __user *uarg = (void __user *)arg;
+       mpt_diag_query_t        karg;
+       MPT_ADAPTER             *ioc;
+       void *                  request_data;
+       int                     iocnum, ii, rc;
+       u8                      buffer_type;
+
+       rc = -EFAULT;
+       if (copy_from_user(&karg, uarg, sizeof(mpt_diag_query_t))) {
+               printk(KERN_ERR "%s@%d::%s - "
+               "Unable to read in mpt_diag_query_t struct @ %p\n",
+                   __FILE__, __LINE__, __FUNCTION__, uarg);
+               return -EFAULT;
+       }
+
+       karg.data.Flags = 0;
+       if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
+               (ioc == NULL)) {
+               printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n",
+                   __FILE__, __FUNCTION__, __LINE__, iocnum);
+               goto out;
+       }
+
+       dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s enter.\n", ioc->name,
+               __FUNCTION__));
+       buffer_type = karg.data.BufferType;
+       if (!(ioc->facts.IOCCapabilities & MPT_DIAG_CAPABILITY(buffer_type))) {
+               printk(MYIOC_s_DEBUG_FMT "%s: doesn't have Capability for "
+                   "buffer_type=%x\n", ioc->name, __FUNCTION__, buffer_type);
+               goto out;
+       }
+
+       if ((ioc->DiagBuffer_Status[buffer_type] &
+               MPT_DIAG_BUFFER_IS_REGISTERED) == 0) {
+               printk(MYIOC_s_DEBUG_FMT "%s: buffer_type=%x is not "
+                   "registered\n", ioc->name, __FUNCTION__, buffer_type);
+               goto out;
+       }
+
+       if (karg.data.UniqueId & 0xffffff00) {
+               if (karg.data.UniqueId != ioc->UniqueId[buffer_type]) {
+                       printk(MYIOC_s_DEBUG_FMT "%s: unique_id=%x is not "
+                           "registered\n", ioc->name, __FUNCTION__,
+                           karg.data.UniqueId);
+                       goto out;
+               }
+       }
+
+       request_data = ioc->DiagBuffer[buffer_type];
+       if (!request_data) {
+               printk(MYIOC_s_DEBUG_FMT "%s: doesn't have buffer for "
+                   "buffer_type=%x\n", ioc->name, __FUNCTION__, buffer_type);
+               goto out;
+       }
+       
+       rc = 0;
+       if (buffer_type == MPI_DIAG_BUF_TYPE_EXTENDED) {
+               if (karg.data.ExtendedType != ioc->ExtendedType[buffer_type])
+                       goto out;
+       } else
+               karg.data.ExtendedType = 0;
+
+       if (ioc->DiagBuffer_Status[buffer_type] & MPT_DIAG_BUFFER_IS_RELEASED)
+               karg.data.Flags = 3;
+       else
+               karg.data.Flags = 7;
+       karg.data.TraceLevel = ioc->TraceLevel[buffer_type];
+       for (ii = 0; ii < 4; ii++)
+               karg.data.ProductSpecific[ii] =
+                   ioc->ProductSpecific[buffer_type][ii];
+       karg.data.DataSize = ioc->DiagBuffer_sz[buffer_type];
+       karg.data.DriverAddedBufferSize = 0;
+       karg.data.UniqueId = ioc->UniqueId[buffer_type];
+
+ out:
+       if (copy_to_user(uarg, &karg, sizeof(mpt_diag_query_t))) {
+               printk(MYIOC_s_ERR_FMT "%s Unable to write mpt_diag_query_t "
+                   "data @ %p\n", ioc->name, __FUNCTION__, uarg);
+               return -EFAULT;
+       }
+       return rc;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/* READ DIAG BUFFER Routine.
+ *
+ * Outputs:    None.
+ * Return:     0 if successful
+ *             -EFAULT if data unavailable
+ *             -EBUSY  if previous command timout and IOC reset is not complete.
+ *             -ENODEV if no such device/adapter
+ *             -ETIME  if timer expires
+ *             -ENOMEM if memory allocation error
+ */
+static int
+mptctl_read_diag_buffer (unsigned long arg)
+{
+       mpt_diag_read_buffer_t  __user *uarg = (void __user *) arg;
+       mpt_diag_read_buffer_t  karg;
+       MPT_ADAPTER             *ioc;
+       void                    *request_data, *diagData;
+       dma_addr_t              request_data_dma;
+       DiagBufferPostRequest_t *diag_buffer_post_request;
+       DiagBufferPostReply_t   *diag_buffer_post_reply;
+       MPT_FRAME_HDR           *mf;
+       int                     iocnum, rc, ii;
+       u8                      buffer_type;
+       u32                     tmp;
+       unsigned long           timeleft;
+
+       rc = 0;
+       if (copy_from_user(&karg, uarg, sizeof(mpt_diag_read_buffer_t))) {
+               printk(KERN_ERR "%s@%d::%s - "
+               "Unable to read in mpt_diag_read_buffer_t struct @ %p\n",
+                   __FILE__, __LINE__, __FUNCTION__, uarg);
+               return -EFAULT;
+       }
+
+       if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
+               (ioc == NULL)) {
+               printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n",
+                   __FILE__, __FUNCTION__, __LINE__, iocnum);
+               return -ENODEV;
+       }
+
+       dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s enter.\n", ioc->name,
+           __FUNCTION__));
+       buffer_type = karg.data.UniqueId & 0x000000ff;
+       if (!(ioc->facts.IOCCapabilities & MPT_DIAG_CAPABILITY(buffer_type))) {
+               printk(MYIOC_s_DEBUG_FMT "%s: doesn't have Capability "
+                   "for buffer_type=%x\n", ioc->name, __FUNCTION__,
+                   buffer_type);
+               return -EFAULT;
+       }
+
+       if (karg.data.UniqueId != ioc->UniqueId[buffer_type]) {
+               printk(MYIOC_s_DEBUG_FMT "%s: unique_id=%x is not registered\n",
+                   ioc->name, __FUNCTION__, karg.data.UniqueId);
+               return -EFAULT;
+       }
+
+       request_data = ioc->DiagBuffer[buffer_type];
+       if (!request_data) {
+               printk(MYIOC_s_DEBUG_FMT "%s: doesn't have buffer for "
+                   "buffer_type=%x\n", ioc->name, __FUNCTION__, buffer_type);
+               return -EFAULT;
+       }
+
+       diagData = (void *)(request_data + karg.data.StartingOffset);
+       dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: diagData=%p "
+           "request_data=%p StartingOffset=%x\n", ioc->name, __FUNCTION__,
+           diagData, request_data, karg.data.StartingOffset));
+
+       if (copy_to_user((void __user *)&uarg->data.DiagnosticData[0],
+           diagData, karg.data.BytesToRead)) {
+               printk(MYIOC_s_ERR_FMT "%s: Unable to write "
+                   "mpt_diag_read_buffer_t data @ %p\n", ioc->name,
+                   __FUNCTION__, diagData);
+               return -EFAULT;
+       }
+
+       if ((karg.data.Flags & MPI_FW_DIAG_FLAG_REREGISTER) == 0)
+               goto out;
+
+       dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: Reregister "
+               "buffer_type=%x\n", ioc->name, __FUNCTION__, buffer_type));
+       if ((ioc->DiagBuffer_Status[buffer_type] &
+           MPT_DIAG_BUFFER_IS_RELEASED) == 0) {
+               dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: buffer_type=%x "
+                   "is still registered\n", ioc->name, __FUNCTION__,
+                   buffer_type));
+               return rc;
+       }
+       /* Get a free request frame and save the message context.
+       */
+       if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL)
+               return -EAGAIN;
+
+       diag_buffer_post_request = (DiagBufferPostRequest_t *)mf;
+       diag_buffer_post_request->Function = MPI_FUNCTION_DIAG_BUFFER_POST;
+       diag_buffer_post_request->ChainOffset = 0;
+       diag_buffer_post_request->BufferType = buffer_type;
+       diag_buffer_post_request->TraceLevel =
+               ioc->TraceLevel[buffer_type];
+       diag_buffer_post_request->MsgFlags = 0;
+       diag_buffer_post_request->Reserved1 = 0;
+       diag_buffer_post_request->Reserved2 = 0;
+       diag_buffer_post_request->Reserved3 = 0;
+       diag_buffer_post_request->BufferAddress.High = 0;
+       if ( buffer_type == MPI_DIAG_BUF_TYPE_EXTENDED )
+               diag_buffer_post_request->ExtendedType =
+                       cpu_to_le32(ioc->ExtendedType[buffer_type]);
+       diag_buffer_post_request->BufferLength =
+           cpu_to_le32(ioc->DiagBuffer_sz[buffer_type]);
+       for (ii = 0; ii < 4; ii++)
+               diag_buffer_post_request->ProductSpecific[ii] =
+                   cpu_to_le32(ioc->ProductSpecific[buffer_type][ii]);
+       request_data_dma = ioc->DiagBuffer_dma[buffer_type];
+       tmp = request_data_dma & 0xFFFFFFFF;
+       diag_buffer_post_request->BufferAddress.Low = cpu_to_le32(tmp);
+       if (sizeof(dma_addr_t) == sizeof(u64)) {
+               tmp = (u32)((u64)request_data_dma >> 32);
+               diag_buffer_post_request->BufferAddress.High = cpu_to_le32(tmp);
+       }
+
+       SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context,
+           diag_buffer_post_request->MsgContext);
+       INITIALIZE_MGMT_STATUS(ioc->ioctl_cmds.status)
+       mpt_put_msg_frame(mptctl_id, ioc, mf);
+       timeleft = wait_for_completion_timeout(&ioc->ioctl_cmds.done,
+           MPT_IOCTL_DEFAULT_TIMEOUT*HZ);
+       if (!(ioc->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
+               rc = -ETIME;
+               printk(MYIOC_s_WARN_FMT "%s: failed\n", ioc->name,
+                   __FUNCTION__);
+               if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) {
+                       mpt_free_msg_frame(ioc, mf);
+                       goto out;
+               }
+               if (!timeleft)
+                       mptctl_timeout_expired(ioc, mf);
+               goto out;
+       }
+
+       /* process the completed Reply Message Frame */
+       if ((ioc->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID) == 0) {
+               dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: status=%x\n",
+                   ioc->name, __FUNCTION__, ioc->ioctl_cmds.status));
+               rc = -EFAULT;
+       }
+
+       diag_buffer_post_reply = (DiagBufferPostReply_t *)ioc->ioctl_cmds.reply;
+       if (le16_to_cpu(diag_buffer_post_reply->IOCStatus) ==
+           MPI_IOCSTATUS_SUCCESS) {
+               if (diag_buffer_post_reply->MsgLength > 5)
+                       ioc->DataSize[buffer_type] =
+                           le32_to_cpu(diag_buffer_post_reply->TransferLength);
+               ioc->DiagBuffer_Status[buffer_type] |=
+                   MPT_DIAG_BUFFER_IS_REGISTERED;
+       } else {
+               dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: IOCStatus=%x "
+                   "IOCLogInfo=%x\n", ioc->name, __FUNCTION__,
+                   diag_buffer_post_reply->IOCStatus,
+                   diag_buffer_post_reply->IOCLogInfo));
+               rc = -EFAULT;
+       }
+
+ out:
+       CLEAR_MGMT_STATUS(ioc->ioctl_cmds.status)
+       SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context, 0);
+       return rc;
+}
diff --git a/drivers/message/fusion/rejected_ioctls/diag_buffer.h b/drivers/message/fusion/rejected_ioctls/diag_buffer.h
new file mode 100644 (file)
index 0000000..aa82990
--- /dev/null
@@ -0,0 +1,101 @@
+#define MPTDIAGREGISTER                                _IOWR(MPT_MAGIC_NUMBER,26,mpt_diag_register_t)
+#define MPTDIAGRELEASE                         _IOWR(MPT_MAGIC_NUMBER,27,mpt_diag_release_t)
+#define MPTDIAGUNREGISTER                      _IOWR(MPT_MAGIC_NUMBER,28,mpt_diag_unregister_t)
+#define MPTDIAGQUERY                           _IOWR(MPT_MAGIC_NUMBER,29,mpt_diag_query_t)
+#define MPTDIAGREADBUFFER                      _IOWR(MPT_MAGIC_NUMBER,30,mpt_diag_read_buffer_t)
+
+#define MPI_FW_DIAG_IOCTL                      (0x80646961)
+#define MPI_FW_DIAG_TYPE_REGISTER              (0x00000001)
+#define MPI_FW_DIAG_TYPE_UNREGISTER            (0x00000002)
+#define MPI_FW_DIAG_TYPE_QUERY                 (0x00000003)
+#define MPI_FW_DIAG_TYPE_READ_BUFFER           (0x00000004)
+#define MPI_FW_DIAG_TYPE_RELEASE               (0x00000005)
+
+#define MPI_FW_DIAG_INVALID_UID                        (0x00000000)
+#define FW_DIAGNOSTIC_BUFFER_COUNT             (3)
+#define FW_DIAGNOSTIC_UID_NOT_FOUND            (0xFF)
+
+#define MPI_FW_DIAG_ERROR_SUCCESS              (0x00000000)
+#define MPI_FW_DIAG_ERROR_FAILURE              (0x00000001)
+#define MPI_FW_DIAG_ERROR_INVALID_PARAMETER    (0x00000002)
+#define MPI_FW_DIAG_ERROR_POST_FAILED          (0x00000010)
+#define MPI_FW_DIAG_ERROR_INVALID_UID          (0x00000011)
+
+#define MPI_FW_DIAG_ERROR_RELEASE_FAILED       (0x00000012)
+#define MPI_FW_DIAG_ERROR_NO_BUFFER            (0x00000013)
+#define MPI_FW_DIAG_ERROR_ALREADY_RELEASED     (0x00000014)
+
+#define MPT_DIAG_CAPABILITY(bufftype)  (MPI_IOCFACTS_CAPABILITY_DIAG_TRACE_BUFFER << bufftype)
+
+#define MPT_DIAG_BUFFER_IS_REGISTERED          1
+#define MPT_DIAG_BUFFER_IS_RELEASED            2
+
+typedef struct _MPI_FW_DIAG_REGISTER {
+       u8                      TraceLevel;
+       u8                      BufferType;
+       u16                     Flags;
+       u32                     ExtendedType;
+       u32                     ProductSpecific[4];
+       u32                     RequestedBufferSize;
+       u32                     UniqueId;
+} MPI_FW_DIAG_REGISTER, *PTR_MPI_FW_DIAG_REGISTER;
+
+typedef struct _mpt_diag_register {
+       mpt_ioctl_header        hdr;
+       MPI_FW_DIAG_REGISTER    data;
+} mpt_diag_register_t;
+
+typedef struct _MPI_FW_DIAG_UNREGISTER {
+       u32                     UniqueId;
+} MPI_FW_DIAG_UNREGISTER, *PTR_MPI_FW_DIAG_UNREGISTER;
+
+typedef struct _mpt_diag_unregister {
+       mpt_ioctl_header         hdr;
+       MPI_FW_DIAG_UNREGISTER  data;
+} mpt_diag_unregister_t;
+
+#define MPI_FW_DIAG_FLAG_APP_OWNED          (0x0001)
+#define MPI_FW_DIAG_FLAG_BUFFER_VALID       (0x0002)
+#define MPI_FW_DIAG_FLAG_FW_BUFFER_ACCESS   (0x0004)
+
+typedef struct _MPI_FW_DIAG_QUERY {
+       u8                      TraceLevel;
+       u8                      BufferType;
+       u16                     Flags;
+       u32                     ExtendedType;
+       u32                     ProductSpecific[4];
+       u32                     DataSize;
+       u32                     DriverAddedBufferSize;
+       u32                     UniqueId;
+} MPI_FW_DIAG_QUERY, *PTR_MPI_FW_DIAG_QUERY;
+
+typedef struct _mpt_diag_query {
+       mpt_ioctl_header        hdr;
+       MPI_FW_DIAG_QUERY       data;
+} mpt_diag_query_t;
+
+typedef struct _MPI_FW_DIAG_RELEASE {
+       u32                     UniqueId;
+} MPI_FW_DIAG_RELEASE, *PTR_MPI_FW_DIAG_RELEASE;
+
+typedef struct _mpt_diag_release {
+       mpt_ioctl_header        hdr;
+       MPI_FW_DIAG_RELEASE     data;
+} mpt_diag_release_t;
+
+#define MPI_FW_DIAG_FLAG_REREGISTER         (0x0001)
+
+typedef struct _MPI_FW_DIAG_READ_BUFFER {
+       u8                      Status;
+       u8                      Reserved;
+       u16                     Flags;
+       u32                     StartingOffset;
+       u32                     BytesToRead;
+       u32                     UniqueId;
+       u32                     DiagnosticData[1];
+} MPI_FW_DIAG_READ_BUFFER, *PTR_MPI_FW_DIAG_READ_BUFFER;
+
+typedef struct _mpt_diag_read_buffer {
+       mpt_ioctl_header        hdr;
+       MPI_FW_DIAG_READ_BUFFER data;
+} mpt_diag_read_buffer_t;