LSI/MPT target driver added
authorvlnb <vlnb@d57e44dd-8a1f-0410-8b47-8ef2f437770f>
Wed, 13 Dec 2006 11:42:59 +0000 (11:42 +0000)
committervlnb <vlnb@d57e44dd-8a1f-0410-8b47-8ef2f437770f>
Wed, 13 Dec 2006 11:42:59 +0000 (11:42 +0000)
git-svn-id: https://scst.svn.sourceforge.net/svnroot/scst/trunk@49 d57e44dd-8a1f-0410-8b47-8ef2f437770f

Makefile
mpt/Kconfig [new file with mode: 0644]
mpt/Makefile [new file with mode: 0644]
mpt/README [new file with mode: 0644]
mpt/in-tree/Kconfig.diff [new file with mode: 0644]
mpt/in-tree/Makefile.diff [new file with mode: 0644]
mpt/mpt_scst.c [new file with mode: 0644]
mpt/mpt_scst.h [new file with mode: 0644]
mpt/scsi3.h [new file with mode: 0644]
scst/kernel/in-tree/Makefile.scsi.Linux-2.6.15.patch [new file with mode: 0644]
scst/src/Makefile

index f22419d..dfecb95 100644 (file)
--- a/Makefile
+++ b/Makefile
 SCST_DIR=scst
 QLA_INI_DIR=qla2x00t
 QLA_DIR=qla2x00t/qla2x00-target
+LSI_DIR=mpt
 
 all:
        cd $(SCST_DIR) && $(MAKE) $@
        @if [ -d $(QLA_DIR) ]; then cd $(QLA_DIR) && $(MAKE) $@; fi
+       @if [ -d $(LSI_DIR) ]; then cd $(LSI_DIR) && $(MAKE) $@; fi
 
 install: 
        cd $(SCST_DIR) && $(MAKE) $@
        @if [ -d $(QLA_DIR) ]; then cd $(QLA_DIR) && $(MAKE) $@; fi
+       @if [ -d $(LSI_DIR) ]; then cd $(LSI_DIR) && $(MAKE) $@; fi
 
 uninstall: 
        cd $(SCST_DIR) && $(MAKE) $@
        @if [ -d $(QLA_DIR) ]; then cd $(QLA_DIR) && $(MAKE) $@; fi
+       @if [ -d $(LSI_DIR) ]; then cd $(LSI_DIR) && $(MAKE) $@; fi
 
 clean: 
        cd $(SCST_DIR) && $(MAKE) $@
        @if [ -d $(QLA_INI_DIR) ]; then cd $(QLA_INI_DIR) && $(MAKE) $@; fi
        @if [ -d $(QLA_DIR) ]; then cd $(QLA_DIR) && $(MAKE) $@; fi
+       @if [ -d $(LSI_DIR) ]; then cd $(LSI_DIR) && $(MAKE) $@; fi
 
 extraclean: 
        cd $(SCST_DIR) && $(MAKE) $@
        @if [ -d $(QLA_INI_DIR) ]; then cd $(QLA_INI_DIR) && $(MAKE) $@; fi
        @if [ -d $(QLA_DIR) ]; then cd $(QLA_DIR) && $(MAKE) $@; fi
+       @if [ -d $(LSI_DIR) ]; then cd $(LSI_DIR) && $(MAKE) $@; fi
 
 scst: 
        cd $(SCST_DIR) && $(MAKE)
@@ -76,6 +82,21 @@ qla_extraclean:
        cd $(QLA_INI_DIR)/.. && $(MAKE) extraclean
        cd $(QLA_DIR) && $(MAKE) extraclean
 
+lsi:
+       cd $(LSI_DIR) && $(MAKE)
+
+lsi_install:
+       cd $(LSI_DIR) && $(MAKE) install
+
+lsi_uninstall:
+       cd $(LSI_DIR) && $(MAKE) uninstall
+
+lsi_clean: 
+       cd $(LSI_DIR) && $(MAKE) clean
+
+lsi_extraclean:
+       cd $(LSI_DIR) && $(MAKE) extraclean
+
 help:
        @echo "         all (the default) : make all"
        @echo "         clean             : clean files"
@@ -94,9 +115,16 @@ help:
        @echo "         qla_extraclean  : 2.6 qla target: clean + clean dependencies"
        @echo "         qla_install     : 2.6 qla target: install"
        @echo "         qla_uninstall   : 2.6 qla target: uninstall"
+       @echo ""
+       @echo "         lsi             : make lsi target"
+       @echo "         lsi_clean       : lsi target: clean "
+       @echo "         lsi_extraclean  : lsi target: clean + clean dependencies"
+       @echo "         lsi_install     : lsi target: install"
+       @echo "         lsi_uninstall   : lsi target: uninstall"
        @echo " Notes :"
        @echo "         - install and uninstall must be made as root"
 
 .PHONY: all install uninstall clean extraclean help \
        qla qla_install qla_uninstall qla_clean qla_extraclean \
+       lsi lsi_install lsi_uninstall lsi_clean lsi_extraclean \
        scst scst_install scst_uninstall scst_clean scst_extraclean
diff --git a/mpt/Kconfig b/mpt/Kconfig
new file mode 100644 (file)
index 0000000..0309760
--- /dev/null
@@ -0,0 +1,10 @@
+
+config FUSION_SCST
+       tristate "Fusion MPT SCST driver"
+       depends on FUSION
+       ---help---
+         This module enables target mode for use by the SCST middle
+         level drivers.  You will also need the SCST middle level
+         drivers from http://scst.sf.net/.
+
+         If unsure whether you really want or need this, say N.
diff --git a/mpt/Makefile b/mpt/Makefile
new file mode 100644 (file)
index 0000000..cbc5d6b
--- /dev/null
@@ -0,0 +1,90 @@
+#  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.
+#
+#
+# Main targets:
+#    all (the default) : make all
+#    clean             : clean files
+#    extraclean        : clean + clean dependencies
+#    install           : install 
+#    uninstall         : uninstall 
+#
+# Notes :
+#    - install and uninstall must be made as root
+#
+
+#SCST_INC_DIR := /usr/local/include/scst
+#SCST_DIR := $(SCST_INC_DIR)
+SCST_INC_DIR := $(SUBDIRS)/../scst/include
+SCST_DIR := $(shell pwd)/../scst/src
+
+EXTRA_CFLAGS += -I$(SCST_INC_DIR)
+
+EXTRA_CFLAGS += -DEXTRACHECKS 
+#EXTRA_CFLAGS += -DTRACING
+#EXTRA_CFLAGS += -DDEBUG
+#EXTRA_CFLAGS += -DDEBUG_WORK_IN_THREAD
+
+ifeq ($(KVER),)
+  ifeq ($(KDIR),)
+    KDIR := /lib/modules/$(shell uname -r)/build
+  endif
+else
+  KDIR := /lib/modules/$(KVER)/build
+endif
+
+LSI_INC_DIR := $(KDIR)/drivers/message/fusion
+EXTRA_CFLAGS += -I$(LSI_INC_DIR)
+
+ifneq ($(KERNELRELEASE),)
+obj-m := mpt_scst.o
+
+else
+
+all: Modules.symvers Module.symvers
+       $(MAKE) -C $(KDIR) SUBDIRS=$(shell pwd) BUILD_INI=m
+
+tgt: Modules.symvers Module.symvers
+       $(MAKE) -C $(KDIR) SUBDIRS=$(shell pwd) BUILD_INI=n
+
+install: all
+       $(MAKE) -C $(KDIR) SUBDIRS=$(shell pwd) BUILD_INI=m \
+               modules_install
+       -depmod -a
+
+SCST_MOD_VERS := $(shell ls $(SCST_DIR)/Modules.symvers 2>/dev/null)
+ifneq ($(SCST_MOD_VERS),)
+Modules.symvers: $(SCST_DIR)/Modules.symvers
+       cp $(SCST_DIR)/Modules.symvers .
+else
+.PHONY: Modules.symvers
+endif
+
+# It's renamed in 2.6.18
+SCST_MOD_VERS := $(shell ls $(SCST_DIR)/Module.symvers 2>/dev/null)
+ifneq ($(SCST_MOD_VERS),)
+Module.symvers: $(SCST_DIR)/Module.symvers
+       cp $(SCST_DIR)/Module.symvers .
+else
+.PHONY: Module.symvers
+endif
+
+uninstall:
+       rm -f $(INSTALL_DIR)/mpt_scst.ko
+       -/sbin/depmod -a
+endif
+
+clean:
+       rm -f *.o *.ko .*.cmd *.mod.c .*.d .depend *~ Modules.symvers Module.symvers
+       rm -rf .tmp_versions
+
+extraclean: clean
+
+.PHONY: all tgt install uninstall clean extraclean
diff --git a/mpt/README b/mpt/README
new file mode 100644 (file)
index 0000000..925cf14
--- /dev/null
@@ -0,0 +1,12 @@
+Target driver for LSI/MPT XXX cards
+===================================
+
+Version X.X.X, XX XXX 200X
+--------------------------
+
+This driver was originally developed by Hu Gang and then is developed by
+Erik Habbinga <erikhabbinga@inphase-tech.com>. It is on the early stage
+of development.
+
+The current maintainer of this driver is Erik. Please send him all
+question related to it (CC: scst-devel@lists.sourceforge.net).
diff --git a/mpt/in-tree/Kconfig.diff b/mpt/in-tree/Kconfig.diff
new file mode 100644 (file)
index 0000000..1f611f6
--- /dev/null
@@ -0,0 +1,10 @@
+--- Kconfig_orig       2006-03-05 22:07:54.000000000 +0300
++++ Kconfig    2006-12-13 13:00:41.000000000 +0300
+@@ -100,4 +100,7 @@
+         If unsure whether you really want or need this, say N.
++config FUSION_SCST
++      source "drivers/message/fusion/mpt_scst/Kconfig"
++
+ endmenu
diff --git a/mpt/in-tree/Makefile.diff b/mpt/in-tree/Makefile.diff
new file mode 100644 (file)
index 0000000..cd2ad39
--- /dev/null
@@ -0,0 +1,30 @@
+--- Makefile_orig      2006-03-05 22:07:54.000000000 +0300
++++ Makefile   2006-12-13 14:11:52.000000000 +0300
+@@ -8,7 +8,6 @@
+ #EXTRA_CFLAGS += -DMPT_DEBUG_EXIT
+ #EXTRA_CFLAGS += -DMPT_DEBUG_FAIL
+-
+ #
+ # driver/module specifics...
+ #
+@@ -30,9 +29,19 @@
+ #CFLAGS_mptctl.o += -DMPT_DEBUG_IOCTL
+ #
++SCST_INC_DIR := /usr/local/include/scst
++SCST_DIR := $(SCST_INC_DIR)
++
++CFLAGS_mpt_scst.o += -I$(SCST_INC_DIR) -I$(src)
++CFLAGS_mpt_scst.o += -DEXTRACHECKS
++#CFLAGS_mpt_scst.o += -DTRACING
++#CFLAGS_mpt_scst.o += -DDEBUG
++#CFLAGS_mpt_scst.o += -DDEBUG_WORK_IN_THREAD
++
+ #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-} LSI_LOGIC
+ obj-$(CONFIG_FUSION_SPI)      += mptbase.o mptscsih.o mptspi.o
++obj-$(CONFIG_FUSION_SCST)     += mpt_scst/mpt_scst.o
+ obj-$(CONFIG_FUSION_FC)               += mptbase.o mptscsih.o mptfc.o
+ obj-$(CONFIG_FUSION_SAS)      += mptbase.o mptscsih.o mptsas.o
+ obj-$(CONFIG_FUSION_CTL)      += mptctl.o
diff --git a/mpt/mpt_scst.c b/mpt/mpt_scst.c
new file mode 100644 (file)
index 0000000..95ad7b0
--- /dev/null
@@ -0,0 +1,5241 @@
+/*
+ *  mpt_scst.c
+ *
+ *  Copyright (C) 2005 Beijing Soul Technology Co., Ltd.
+ *  Copyright (C) 2002, 2003, 2004 LSI Logic Corporation
+ *  Copyright (C) 2004 Vladislav Bolkhovitin <vst@vlnb.net>
+ *                and Leonid Stoljar
+ *
+ *  MPT SCSI target mode driver for SCST.
+ * 
+ *  Originally   By: Stephen Shirron
+ *  Port to SCST By: Hu Gang <hugang@soulinfo.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; either version 2
+ *  of the License, or (at your option) any later version.
+ * 
+ *  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.
+ *
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/version.h>
+#include <linux/blkdev.h>
+#include <linux/interrupt.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_host.h>
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
+#include <linux/pci.h>
+#endif
+
+#include "scsi_tgt.h"
+
+#include <scst_debug.h>
+
+#include <scst_debug.c>
+#include <linux/proc_fs.h>
+
+#include "mpt_scst.h"
+
+#define MYNAM "mpt_scst"
+
+#ifdef TRACING
+static int trace_mpi = 0;
+
+#define TRACE_MPI      0x80000000
+
+static char *mpt_state_string[] = {
+       "0",
+       "new",
+       "need data",
+       "data in",
+       "data out",
+       "processed",
+       "NULL",
+};
+#endif
+
+static MPT_STM_PRIV *mpt_stm_priv[MPT_MAX_ADAPTERS+1];
+
+static int set_aliases_in_fcportpage1 = 1;
+static int num_aliases = 0;
+static int stm_context = 0;
+
+static int mpt_stm_adapter_online(MPT_STM_PRIV *priv);
+static void mpt_stm_adapter_dispose(MPT_STM_PRIV *priv);
+static int mpt_stm_adapter_install(MPT_ADAPTER *ioc);
+
+static int __init _mpt_stm_init(void);
+
+static void stmapp_set_status(MPT_STM_PRIV *priv, CMD *cmd, int status);
+static void stmapp_tgt_command(MPT_STM_PRIV *priv, u32 reply_word);
+static void stm_cmd_buf_post(MPT_STM_PRIV *priv, int index);
+
+static void stm_tgt_reply_high_pri(MPT_ADAPTER *ioc, 
+               TargetCmdBufferPostErrorReply_t *rep);
+static void stm_target_reply_error(MPT_ADAPTER *ioc, TargetErrorReply_t *rep);
+static void stmapp_target_error(MPT_STM_PRIV *priv, u32 reply_word, int index,
+               int status, int reason);
+static void stm_link_service_reply(MPT_ADAPTER *ioc,
+                      LinkServiceBufferPostReply_t *rep);
+static void stm_link_service_rsp_reply(MPT_ADAPTER *ioc,
+                          LinkServiceRspRequest_t *req, LinkServiceRspReply_t *rep);
+static void stmapp_set_sense_info(MPT_STM_PRIV *priv,
+                     CMD *cmd, int sense_key, int asc, int ascq);
+static void stmapp_srr_adjust_offset(MPT_STM_PRIV *priv, int index);
+static void stmapp_srr_convert_ta_to_tss(MPT_STM_PRIV *priv, int index);
+static void stmapp_abts_process(MPT_STM_PRIV *priv,
+                   int rx_id, LinkServiceBufferPostReply_t *rep, int index);
+static int stm_do_config_action(MPT_STM_PRIV *priv,
+                    int action, int type, int number, int address, int length,
+                    int sleep);
+static int stm_get_config_page(MPT_STM_PRIV *priv,
+                   int type, int number, int address, int sleep);
+static int stm_set_config_page(MPT_STM_PRIV *priv,
+                   int type, int number, int address, int sleep);
+static void stm_cmd_buf_post_list(MPT_STM_PRIV *priv, int index);
+static int stm_send_target_status(MPT_STM_PRIV *priv,
+                      u32 reply_word, int index, int flags, int lun, int tag);
+static void stm_send_els(MPT_STM_PRIV *priv, LinkServiceBufferPostReply_t *rep,
+            int index, int length);
+static void stm_link_serv_buf_post(MPT_STM_PRIV *priv, int index);
+
+static void stm_wait(MPT_STM_PRIV *priv, int milliseconds, int sleep);
+static int stm_wait_for(MPT_STM_PRIV *priv, volatile int *flag, int seconds,
+            int sleep);
+static void stmapp_srr_process(MPT_STM_PRIV *priv, int rx_id, int r_ctl, 
+               u32 offset, LinkServiceBufferPostReply_t *rep, int index);
+
+static int
+mpt_proc_read(char *buffer, char **start, off_t offset, int length, int *eof,
+               struct scst_tgt *scst_tgt)
+{
+       struct mpt_tgt *tgt = scst_tgt_get_tgt_priv(scst_tgt);
+       MPT_ADAPTER *ioc = tgt->priv->ioc;
+       int res = 0, len = 0;
+       MPT_STM_PRIV *priv = tgt->priv;
+
+       TRACE_ENTRY();
+       TRACE_DBG("res %d, buffer %p, length %d, %d, priv %p, tgt %p", 
+                       res, buffer, length, len, priv, tgt); 
+
+       BUG_ON(tgt == NULL);
+       BUG_ON(ioc == NULL);
+
+       len = snprintf(buffer, length,
+                       "ProductID        :0x%04x (%s)\n"
+                       "Target Enable    :%s\n",
+                       ioc->facts.ProductID,
+                       ioc->prod_name,
+                       tgt->target_enable ? "True" : "False");
+#define LEN_CHECK(res, buffer, length) \
+       TRACE_DBG("res %d, buffer %p, length %d, %d", res, buffer, length, len); \
+       res += len; buffer += len; length -= len; \
+       if (length <= 0) goto out;
+
+       LEN_CHECK(res, buffer, length)
+
+       if (ioc->bus_type == SCSI) {
+               int i = 0;
+               len = snprintf(buffer, length, 
+                               "Target ID        :%d\n"
+                               "Capabilities     :0x%x\n"
+                               "PhysicalInterface:0x%x\n",
+                               tgt->target_id,
+                               priv->SCSIPortPage0.Capabilities,
+                               priv->SCSIPortPage0.PhysicalInterface);
+               LEN_CHECK(res, buffer, length)
+
+               len = snprintf(buffer, length,
+                               "Configuration    :0x%x\n"
+                               "OnBusTimerValue  :0x%x\n"
+                               "TargetConfig     :0x%x\n"
+                               "IDConfig         :0x%x\n",
+                               priv->SCSIPortPage1.Configuration,
+                               priv->SCSIPortPage1.OnBusTimerValue,
+                               priv->SCSIPortPage1.TargetConfig,
+                               priv->SCSIPortPage1.IDConfig);
+               LEN_CHECK(res, buffer, length);
+
+               len = snprintf(buffer, length,
+                               "PortFlags        :0x%x\n"
+                               "PortSettings     :0x%x\n",
+                               priv->SCSIPortPage2.PortFlags,
+                               priv->SCSIPortPage2.PortSettings);
+               LEN_CHECK(res, buffer, length);
+#if 0
+               for (i = 0; i < 16; i++) {
+                       len = snprintf(buffer, length,
+                                       " DeviceSeting %02d: 0x%x 0x%x 0x%x\n",
+                                       priv->SCSIPortPage2.DeviceSettings[i].Timeout,
+                                       priv->SCSIPortPage2.DeviceSettings[i].SyncFactor,
+                                       priv->SCSIPortPage2.DeviceSettings[i].DeviceFlags);
+                       LEN_CHECK(res, buffer, length);
+               }
+#endif
+               for (i = 0; i < NUM_SCSI_DEVICES; i++) {
+                       len = snprintf(buffer, length, 
+                                       "  Device %02d: 0x%x, 0x%x\n",
+                                       i,
+                                       priv->SCSIDevicePage1[i].RequestedParameters,
+                                       priv->SCSIDevicePage1[i].Configuration);
+                       LEN_CHECK(res, buffer, length);
+               }
+       }
+
+       if (ioc->bus_type == FC) {
+               len = snprintf(buffer, length,
+                               "WWN              :%08X%08X:%08X%08X\n",
+                               ioc->fc_port_page0[0].WWNN.High,
+                               ioc->fc_port_page0[0].WWNN.Low,
+                               ioc->fc_port_page0[0].WWPN.High,
+                               ioc->fc_port_page0[0].WWPN.Low);
+               LEN_CHECK(res, buffer, length);
+       }
+#undef LEN_CHECK
+out:
+       TRACE_EXIT_RES(res);
+
+       return res;
+}
+
+static int
+mpt_proc_write(struct file *file, const char *buf, unsigned long length, 
+               struct scst_tgt *scst_tgt)
+{
+
+       struct mpt_tgt *tgt = scst_tgt_get_tgt_priv(scst_tgt);
+       MPT_ADAPTER *ioc = tgt->priv->ioc;
+       int res = 0;
+       char tmp[32+1];
+
+       TRACE_ENTRY();
+       res = min(32, (int)length);
+       memcpy(tmp, buf, res);
+       tmp[res] = 0;
+
+       TRACE_DBG("buff '%s'", tmp);
+       if (strncmp("target:enable", tmp, strlen("target:enable")) == 0) {
+               TRACE_DBG("Enable Target, %d, %d", ioc->id, tgt->target_enable);
+               if (tgt->target_enable != 1) {
+                       mpt_stm_adapter_online(mpt_stm_priv[ioc->id]);
+                       tgt->target_enable = 1;
+               }
+       }
+
+       if (strncmp("target:disable", tmp, strlen("target:disable")) == 0) {
+               TRACE_DBG("Disable Target %d, %d", ioc->id, tgt->target_enable);
+               if (tgt->target_enable != 0) {
+                       /* FIXME */
+                       tgt->target_enable = 0;
+               }
+       }
+
+#ifdef DEBUG   
+       if (strncmp("target_id:", tmp, strlen("target_id:")) == 0) {
+               char *s = tmp + strlen("target_id:");
+               TRACE_DBG("target id is '%s'", s);
+       }
+#endif
+
+       TRACE_EXIT_RES(res);
+
+       return length;
+}
+
+static int mpt_proc_info(char *buffer, char **start, off_t offset,
+               int length, int *eof, struct scst_tgt *tgt, int inout)
+{
+       if (inout) {
+               return mpt_proc_write(NULL, buffer, length, tgt);
+       }
+       return  mpt_proc_read(buffer, start, offset, length, eof, tgt);
+}
+
+
+static int mpt_target_detect(struct scst_tgt_template *temp1);
+static int mpt_target_release(struct scst_tgt *scst_tgt);
+static int mpt_xmit_response(struct scst_cmd *scst_cmd);
+static int mpt_rdy_to_xfer(struct scst_cmd *scst_cmd);
+static void mpt_on_free_cmd(struct scst_cmd *scst_cmd);
+static void mpt_task_mgmt_fn_done(struct scst_mgmt_cmd *mcmd);
+static int mpt_handle_task_mgmt(MPT_STM_PRIV * priv, u32 reply_word,
+               int task_mgmt, int lun);
+static int mpt_send_cmd_to_scst(struct mpt_cmd *cmd, int context);
+
+static struct scst_tgt_template tgt_template = {
+       .name = MYNAM,
+       .sg_tablesize = 128, /* FIXME */
+       .use_clustering = 1,
+#ifdef DEBUG_WORK_IN_THREAD
+       .xmit_response_atomic = 0,
+       .rdy_to_xfer_atomic = 0,
+#else
+       .xmit_response_atomic = 1,
+       .rdy_to_xfer_atomic = 1,
+#endif
+       .detect = mpt_target_detect,
+       .release = mpt_target_release,
+       .xmit_response = mpt_xmit_response,
+       .rdy_to_xfer = mpt_rdy_to_xfer,
+       .on_free_cmd = mpt_on_free_cmd,
+       .task_mgmt_fn_done = mpt_task_mgmt_fn_done,
+       .proc_info = mpt_proc_info,
+};
+
+static inline void 
+mpt_msg_frame_free(MPT_STM_PRIV *priv, int index)
+{
+       MPT_ADAPTER *ioc = priv->ioc;
+       if (priv->current_mf[index] != NULL) {
+               TRACE_DBG("%s: free mf index %d, %p", ioc->name,
+                               MF_TO_INDEX(priv->current_mf[index]), 
+                               priv->current_mf[index]);
+               mpt_free_msg_frame(_HANDLE_IOC_ID, priv->current_mf[index]);
+               priv->current_mf[index] = NULL;
+       }
+}
+
+static inline MPT_FRAME_HDR *
+mpt_msg_frame_alloc(MPT_ADAPTER *ioc, int index)
+{
+       MPT_STM_PRIV *priv = mpt_stm_priv[ioc->id];
+       MPT_FRAME_HDR *mf;
+
+       if (index != -1) {
+               TRACE_DBG("%s: current_mf %p, index %d", 
+                               ioc->name, priv->current_mf[index], index);
+               WARN_ON(priv->current_mf[index] != NULL);
+       }
+
+       mf = mpt_get_msg_frame(stm_context, _IOC_ID);
+
+       if (mf == NULL) {
+               BUG_ON(1);
+       }
+       
+       if (index != -1) {
+               priv->current_mf[index] = mf;
+       }
+
+       TRACE_DBG("%s: alloc mf index %d, %p, %d", ioc->name, 
+                       MF_TO_INDEX(mf), mf, index);
+
+       return mf;
+}
+
+static int _mpt_ada_nums = 0;
+
+static int
+mptstm_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+    MPT_ADAPTER        *ioc = pci_get_drvdata(pdev);
+    int ret = 0;
+    struct mpt_tgt *tgt;
+    
+    TRACE_ENTRY();
+    ret = mpt_stm_adapter_install(ioc);
+    if (ret != 0) {
+           goto out;
+    }
+
+    tgt = kmalloc(sizeof(*tgt), GFP_KERNEL);
+    TRACE_MEM("kmalloc(GFP_KERNEL) for tgt (%d), %p",
+             sizeof(*tgt), tgt);
+    if (tgt == NULL) {
+           TRACE(TRACE_OUT_OF_MEM, "%s",
+                 "Allocation of tgt failed");
+           ret = -ENOMEM;
+           goto out;
+    }
+    memset(tgt, 0, sizeof(*tgt));
+    tgt->priv = mpt_stm_priv[ioc->id];
+       tgt->target_enable = 0;
+       tgt->target_id = 0;
+    atomic_set(&tgt->sess_count, 0);
+    init_waitqueue_head(&tgt->waitQ);
+    
+    tgt->scst_tgt = scst_register(&tgt_template);
+    if (tgt->scst_tgt == NULL) {
+           PRINT_ERROR(MYNAM ": scst_register() "
+                       "failed for host %p", pdev);
+           
+           ret = -ENODEV;
+           goto out;
+    }
+    scst_tgt_set_tgt_priv(tgt->scst_tgt, tgt);
+    mpt_stm_priv[ioc->id]->tgt = tgt;
+    
+    _mpt_ada_nums ++;
+                       
+ out:
+    
+    TRACE_EXIT_RES(ret);
+    
+    return ret;
+}
+
+static void
+mptstm_remove(struct pci_dev *pdev)
+{
+    MPT_ADAPTER        *ioc = pci_get_drvdata(pdev);
+    MPT_STM_PRIV *priv;
+
+       priv = mpt_stm_priv[ioc->id];
+       if (priv != NULL) {
+               mpt_stm_adapter_dispose(priv);
+       }
+}
+
+static struct mpt_pci_driver mptstm_driver = {
+    .probe = mptstm_probe,
+    .remove = mptstm_remove,
+};
+
+/*
+ * mpt_target_detect
+ *
+ * this function is intended to detect the target adapters that are present in
+ * the system. Each found adapter should be registered by calling
+ * scst_register(). The function should return a value >= 0 to signify
+ * the number of detected target adapters. A negative value should be
+ * returned whenever there is an error. 
+ */
+static int mpt_target_detect(struct scst_tgt_template *templ)
+{
+       int ret  = 0;
+
+       TRACE_ENTRY();
+       ret = _mpt_stm_init();
+       if (ret != 0) {
+               goto out;
+       }
+
+       if (mpt_device_driver_register(&mptstm_driver, MPTSTM_DRIVER)) {
+               printk(KERN_WARNING MYNAM
+                      ": failed to register for device driver callbacks\n");
+               ret = -ENODEV;
+               goto out;
+       }
+       
+       ret = _mpt_ada_nums;
+       
+ out:
+       TRACE_EXIT_RES(ret);
+       
+       return ret;
+}
+
+static struct scst_cmd *
+_stm_target_command(MPT_STM_PRIV *priv, int reply_word, 
+                   struct mpt_cmd *mpt_cmd)
+{
+       u8 *cdb;
+       int lun, tag, dl, alias, index, init_index, task_mgmt;
+       char alias_lun[32];
+       CMD *cmd;
+       struct scst_cmd *scst_cmd;
+       struct mpt_sess *sess = mpt_cmd->sess;
+#ifdef DEBUG
+       MPT_ADAPTER *ioc = priv->ioc;
+#endif
+       /* 
+        * Get the CBD, LUN, tag,  Task Mgmt flags, and data length from the 
+        * receive packet 
+        */
+       TRACE_ENTRY();
+
+       index = GET_IO_INDEX(reply_word);
+       init_index = GET_INITIATOR_INDEX(reply_word);
+
+       cmd = &priv->hw->cmd_buf[index];
+
+       if (IsScsi(priv)) {
+               SCSI_CMD *scsi_cmd = (SCSI_CMD *)cmd->cmd;
+
+               cdb = scsi_cmd->CDB;
+               lun = get2bytes(scsi_cmd->LogicalUnitNumber, 0);
+               tag = scsi_cmd->Tag;
+               task_mgmt = scsi_cmd->TaskManagementFlags;
+               dl = 0;
+               /*TRACE_DBG("AliasID %d, %d", scsi_cmd->AliasID, priv->port_id);*/
+               if (reply_word & TARGET_MODE_REPLY_ALIAS_MASK) {
+                       alias = (scsi_cmd->AliasID - priv->port_id) & 15;
+                       sprintf(alias_lun, "alias %d lun %d", alias, lun);
+               } else {
+                       alias = 0;
+                       sprintf(alias_lun, "lun %d", lun);
+               }
+       } else if (IsSas(priv)) {
+               SSP_CMD *ssp_cmd = (SSP_CMD *)cmd->cmd;
+
+               cdb = ssp_cmd->CDB;
+               lun = get2bytes(ssp_cmd->LogicalUnitNumber, 0);
+               if (ssp_cmd->FrameType == SSP_TASK_FRAME) {
+                       SSP_TASK        *ssp_task = (SSP_TASK *)cmd->cmd;
+
+                       tag = ssp_task->ManagedTaskTag;
+                       task_mgmt = ssp_task->TaskManagementFunction;
+               } else {
+                       tag = ssp_cmd->InitiatorTag;
+                       task_mgmt = 0;
+               }
+               dl = 0;
+               alias = 0;
+               sprintf(alias_lun, "lun %d", lun);
+       } else {
+               FCP_CMD *fcp_cmd = (FCP_CMD *)cmd->cmd;
+
+               cdb = fcp_cmd->FcpCdb;
+               lun = get2bytes(fcp_cmd->FcpLun, 0);
+               tag = 0;
+               task_mgmt = fcp_cmd->FcpCntl[2];
+               dl = be32_to_cpu(fcp_cmd->FcpDl);
+               if (reply_word & TARGET_MODE_REPLY_ALIAS_MASK) {
+                       alias = fcp_cmd->AliasIndex;
+                       sprintf(alias_lun, "alias %d lun %d", alias, lun);
+               } else {
+                       alias = 0;
+                       sprintf(alias_lun, "lun %d", lun);
+               }
+       }
+
+       cmd->reply_word = reply_word;
+       cmd->alias = alias;
+       cmd->lun = lun;
+       cmd->tag = tag;
+
+       TRACE_DBG("%s: cmd %p, re_word %x, alias %x, lun %x, tag %x,"
+                       "%s, init_idx %d, %p, %d",
+                       ioc->name, cmd, reply_word, alias, lun, tag, alias_lun, 
+                       init_index, priv->scst_cmd[index], dl);
+
+       mpt_cmd->CMD = cmd;
+       {
+               uint16_t _lun = lun;
+               _lun = swab16(le16_to_cpu(_lun));
+               scst_cmd = scst_rx_cmd(sess->scst_sess, (uint8_t *)&_lun,
+                               sizeof(_lun), cdb, MPT_MAX_CDB_LEN, SCST_ATOMIC);
+       }
+       if (scst_cmd == NULL) {
+               PRINT_ERROR(MYNAM ": scst_rx_cmd() failed for %p", cmd);
+               goto out;
+       }
+       TRACE_DBG("scst cmd %p, index %d", priv->scst_cmd[index], index);
+
+       WARN_ON(priv->scst_cmd[index] != 0);
+       priv->scst_cmd[index] = scst_cmd;
+
+       scst_cmd_set_tag(scst_cmd, tag);
+       scst_cmd_set_tgt_priv(scst_cmd, mpt_cmd);
+
+       /* FIXME scst_cmd_set_expected */
+out:
+       TRACE_EXIT();
+
+       return scst_cmd;
+}
+
+static void
+mpt_send_busy(struct mpt_cmd *cmd)
+{
+       stmapp_set_status(cmd->priv, cmd->CMD, STS_BUSY);
+}
+
+static void 
+mpt_alloc_session_done(struct scst_session *scst_sess, void *data, int result)
+{
+       struct mpt_sess *sess = (struct mpt_sess *) data;
+       struct mpt_tgt *tgt = sess->tgt;
+       struct mpt_cmd *cmd = NULL;
+       int rc = 0;
+
+       TRACE_ENTRY();
+       if (result == 0) {
+               scst_sess_set_tgt_priv(scst_sess, sess);
+               
+               while (!list_empty(&sess->delayed_cmds)) {
+                       cmd = list_entry(sess->delayed_cmds.next,
+                                        typeof(*cmd), delayed_cmds_entry);
+                       list_del(&cmd->delayed_cmds_entry);
+                       if (rc == 0)
+                               rc = mpt_send_cmd_to_scst(cmd, SCST_CONTEXT_THREAD);
+                       if (rc != 0) {
+                               PRINT_INFO(MYNAM ": Unable to get the command, sending BUSY state %p", 
+                                          cmd);
+                               mpt_send_busy(cmd);
+                               kfree(cmd);
+                       }
+               }
+       } else {
+               PRINT_INFO(MYNAM ": Session initialization failed, "
+                          "sending BUSY status to all deferred commands %p",
+                          cmd);
+               while (!list_empty(&sess->delayed_cmds)) {
+                       cmd = list_entry(sess->delayed_cmds.next,
+                                        typeof(*cmd), delayed_cmds_entry);
+                       list_del(&cmd->delayed_cmds_entry);
+                       TRACE(TRACE_MGMT, "Command <%p> Busy", cmd);
+                       mpt_send_busy(cmd);
+                       kfree(cmd);
+               }
+               tgt->sess[sess->init_index] = NULL;
+               
+               TRACE_MEM("kfree for sess %p", sess);
+               kfree(sess);
+               
+               if (atomic_dec_and_test(&tgt->sess_count))
+                               wake_up_all(&tgt->waitQ);
+       }
+       
+        __clear_bit(MPT_SESS_INITING, &sess->sess_flags);
+
+       TRACE_EXIT();
+       return;
+}
+
+static int 
+mpt_send_cmd_to_scst(struct mpt_cmd *cmd, int context)
+{
+       int res = 0;
+       
+       TRACE_ENTRY();
+       
+       cmd->scst_cmd = _stm_target_command(cmd->priv, cmd->reply_word, cmd);
+       if (cmd->scst_cmd == NULL) {
+               res = -EFAULT;
+               goto out;
+       }
+#ifdef DEBUG_WORK_IN_THREAD
+       context = SCST_CONTEXT_THREAD;
+#endif
+       scst_cmd_init_done(cmd->scst_cmd, context);
+
+ out:  
+       TRACE_EXIT_RES(res);
+       
+       return res;
+}
+
+static void
+stm_send_target_status_deferred(MPT_STM_PRIV *priv,
+               u32 reply_word, int index)
+{
+       int ret = 0;
+       MPT_ADAPTER         *ioc = priv->ioc;
+       MPT_FRAME_HDR       *mf;
+       TargetStatusSendRequest_t   *req;
+
+       TRACE_ENTRY();
+       mf = priv->status_deferred_mf[index];
+       TRACE_DBG("mf %p, index %d", mf, index);
+       req = (TargetStatusSendRequest_t *)mf;
+
+       priv->io_state[index] |= IO_STATE_STATUS_SENT;
+
+       priv->current_mf[index] = mf;
+       priv->status_deferred_mf[index] = NULL;
+       if (priv->io_state[index] & IO_STATE_HIGH_PRIORITY) {
+               ret = mpt_send_handshake_request(stm_context, _IOC_ID,
+                               sizeof(*req), (u32 *)req _HS_SLEEP);
+       } else {
+               mpt_put_msg_frame(stm_context, _IOC_ID, mf);
+       }
+
+       TRACE_EXIT_RES(ret);
+}
+
+static void
+stm_data_done(MPT_ADAPTER *ioc, u32 reply_word, 
+               struct scst_cmd *scst_cmd, struct mpt_cmd *cmd, int index)
+{
+       MPT_STM_PRIV *priv = mpt_stm_priv[ioc->id];
+       uint8_t *buf = NULL;
+
+       TRACE_ENTRY();
+       TRACE_DBG("scst cmd %p, index %d, data done",  scst_cmd, index);
+
+       if (scst_cmd_get_resp_data_len(scst_cmd) > 0) {
+               TRACE_DBG("clear the data flags <%p>", scst_cmd);
+               if (scst_cmd_get_sg_cnt(scst_cmd)) {
+                       pci_unmap_sg(priv->ioc->pcidev,
+                               scst_cmd_get_sg(scst_cmd),
+                               scst_cmd_get_sg_cnt(scst_cmd),
+                               scst_to_dma_dir(scst_cmd_get_data_direction(scst_cmd)));
+               } else {
+                       pci_unmap_single(priv->ioc->pcidev, cmd->dma_handle,
+                               scst_get_buf_first(scst_cmd, &buf),
+                               scst_to_dma_dir(scst_cmd_get_data_direction(scst_cmd)));
+               }
+       }
+       TRACE_EXIT();
+}
+
+void 
+stm_tgt_reply(MPT_ADAPTER *ioc, u32 reply_word)
+{
+       MPT_STM_PRIV *priv = mpt_stm_priv[ioc->id];
+       int index;
+       struct scst_cmd *scst_cmd;
+       struct mpt_cmd *cmd;
+       volatile int *io_state;
+       
+       TRACE_ENTRY();
+
+       index = GET_IO_INDEX(reply_word);
+       scst_cmd = priv->scst_cmd[index];
+       io_state = priv->io_state + index;
+
+       TRACE_DBG("index %d, state %x, scst cmd %p, current_mf %p",
+                       index, *io_state, scst_cmd, priv->current_mf[index]);
+       /*
+        * if scst_cmd is NULL it show the command buffer not using by 
+        * SCST, let parse the CDB
+        */
+       if (scst_cmd == NULL) {
+               WARN_ON((*io_state & ~IO_STATE_HIGH_PRIORITY) != IO_STATE_POSTED);
+               *io_state &= ~IO_STATE_POSTED;
+       
+               mpt_msg_frame_free(priv, index);
+               
+               stmapp_tgt_command(priv, reply_word);
+               goto out;
+       }
+       
+       cmd = (struct mpt_cmd *)scst_cmd_get_tgt_priv(scst_cmd);
+       TRACE_DBG("scst cmd %p, index %d, cmd %p, cmd state %s", 
+                 scst_cmd, index, cmd, mpt_state_string[cmd->state]);
+       
+       if (cmd->state == MPT_STATE_NEED_DATA) {
+               int context = SCST_CONTEXT_TASKLET;
+               int rx_status = SCST_RX_STATUS_SUCCESS;
+
+               cmd->state = MPT_STATE_DATA_IN;
+
+#ifdef DEBUG_WORK_IN_THREAD
+               context = SCST_CONTEXT_THREAD;
+#endif
+               TRACE_DBG("Data received, context %x, rx_status %d",
+                               context, rx_status);
+
+               BUG_ON(!(*io_state & IO_STATE_DATA_SENT));
+               mpt_msg_frame_free(priv, index);
+               if (*io_state & IO_STATE_DATA_SENT) {
+                       *io_state &= ~IO_STATE_DATA_SENT;
+                       stm_data_done(ioc, reply_word, scst_cmd, cmd, index);
+               }
+#if 0
+               if ((*io_state & ~IO_STATE_HIGH_PRIORITY) == IO_STATE_AUTO_REPOST) {
+                       TRACE_DBG("%s", "io state auto repost");
+                       *io_state = IO_STATE_POSTED;
+               } else if ((*io_state & ~IO_STATE_HIGH_PRIORITY) == 0) {
+                       TRACE_DBG("%s", "io state");
+                       stm_cmd_buf_post(priv, index);
+               }
+#endif
+               scst_rx_data(scst_cmd, rx_status, context);
+
+               goto out;
+       }
+
+       if (*io_state & IO_STATE_STATUS_SENT) {
+               /*
+                *  status (and maybe data too) was being sent, so repost the
+                *  command buffer
+                */
+               *io_state &= ~IO_STATE_STATUS_SENT;
+               mpt_msg_frame_free(priv, index);
+               if (*io_state & IO_STATE_DATA_SENT) {
+                       *io_state &= ~IO_STATE_DATA_SENT;
+                       stm_data_done(ioc, reply_word, scst_cmd, cmd, index);
+               }
+               if ((*io_state & ~IO_STATE_HIGH_PRIORITY) == IO_STATE_AUTO_REPOST) {
+                       TRACE_DBG("%s", "io state auto repost");
+                       *io_state = IO_STATE_POSTED;
+               } else if ((*io_state & ~IO_STATE_HIGH_PRIORITY) == 0) {
+                       TRACE_DBG("%s", "io state");
+                       stm_cmd_buf_post(priv, index);
+               }
+
+               scst_tgt_cmd_done(scst_cmd);
+
+               goto out;
+       }
+
+       /*
+        *  data (but not status) was being sent, so if status needs to be
+        *  set now, go ahead and do it; otherwise do nothing
+        */
+       if (*io_state & IO_STATE_DATA_SENT) {
+               *io_state &= ~IO_STATE_DATA_SENT;
+               mpt_msg_frame_free(priv, index);
+               stm_data_done(ioc, reply_word, scst_cmd, cmd, index);
+               if (*io_state & IO_STATE_STATUS_DEFERRED) {
+                       *io_state &= ~IO_STATE_STATUS_DEFERRED;
+                       stm_send_target_status_deferred(priv, reply_word, index);
+               }
+               cmd->state = MPT_STATE_PROCESSED;
+               goto out;
+       }
+
+       /*
+        * just insert into list
+        * bug how can i handle it 
+        */
+       if (*io_state == 0 && cmd->state == MPT_STATE_NEW) {
+               WARN_ON(1);
+               goto out;
+       }
+#if 0
+       if (*io_state == IO_STATE_POSTED) {
+               TRACE_DBG("%s", "io state posted");
+               /*
+                *  command buffer was posted, so we now have a SCSI command
+                */
+               *io_state &= ~IO_STATE_POSTED;
+               goto out;
+       }
+#endif
+       WARN_ON(1);
+ out:
+       
+       TRACE_EXIT();
+}
+
+static int 
+mpt_is_task_mgm(MPT_STM_PRIV *priv, u32 reply_word, int *lun)
+{
+       int task_mgmt = 0, index;
+       CMD *cmd;
+       //struct mpt_tgt *tgt = priv->tgt;
+
+       TRACE_ENTRY();
+
+       index = GET_IO_INDEX(reply_word);
+       cmd = &priv->hw->cmd_buf[index];
+
+       if (IsScsi(priv)) {
+               SCSI_CMD *scsi_cmd = (SCSI_CMD *)cmd->cmd;
+               task_mgmt = scsi_cmd->TaskManagementFlags;
+               *lun = get2bytes(scsi_cmd->LogicalUnitNumber, 0);
+       } else if (IsSas(priv)) {
+               SSP_CMD *ssp_cmd = (SSP_CMD *)cmd->cmd;
+               if (ssp_cmd->FrameType == SSP_TASK_FRAME) {
+                       SSP_TASK *ssp_task = (SSP_TASK *)cmd->cmd;
+                       task_mgmt = ssp_task->TaskManagementFunction;
+               }
+               *lun = get2bytes(ssp_cmd->LogicalUnitNumber, 0);
+       } else {
+               FCP_CMD *fcp_cmd = (FCP_CMD *)cmd->cmd;
+               task_mgmt = fcp_cmd->FcpCntl[2];
+               *lun = get2bytes(fcp_cmd->FcpLun, 0);
+       }
+       TRACE_EXIT_RES(task_mgmt);
+
+       return task_mgmt;
+}
+
+static void
+stmapp_tgt_command(MPT_STM_PRIV *priv, u32 reply_word)
+{
+       struct mpt_tgt *tgt = NULL;
+       struct mpt_sess *sess = NULL;
+       struct mpt_cmd *cmd = NULL;
+       int init_index, res = 0, task_mgmt, lun;
+
+       TRACE_ENTRY();
+       
+       tgt = priv->tgt;
+
+       task_mgmt = mpt_is_task_mgm(priv, reply_word, &lun);
+       if (task_mgmt) {
+               mpt_handle_task_mgmt(priv, reply_word, task_mgmt, lun);
+       }
+       
+       init_index = GET_INITIATOR_INDEX(reply_word);
+       
+       if (test_bit(MPT_TGT_SHUTDOWN, &tgt->tgt_flags)) {
+               TRACE_DBG("New command while the device %p is shutting down", tgt);
+               res = -EFAULT;
+               goto out;
+       }
+       
+       cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
+       TRACE_MEM("kmalloc(GFP_ATOMIC) for cmd (%d): %p", sizeof(*cmd), cmd);
+       if (cmd == NULL) {
+               TRACE(TRACE_OUT_OF_MEM, "%s", "Allocation of cmd failed");
+               res = -ENOMEM;
+               goto out;
+       }
+       
+       memset(cmd, 0, sizeof(*cmd));
+       cmd->priv = priv;
+       cmd->reply_word = reply_word;
+       cmd->state = MPT_STATE_NEW;
+
+       sess = tgt->sess[init_index];
+       if (sess == NULL) {
+               sess = kmalloc(sizeof(*sess), GFP_ATOMIC);
+               if (sess == NULL) {
+                       TRACE(TRACE_OUT_OF_MEM, "%s",
+                             "Allocation of sess failed");
+                       res = -ENOMEM;
+                       goto out_free_cmd;
+               }
+               /* WWPN */
+               
+               atomic_inc(&tgt->sess_count);
+               smp_mb__after_atomic_inc();
+               
+               memset(sess, 0, sizeof(*sess));
+               sess->tgt = tgt;
+               sess->init_index = init_index;
+               INIT_LIST_HEAD(&sess->delayed_cmds);
+               
+               sess->scst_sess = scst_register_session(tgt->scst_tgt, 1,
+                                                       "", sess, mpt_alloc_session_done);
+               if (sess->scst_sess == NULL) {
+                       PRINT_ERROR(MYNAM ": scst_register_session failed %p", 
+                                   tgt);
+                       res = -EFAULT;
+                       goto out_free_sess;
+               }
+               
+               __set_bit(MPT_SESS_INITING, &sess->sess_flags);
+               
+               tgt->sess[init_index] = sess;
+               scst_sess_set_tgt_priv(sess->scst_sess, sess);
+               
+               cmd->sess = sess;
+               list_add_tail(&cmd->delayed_cmds_entry, &sess->delayed_cmds);
+               goto out;
+       }
+
+       /* seesion is ready let us do it */
+       cmd->sess = sess;
+       if (test_bit(MPT_SESS_INITING, &sess->sess_flags)) {
+               list_add_tail(&cmd->delayed_cmds_entry, &sess->delayed_cmds);
+       } else {
+               res = mpt_send_cmd_to_scst(cmd, SCST_CONTEXT_TASKLET);
+               /*res = mpt_send_cmd_to_scst(cmd, SCST_CONTEXT_DIRECT_ATOMIC);*/
+               if (res != 0)
+                       goto out_free_cmd;
+       }
+       
+ out:
+       TRACE_EXIT();
+       return;
+
+ out_free_sess:
+       TRACE_MEM("kfree for sess %p", sess);
+       kfree(sess);
+
+       if (atomic_dec_and_test(&tgt->sess_count))
+               wake_up_all(&tgt->waitQ);
+       /* go through */
+ out_free_cmd:
+       TRACE_MEM("kfree for cmd %p", cmd);
+       kfree(cmd);
+       goto out;
+}
+
+/*
+ * mpt_target_release
+ * 
+ * this function is
+ * intended to free up the resources allocated to the device. The function
+ * should return 0 to indicate successful release or a negative value if
+ * there are some issues with the release. In the current version of SCST
+ * the return value is ignored. Must be defined.
+ */
+static int mpt_target_release(struct scst_tgt *scst_tgt)
+{
+       /* FIXME */
+       return 0;
+}
+
+struct mpt_prm
+{
+       struct mpt_tgt *tgt;
+       uint16_t seg_cnt;
+       unsigned short use_sg;
+       struct scatterlist *sg;
+       unsigned int bufflen;
+       void *buffer;
+       scst_data_direction data_direction;
+       uint16_t rq_result;
+       uint16_t scsi_status;
+       unsigned char *sense_buffer;
+       unsigned int sense_buffer_len;
+       struct mpt_cmd *cmd;
+};
+
+static inline void 
+mpt_dump_sge(MPT_SGE *sge, struct scatterlist *sg)
+{
+       if (sge) {
+               void *address = NULL;
+               struct page *page = NULL;
+               address = bus_to_virt(sge->address);
+               page = virt_to_page(address);
+               TRACE_DBG("address %p, length %x, count %d, page %p", 
+                               address, sge->length, page_count(page), page);
+               TRACE_BUFFER("sge data", address, min(sge->length, (u32)0x10));
+       }
+       if (sg) {
+               TRACE_DBG("sg %p, page %p, %p, offset %d, dma address %x, len %d",
+                               sg, sg->page, page_address(sg->page), 
+                               sg->offset, sg->dma_address, sg->length);
+               TRACE_BUFFER("sg data", page_address(sg->page), (u32)0x10);
+       }
+}
+
+/* FIXME
+ *
+ * use_sg can not bigger then NUM_SGES
+ *
+ */
+static inline void
+mpt_sge_to_sgl(struct mpt_prm *prm, MPT_STM_PRIV *priv, MPT_SGL *sgl)
+{
+       unsigned int bufflen = prm->bufflen;
+       TRACE_ENTRY();
+       TRACE_DBG("bufflen %d, %p", bufflen, prm->buffer);
+       if (prm->use_sg) {
+               int i;
+               prm->sg = (struct scatterlist *)prm->buffer;
+               prm->seg_cnt = 
+                       pci_map_sg(priv->ioc->pcidev, prm->sg, prm->use_sg,
+                                  scst_to_dma_dir(prm->data_direction));
+               
+               pci_dma_sync_sg_for_cpu(priv->ioc->pcidev, prm->sg, 
+                               prm->use_sg, 
+                               scst_to_dma_dir(prm->data_direction));
+               for (i = 0; i < prm->use_sg; i++) {
+                       sgl->sge[i].length = sg_dma_len(&prm->sg[i]);
+                       sgl->sge[i].address = sg_dma_address(&prm->sg[i]);
+
+                       TRACE_DBG("%d, %d", bufflen, prm->sg[i].length);
+                       if (bufflen < prm->sg[i].length) {
+                               sgl->sge[i].length = bufflen;
+                       }
+                       mpt_dump_sge(&sgl->sge[i], &prm->sg[i]);
+                       bufflen -= sgl->sge[i].length;
+               }
+               pci_dma_sync_sg_for_device(priv->ioc->pcidev, prm->sg, 
+                               prm->use_sg, 
+                               scst_to_dma_dir(prm->data_direction));
+       } else {
+               prm->cmd->dma_handle = 
+                       pci_map_single(priv->ioc->pcidev, prm->buffer, 
+                                      prm->bufflen,
+                                      scst_to_dma_dir(prm->data_direction));
+               
+               pci_dma_sync_single_for_cpu(priv->ioc->pcidev, prm->cmd->dma_handle, prm->bufflen, scst_to_dma_dir(prm->data_direction));
+               sgl->sge[0].length = prm->bufflen;
+               sgl->sge[0].address = virt_to_phys(prm->buffer);
+               
+               mpt_dump_sge(&sgl->sge[0], NULL);
+               pci_dma_sync_single_for_device(priv->ioc->pcidev, prm->cmd->dma_handle, prm->bufflen, scst_to_dma_dir(prm->data_direction));
+
+               prm->seg_cnt = 1;
+       }
+       
+       sgl->num_sges = prm->seg_cnt;
+       
+       TRACE_EXIT();
+}
+
+static inline void
+mpt_set_sense_info(MPT_STM_PRIV *priv, CMD *cmd, int len, u8 *sense_buf)
+{
+       u8 *info = NULL;
+       
+       TRACE_ENTRY();
+
+       if (IsScsi(priv)) {
+               SCSI_RSP    *rsp = (SCSI_RSP *)cmd->rsp;
+
+               rsp->Status = STS_CHECK_CONDITION;
+               rsp->Valid |= SCSI_SENSE_LEN_VALID;
+               rsp->SenseDataListLength = cpu_to_be32(len);
+               info = rsp->SenseData;
+               if (rsp->Valid & SCSI_RSP_LEN_VALID) {
+                       info += be32_to_cpu(rsp->PktFailuresListLength);
+               }
+       } else if (IsSas(priv)) {
+               SSP_RSP     *rsp = (SSP_RSP *)cmd->rsp;
+
+               rsp->Status = STS_CHECK_CONDITION;
+               rsp->DataPres |= SSP_SENSE_LEN_VALID;
+               rsp->SenseDataLength = cpu_to_be32(len);
+               info = rsp->ResponseSenseData;
+               if (rsp->DataPres & SSP_RSP_LEN_VALID) {
+                       info += be32_to_cpu(rsp->ResponseDataLength);
+               }
+       } else {
+               FCP_RSP     *rsp = (FCP_RSP *)cmd->rsp;
+
+               rsp->FcpStatus = STS_CHECK_CONDITION;
+               rsp->FcpFlags |= FCP_SENSE_LEN_VALID;
+               rsp->FcpSenseLength = cpu_to_be32(len);
+               info = rsp->FcpSenseData - sizeof(rsp->FcpResponseData);
+               if (rsp->FcpFlags & FCP_RSP_LEN_VALID) {
+                       info += be32_to_cpu(rsp->FcpResponseLength);
+               }
+       }
+
+       BUG_ON(info == NULL);
+       memcpy(info, sense_buf, len);
+/*out:*/
+
+       TRACE_EXIT();
+}
+
+static int
+mpt_send_tgt_data(MPT_STM_PRIV *priv, u32 reply_word,
+               int index, int flags, int lun, int tag, MPT_SGL *sgl,
+               int length, int offset)
+{
+       MPT_ADAPTER *ioc = priv->ioc;
+       TargetAssistRequest_t *req;
+       MPT_STM_SIMPLE  *sge_simple;
+       MPT_STM_CHAIN   *sge_chain = NULL;
+       u32 sge_flags;
+       int chain_length, i, j, k, init_index, res = 1;
+       dma_addr_t dma_addr;
+
+       TRACE_ENTRY();
+       req = (TargetAssistRequest_t *)mpt_msg_frame_alloc(ioc,index);
+       memset(req, 0, sizeof(*req));
+       
+       if (priv->exiting) {
+               flags &= ~TARGET_ASSIST_FLAGS_REPOST_CMD_BUFFER;
+       }
+       
+       if (priv->io_state[index] & IO_STATE_HIGH_PRIORITY) {
+               flags |= TARGET_ASSIST_FLAGS_HIGH_PRIORITY;
+               if (flags & TARGET_ASSIST_FLAGS_AUTO_STATUS) {
+                       flags |= TARGET_ASSIST_FLAGS_REPOST_CMD_BUFFER;
+                       priv->io_state[index] |= IO_STATE_AUTO_REPOST;
+               }
+       }
+       
+       if (priv->fcp2_capable/* && priv->initiators != NULL*/) {
+               init_index = GET_INITIATOR_INDEX(reply_word);
+               /*init = priv->initiators[init_index];
+               if (init != NULL && init->confirm_capable) {
+                       flags |= TARGET_ASSIST_FLAGS_CONFIRMED;
+               }*/
+       }
+       TRACE_DBG("flags %x, tag %x, lun %x, offset %x, length %x",
+                 flags, tag, lun, offset, length);
+       
+       req->StatusCode = 0;
+       req->TargetAssistFlags = (u8)flags;
+       req->Function = MPI_FUNCTION_TARGET_ASSIST;
+       req->QueueTag = (u16)tag;
+       req->ReplyWord = cpu_to_le32(reply_word);
+       req->LUN[0] = (u8)(lun >> 8);
+       req->LUN[1] = (u8)lun;
+       req->RelativeOffset = cpu_to_le32(offset);
+       req->DataLength = cpu_to_le32(length);
+       sge_flags =
+               MPI_SGE_SET_FLAGS(MPI_SGE_FLAGS_SIMPLE_ELEMENT |
+                                 MPI_SGE_FLAGS_MPT_STM_ADDRESSING);
+       if (flags & TARGET_ASSIST_FLAGS_DATA_DIRECTION)
+               sge_flags |= MPI_SGE_SET_FLAGS(MPI_SGE_FLAGS_HOST_TO_IOC);
+       sge_simple = (MPT_STM_SIMPLE *)&req->SGL;
+       for (i = 0, j = 0, k = 0; i < (int)sgl->num_sges; i++, j++) {
+               if (k == 0) {
+                       /* still in mf, haven't chained yet -- do we need to? */
+                       if (j == priv->num_sge_target_assist) {
+                               /* yes, we need to chain */
+                               /* overwrite the last element in the mf with a chain */
+                               sge_chain = (MPT_STM_CHAIN *)(sge_simple - 1);
+                               sge_chain->Flags =
+                                       (u8)(MPI_SGE_FLAGS_CHAIN_ELEMENT |
+                                                MPI_SGE_FLAGS_MPT_STM_ADDRESSING);
+                               dma_addr = priv->hw_dma +
+                                       ((u8 *)priv->hw->cmd_buf[index].chain_sge - 
+                                        (u8 *)priv->hw);
+                               stm_set_dma_addr(sge_chain->Address, dma_addr);
+                               /* set the "last element" flag in the mf */
+                               sge_simple = (MPT_STM_SIMPLE *)(sge_chain - 1);
+                               sge_simple->FlagsLength |=
+                                       cpu_to_le32(MPI_SGE_SET_FLAGS(MPI_SGE_FLAGS_LAST_ELEMENT));
+                               /* redo the last element in the mf */
+                               sge_simple =
+                                       (MPT_STM_SIMPLE *)priv->hw->cmd_buf[index].chain_sge;
+                               sge_simple->FlagsLength =
+                                       cpu_to_le32(sgl->sge[i-1].length | sge_flags);
+                               stm_set_dma_addr(sge_simple->Address, sgl->sge[i-1].address);
+                               mpt_dump_sge(&sgl->sge[i-1], NULL);
+                               sge_simple++;
+                               /* say we've chained */
+                               req->ChainOffset =
+                                       ((u8 *)sge_chain - (u8 *)req) / sizeof(u32);
+                               j = 1;
+                               k++;
+                       }
+               } else {
+                       /* now in chain, do we need to chain again? */
+                       if (j == priv->num_sge_chain) {
+                               /* yes, we need to chain */
+                               /* fix up the previous chain element */
+                               chain_length = sizeof(MPT_STM_CHAIN) +
+                                       (priv->num_sge_chain - 1) * sizeof(MPT_STM_SIMPLE);
+                               sge_chain->Length = cpu_to_le16(chain_length);
+                               sge_chain->NextChainOffset =
+                                       (chain_length - sizeof(MPT_STM_CHAIN)) / sizeof(u32);
+                               /* overwrite the last element in the chain with another chain */
+                               sge_chain = (MPT_STM_CHAIN *)(sge_simple - 1);
+                               sge_chain->Flags =
+                                       (u8)(MPI_SGE_FLAGS_CHAIN_ELEMENT |
+                                                MPI_SGE_FLAGS_MPT_STM_ADDRESSING);
+                               dma_addr = priv->hw_dma + ((u8 *)sge_simple - (u8 *)priv->hw);
+                               stm_set_dma_addr(sge_chain->Address, dma_addr);
+                               /* set the "last element" flag in the previous chain */
+                               sge_simple = (MPT_STM_SIMPLE *)(sge_chain - 1);
+                               sge_simple->FlagsLength |=
+                                       cpu_to_le32(MPI_SGE_SET_FLAGS(MPI_SGE_FLAGS_LAST_ELEMENT));
+                               /* redo the last element in the previous chain */
+                               sge_simple = (MPT_STM_SIMPLE *)(sge_chain + 1);
+                               sge_simple->FlagsLength =
+                                       cpu_to_le32(sgl->sge[i-1].length | sge_flags);
+                               stm_set_dma_addr(sge_simple->Address, sgl->sge[i-1].address);
+                               mpt_dump_sge(&sgl->sge[i-1], NULL);
+                               sge_simple++;
+                               /* say we've chained */
+                               j = 1;
+                               k++;
+                       }
+               }
+               sge_simple->FlagsLength = cpu_to_le32(sgl->sge[i].length | sge_flags);
+               stm_set_dma_addr(sge_simple->Address, sgl->sge[i].address);
+               mpt_dump_sge(&sgl->sge[i], NULL);
+               sge_simple++;
+       }
+       /* did we chain? */
+       if (k != 0) {
+               /* fix up the last chain element */
+               sge_chain->Length = cpu_to_le16(j * sizeof(MPT_STM_SIMPLE));
+               sge_chain->NextChainOffset = 0;
+       }
+       /* fix up the last element */
+       sge_simple--;
+       sge_simple->FlagsLength |=
+               cpu_to_le32(MPI_SGE_SET_FLAGS(MPI_SGE_FLAGS_LAST_ELEMENT |
+                                             MPI_SGE_FLAGS_END_OF_BUFFER |
+                     MPI_SGE_FLAGS_END_OF_LIST));
+#ifdef TRACING
+if(trace_mpi)
+{
+       u32 *p = (u32 *)req;
+       int i;
+       //dma_addr_t _data;
+       //u8 *_buf;
+
+       TRACE(TRACE_MPI, "%s stm_send_target_data %d",
+                       ioc->name, index);
+       for (i = 0; i < (sizeof(*req) - sizeof(req->SGL)) / 4; i++) {
+               TRACE(TRACE_MPI, "%s req[%02x] = %08x",
+                               ioc->name, i * 4, le32_to_cpu(p[i]));
+       }
+       TRACE(TRACE_MPI, "%s num_sges = %d, j = %d, k = %d",
+                       ioc->name, sgl->num_sges, j, k);
+       p = (u32 *)&req->SGL;
+       for (i = 0; i < ((k != 0) ? priv->num_sge_target_assist : j); i++) {
+#if MPT_STM_64_BIT_DMA
+       TRACE(TRACE_MPI, "%s req sgl[%04x] = %08x %08x %08x",
+                               ioc->name, i * 12, le32_to_cpu(p[i*3]),
+                               le32_to_cpu(p[i*3+1]), le32_to_cpu(p[i*3+2]));
+#else
+       _data = le32_to_cpu(p[i*2+1]);
+       _buf = (u8 *)phys_to_virt(_data);
+       TRACE(TRACE_MPI, "%s req sgl[%04x] = %08x %08x,%x,%x,%x,%x,%p",
+                       ioc->name, i * 8, le32_to_cpu(p[i*2]), le32_to_cpu(p[i*2+1]),
+                       _buf[0], _buf[1], _buf[2], _buf[3], _buf);
+#endif
+       }
+       p = (u32 *)priv->hw->cmd_buf[index].chain_sge;
+       for (i = 0; i < ((k != 0) ? (k - 1) * priv->num_sge_chain + j : 0); i++) {
+#if MPT_STM_64_BIT_DMA
+       TRACE(TRACE_MPI, "%s chain sgl[%04x] = %08x %08x %08x",
+                       ioc->name, i * 12, le32_to_cpu(p[i*3]),
+                       le32_to_cpu(p[i*3+1]), le32_to_cpu(p[i*3+2]));
+#else
+       _data = le32_to_cpu(p[i*2+1]);
+       _buf = (u8 *)phys_to_virt(_data);
+       TRACE(TRACE_MPI, "%s req sgl[%04x] = %08x %08x,%x,%x,%x,%x,%p",
+                       ioc->name, i * 8, le32_to_cpu(p[i*2]), le32_to_cpu(p[i*2+1]),
+                       _buf[0], _buf[1], _buf[2], _buf[3], _buf);
+#endif
+               }
+       }
+#endif
+       res = 0;
+       
+       priv->io_state[index] |= IO_STATE_DATA_SENT;
+       if (flags & TARGET_ASSIST_FLAGS_AUTO_STATUS)
+               priv->io_state[index] |= IO_STATE_STATUS_SENT;
+
+
+       if (priv->io_state[index] & IO_STATE_HIGH_PRIORITY) {
+               res =mpt_send_handshake_request(stm_context, _IOC_ID,
+                                          ioc->req_sz, (u32 *)req _HS_SLEEP);
+       } else {
+               mpt_put_msg_frame(stm_context, _IOC_ID, (MPT_FRAME_HDR *)req);
+       }
+
+       TRACE_EXIT_RES(res);
+       
+       return res;     
+}
+
+/* 
+ * calling mpt_send_target_data
+ *
+ */
+static void 
+mpt_send_target_data(struct mpt_prm *prm, int flags)
+{
+       MPT_STM_PRIV *priv;
+       u32 reply_word;
+       int index, lun, tag, length, offset;
+       MPT_SGL *sgl;
+       
+       TRACE_ENTRY();
+       priv = prm->tgt->priv;
+       sgl = &priv->sgl;
+       
+       mpt_sge_to_sgl(prm, priv, sgl);
+       
+       reply_word = prm->cmd->CMD->reply_word;
+       index = GET_IO_INDEX(reply_word);
+
+       lun = prm->cmd->CMD->lun;
+       tag = prm->cmd->CMD->tag;
+
+       if (prm->data_direction == SCST_DATA_READ) {
+               flags |= TARGET_ASSIST_FLAGS_DATA_DIRECTION;
+       }
+       
+       length = prm->bufflen;
+       offset = 0;
+#if 0  
+       TRACE_DBG("priv %p, reply_word %x, index %x, flags %x, lun %x, "
+                 "tag %x, sgl %p, length %x, offset %x",
+                 priv, reply_word, index, flags, lun, tag, 
+                 sgl, length, offset);
+#endif 
+       mpt_send_tgt_data(priv, reply_word, index, flags, lun, tag,
+                       sgl, length, offset);
+
+       TRACE_EXIT();
+       return;
+}
+
+/*
+ * this function is equivalent to the SCSI queuecommand(). The target should
+ * transmit the response data and the status in the struct scst_cmd. See
+ * below for details. Must be defined.
+ */
+static int 
+mpt_xmit_response(struct scst_cmd *scst_cmd)
+{
+       int res = SCST_TGT_RES_SUCCESS;
+       struct mpt_sess *sess;
+       struct mpt_prm prm = { 0 };
+       int resp_flags;
+       //uint16_t full_req_cnt;
+       //int data_sense_flag = 0;
+
+       TRACE_ENTRY();
+       prm.cmd = (struct mpt_cmd *)scst_cmd_get_tgt_priv(scst_cmd);
+       sess = (struct mpt_sess *)
+               scst_sess_get_tgt_priv(scst_cmd_get_session(scst_cmd));
+       
+       prm.sg = NULL;
+       prm.bufflen = scst_cmd_get_resp_data_len(scst_cmd);
+       prm.buffer = scst_cmd->sg;
+       prm.use_sg = scst_cmd->sg_cnt;
+       prm.data_direction = scst_cmd_get_data_direction(scst_cmd);
+       prm.rq_result = scst_cmd_get_status(scst_cmd);
+       prm.sense_buffer = scst_cmd_get_sense_buffer(scst_cmd);
+       prm.sense_buffer_len = scst_cmd_get_sense_buffer_len(scst_cmd);
+       prm.tgt = sess->tgt;
+       prm.seg_cnt = 0;
+       resp_flags = scst_cmd_get_tgt_resp_flags(scst_cmd);
+
+       /* FIXME */
+       prm.sense_buffer_len = 14;
+
+       TRACE_DBG("rq_result=%x, resp_flags=%x, %x, %d", prm.rq_result, 
+                       resp_flags, prm.bufflen, prm.sense_buffer_len);
+       if (prm.rq_result != 0)
+               TRACE_BUFFER("Sense", prm.sense_buffer, prm.sense_buffer_len);
+
+       if ((resp_flags & SCST_TSC_FLAG_STATUS) == 0) {
+               /* ToDo, after it's done in SCST */
+               PRINT_ERROR(MYNAM ": SCST_TSC_FLAG_STATUS not set: "
+                           "feature not implemented %p", scst_cmd);
+               res = SCST_TGT_RES_FATAL_ERROR;
+               goto out_tgt_free;
+       }
+       
+       if (test_bit(MPT_SESS_SHUTDOWN, &sess->sess_flags)) {
+               TRACE_DBG("cmd %p while session %p is shutting down",
+                         prm.cmd, sess);
+               res = SCST_TGT_RES_SUCCESS;
+               goto out_tgt_free;
+       }
+       
+       if (SCST_SENSE_VALID(prm.sense_buffer)) {
+               mpt_set_sense_info(prm.tgt->priv, prm.cmd->CMD, 
+                               prm.sense_buffer_len, prm.sense_buffer);
+       }
+
+       if (scst_cmd_get_resp_data_len(scst_cmd) > 0) {
+               int flags = 0;
+               if (prm.rq_result == 0) {
+                       flags |= TARGET_ASSIST_FLAGS_AUTO_STATUS;
+               }
+               if (scst_get_may_need_dma_sync(scst_cmd)) {
+                       dma_sync_sg(&(prm.tgt->priv->ioc->pcidev->dev),
+                               scst_cmd->sg, scst_cmd->sg_cnt,
+                               scst_to_tgt_dma_dir(scst_cmd_get_data_direction(scst_cmd)));
+               }
+               mpt_send_target_data(&prm, flags);
+               
+               if (prm.rq_result == 0) {
+                       goto out;
+               }
+       }
+       {
+               int flags = 0;
+               u32 reply_word = prm.cmd->CMD->reply_word;
+               int index = GET_IO_INDEX(reply_word);
+               int lun = prm.cmd->CMD->lun;
+               int tag = prm.cmd->CMD->tag;
+               MPT_STM_PRIV *priv = prm.tgt->priv;
+
+               if (prm.rq_result == 0) {
+                       flags |= TARGET_STATUS_SEND_FLAGS_AUTO_GOOD_STATUS;
+               }
+
+               flags |= TARGET_STATUS_SEND_FLAGS_REPOST_CMD_BUFFER;
+               priv->io_state[index] |= IO_STATE_AUTO_REPOST;
+
+               TRACE_DBG("scst cmd %p, index %d, flags %d",
+                               scst_cmd, index, flags);
+
+               stm_send_target_status(priv, reply_word, index, 
+                               flags, lun, tag);
+       }
+
+ out:
+       TRACE_EXIT_RES(res);
+       
+       return res;
+
+ out_tgt_free:
+       scst_tgt_cmd_done(scst_cmd);
+       goto out;
+}
+
+/*
+ * this function 
+ * informs the driver that data buffer corresponding to the said command
+ * have now been allocated and it is OK to receive data for this command.
+ * This function is necessary because a SCSI target does not have any
+ * control over the commands it receives. Most lower-level protocols have a
+ * corresponding function which informs the initiator that buffers have
+ * been allocated e.g., XFER_RDY in Fibre Channel. After the data is
+ * actually received the low-level driver should call scst_rx_data()
+ * in order to continue processing this command. Returns one of the
+ * SCST_TGT_RES_* constants, described below. Pay attention to
+ * "atomic" attribute of the command, which can be get via
+ * scst_cmd_get_atomic(): it is true if the function called in the
+ * atomic (non-sleeping) context. Must be defined.
+ */
+static int mpt_rdy_to_xfer(struct scst_cmd *scst_cmd)
+{
+       int res = SCST_TGT_RES_SUCCESS;
+       struct mpt_sess *sess;
+       /*unsigned long flags = 0;*/
+       struct mpt_prm prm = { 0 };
+
+       TRACE_ENTRY();
+       prm.cmd = (struct mpt_cmd *)scst_cmd_get_tgt_priv(scst_cmd);
+       sess = (struct mpt_sess *)
+               scst_sess_get_tgt_priv(scst_cmd_get_session(scst_cmd));
+
+       prm.sg = (struct scatterlist *)NULL;
+       prm.bufflen = scst_cmd->bufflen;
+       prm.buffer = scst_cmd->sg;
+       prm.use_sg = scst_cmd->sg_cnt;
+       prm.data_direction = scst_cmd_get_data_direction(scst_cmd);
+       prm.tgt = sess->tgt;
+       
+       if (test_bit(MPT_SESS_SHUTDOWN, &sess->sess_flags)) {
+               TRACE_DBG("cmd %p while session %p is shutting down",
+                         prm.cmd, sess);
+               scst_rx_data(scst_cmd, SCST_RX_STATUS_ERROR_FATAL,
+                            SCST_CONTEXT_THREAD);
+               res = SCST_TGT_RES_SUCCESS;
+               goto out;
+       }
+       
+       prm.cmd->state = MPT_STATE_NEED_DATA;
+       
+       mpt_send_target_data(&prm, 0);
+       
+ out:
+       TRACE_EXIT_RES(res);
+       
+       return res;
+}
+
+/*
+ * this function
+ * called to notify the driver that the command is about to be freed.
+ * Necessary, because for aborted commands <bf/xmit_response()/ could not be
+ * called. Could be used on IRQ context. Must be defined.
+ */
+static void mpt_on_free_cmd(struct scst_cmd *scst_cmd)
+{
+       struct mpt_cmd *cmd =
+               (struct mpt_cmd *)scst_cmd_get_tgt_priv(scst_cmd);
+       MPT_STM_PRIV *priv = cmd->priv;
+       int index = GET_IO_INDEX(cmd->reply_word);
+       //MPT_ADAPTER *ioc = priv->ioc;
+
+       TRACE_ENTRY();
+       
+       TRACE_DBG("scst_cmd is %p, cmd %p, %p", 
+                       priv->scst_cmd[index], cmd, scst_cmd);
+       WARN_ON(priv->scst_cmd[index] != scst_cmd);
+       priv->scst_cmd[index] = NULL;
+
+       scst_cmd_set_tgt_priv(scst_cmd, NULL);
+
+#if 1
+       memset(cmd, 0, sizeof(*cmd));
+#endif
+       kfree(cmd);
+
+       TRACE_EXIT();
+}
+
+/*
+ * this function informs the driver that a received task management
+ * function has been completed. Completion status could be get via
+ * scst_mgmt_cmd_get_status(). No return value expected. Must be
+ * defined, if the target supports task management functionality.
+ */
+static void 
+mpt_task_mgmt_fn_done(struct scst_mgmt_cmd *mgmt_cmd)
+{
+       TRACE_ENTRY();
+       WARN_ON(1);
+       TRACE_EXIT();
+}
+
+static void
+mpt_local_task_mgmt(struct mpt_sess *sess, int task_mgmt, int lun)
+{
+       struct mpt_cmd *cmd, *t;
+       
+       TRACE_ENTRY();
+       switch (task_mgmt) {
+       case IMM_NTFY_TARGET_RESET:
+               while (!list_empty(&sess->delayed_cmds)) {
+                       cmd = list_entry(sess->delayed_cmds.next,
+                                        typeof(*cmd), delayed_cmds_entry);
+                       list_del(&cmd->delayed_cmds_entry);
+                       kfree(cmd);
+               }
+               break;
+
+       case IMM_NTFY_LUN_RESET1:
+       case IMM_NTFY_LUN_RESET2:
+       case IMM_NTFY_CLEAR_TS:
+       case IMM_NTFY_ABORT_TS:
+               list_for_each_entry_safe(cmd, t, &sess->delayed_cmds,
+                                        delayed_cmds_entry)
+                       {
+                               if (cmd->CMD->lun == lun) {
+                                       list_del(&cmd->delayed_cmds_entry);
+                                       kfree(cmd);
+                               }
+                       }
+               break;
+               
+       case IMM_NTFY_CLEAR_ACA:
+       default:
+               break;
+       }
+       TRACE_EXIT();
+}
+
+static int 
+mpt_handle_task_mgmt(MPT_STM_PRIV *priv, u32 reply_word,
+                    int task_mgmt, int _lun)
+{
+       int res = 0, rc = 0;
+       struct mpt_mgmt_cmd *mcmd;
+       struct mpt_tgt *tgt;
+       struct mpt_sess *sess;
+       int init_index;
+       uint16_t lun = _lun;
+
+       TRACE_ENTRY();
+       
+       TRACE_DBG("task_mgmt %d", task_mgmt);
+       tgt = priv->tgt;
+       init_index = GET_INITIATOR_INDEX(reply_word);
+       
+       sess = tgt->sess[init_index];
+       if (sess == NULL) {
+               TRACE(TRACE_MGMT, "mpt_scst(%s): task mgmt fn %p for "
+                     "unexisting session", priv->ioc->name, tgt);
+               res = -EFAULT;
+               goto out;
+       }
+       
+       if (test_bit(MPT_SESS_INITING, &sess->sess_flags)) {
+               TRACE(TRACE_MGMT, "mpt_scst(%s): task mgmt fn %p for "
+                     "inited session", priv->ioc->name, tgt);
+               mpt_local_task_mgmt(sess, reply_word, task_mgmt);
+               res = -EFAULT;
+               goto out;
+       }
+       
+       mcmd = kmalloc(sizeof(*mcmd), GFP_ATOMIC);
+       TRACE_MEM("kmalloc(GFP_ATOMIC) for mcmd (%d): %p",
+                 sizeof(*mcmd), mcmd);
+       if (mcmd == NULL) {
+               TRACE(TRACE_OUT_OF_MEM, "%s", "Allocation of mgmt cmd failed");
+               res = -ENOMEM;
+               goto out;
+       }
+
+       memset(mcmd, 0, sizeof(*mcmd));
+       mcmd->sess = sess;
+       mcmd->task_mgmt = task_mgmt;
+       
+       switch(task_mgmt) {
+       case IMM_NTFY_CLEAR_ACA:
+               TRACE(TRACE_MGMT, "%s", "IMM_NTFY_CLEAR_ACA received");
+               rc = scst_rx_mgmt_fn_lun(sess->scst_sess, SCST_CLEAR_ACA,
+                                        (uint8_t *)&lun, sizeof(lun),
+                                        SCST_ATOMIC, mcmd);
+               break;
+       case IMM_NTFY_TARGET_RESET:
+               TRACE(TRACE_MGMT, "%s", "IMM_NTFY_TARGET_RESET received");
+               rc = scst_rx_mgmt_fn_lun(sess->scst_sess, SCST_TARGET_RESET,
+                                        (uint8_t *)&lun, sizeof(lun),
+                                        SCST_ATOMIC, mcmd);
+               break;
+       case IMM_NTFY_LUN_RESET1:
+       case IMM_NTFY_LUN_RESET2:
+               TRACE(TRACE_MGMT, "%s", "IMM_NTFY_LUN_RESET received");
+               rc = scst_rx_mgmt_fn_lun(sess->scst_sess, SCST_LUN_RESET,
+                                        (uint8_t *)&lun, sizeof(lun),
+                                        SCST_ATOMIC, mcmd);
+               break;
+       case IMM_NTFY_CLEAR_TS:
+               TRACE(TRACE_MGMT, "%s", "IMM_NTFY_CLEAR_TS received");
+               rc = scst_rx_mgmt_fn_lun(sess->scst_sess, SCST_CLEAR_TASK_SET,
+                                        (uint8_t *)&lun, sizeof(lun),
+                                        SCST_ATOMIC, mcmd);
+               break;
+               
+       case IMM_NTFY_ABORT_TS:
+               TRACE(TRACE_MGMT, "%s", "IMM_NTFY_ABORT_TS received");
+               rc = scst_rx_mgmt_fn_lun(sess->scst_sess, SCST_ABORT_TASK_SET,
+                                        (uint8_t *)&lun, sizeof(lun),
+                                        SCST_ATOMIC, mcmd);
+               break;
+
+       default:
+               PRINT_ERROR("mpt_scst(%s): Unknown task mgmt fn 0x%x",
+                           priv->ioc->name, task_mgmt);
+               break;
+       }
+       if (rc != 0) {
+               PRINT_ERROR("mpt_scst(%s): scst_rx_mgmt_fn_lun() failed: %d",
+                           priv->ioc->name, rc);
+               res = -EFAULT;
+               goto out_free;
+       }
+
+ out:
+       TRACE_EXIT_RES(res);
+       return res;
+
+ out_free:
+       TRACE_MEM("kmem_cache_free for mcmd %p", mcmd);
+       kfree(mcmd);
+       goto out;
+}
+
+
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *  called when any target mode reply is received
+ *  if mf_req is null, then this is a turbo reply; otherwise it's not
+ */
+static int
+stm_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf_req, MPT_FRAME_HDR *mf_rep)
+{
+    MPT_STM_PRIV       *priv = mpt_stm_priv[ioc->id];
+    MPIDefaultReply_t  *rep = (MPIDefaultReply_t *)mf_rep;
+    int        ioc_status;
+
+       TRACE_ENTRY();
+       if (mf_req == NULL) {
+               TRACE_DBG("%s: got turbo reply, reply %x",
+                               ioc->name, CAST_PTR_TO_U32(mf_rep));
+               /*
+                *  this is a received SCSI command, so go handle it
+                */
+               stm_tgt_reply(ioc, CAST_PTR_TO_U32(mf_rep));
+               return 0;
+       }
+
+#if 0
+    if (rep->Function == MPI_FUNCTION_EVENT_NOTIFICATION) {
+       /*
+        *  this is an event notification -- do nothing for now
+        *  (this short-cuts the switch() below and avoids the printk)
+        */
+       return (0);
+    }
+#endif
+    ioc_status = le16_to_cpu(rep->IOCStatus);
+
+    TRACE_DBG("%s: request %p, reply %p (%02x), %d",
+             ioc->name, mf_req, mf_rep, rep->Function, ioc_status);
+    TRACE_DBG("%s: mf index = %d", ioc->name, MF_TO_INDEX(mf_req));
+
+       if (ioc_status & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
+               TRACE_DBG("%s Function = %02x, IOCStatus = %04x, IOCLogInfo = %08x",
+                               ioc->name, rep->Function, ioc_status,
+                               le32_to_cpu(rep->IOCLogInfo));
+       }
+
+    ioc_status &= MPI_IOCSTATUS_MASK;
+    switch (rep->Function) {
+       case MPI_FUNCTION_CONFIG:
+           /*
+            *  this signals that the config is done
+            */
+           priv->config_pending = 0;
+           memcpy(&priv->config_rep, rep, sizeof(ConfigReply_t));
+           /*
+            *  don't free the message frame, since we're remembering it
+            *  in priv->config_mf, and we'll be using it over and over
+            */
+           return (0);
+
+       case MPI_FUNCTION_PORT_ENABLE:
+           /*
+            *  this signals that the port enable is done
+            */
+           priv->port_enable_loginfo = le32_to_cpu(rep->IOCLogInfo);
+           priv->port_enable_pending = 0;
+           return (1);
+
+       case MPI_FUNCTION_TARGET_CMD_BUFFER_POST:
+       case MPI_FUNCTION_TARGET_CMD_BUF_LIST_POST:
+           /*
+            *  this is the response to a command buffer post; if status
+            *  is success, then this just acknowledges the posting of a
+            *  command buffer, so do nothing
+            *
+            *  we can also get here for High Priority I/O (such as getting
+            *  a command while not being allowed to disconnect from the SCSI
+            *  bus), and if we're shutting down
+            */
+               if (ioc_status == MPI_IOCSTATUS_SUCCESS) {
+                       TRACE_EXIT();
+                       return 1;
+               }
+               if (priv->target_mode_abort_pending &&
+                               ioc_status == MPI_IOCSTATUS_TARGET_ABORTED) {
+                       TRACE_EXIT();
+                       return (0);
+               }
+               if (ioc_status == MPI_IOCSTATUS_TARGET_PRIORITY_IO) {
+                       stm_tgt_reply_high_pri(ioc,
+                                       (TargetCmdBufferPostErrorReply_t *)rep);
+                       TRACE_EXIT();
+                       return (0);
+               }
+               TRACE_DBG(":%s TargetCmdBufPostReq IOCStatus = %04x",
+                               ioc->name, ioc_status);
+               if (ioc_status == MPI_IOCSTATUS_INSUFFICIENT_RESOURCES) {
+                       /*
+                        *  this should never happen since we carefully count
+                        *  our resources, but if it does, tolerate it -- don't
+                        *  repost the errant command buffer, lest we create an
+                        *  endless loop
+                        */
+                       WARN_ON(1);
+                       return (0);
+               }
+               if (ioc_status == MPI_IOCSTATUS_TARGET_NO_CONNECTION) {
+                       printk(KERN_ERR MYNAM 
+                                       ": %s: Got MPI_IOCSTATUS_TARGET_NO_CONNECTION\n",
+                                       ioc->name);
+                       return (0);
+               }
+               if (rep->MsgLength > sizeof(*rep)/sizeof(u32)) {
+                       TRACE_DBG("MsgLength is %d, %d", 
+                                       rep->MsgLength, sizeof(*rep)/sizeof(u32));
+                       WARN_ON(1);
+                       /*
+                        *  the TargetCmdBufferPostErrorReply and TargetErrorReply
+                        *  structures are nearly identical; the exception is that
+                        *  the former does not have a TransferCount field, while
+                        *  the latter does; add one
+                        */
+                       ((TargetErrorReply_t *)rep)->TransferCount = 0;
+                       stm_target_reply_error(ioc, (TargetErrorReply_t *)rep);
+                       return (0);
+               }
+               WARN_ON(1);
+           return (1);
+
+       case MPI_FUNCTION_TARGET_CMD_BUF_BASE_POST:
+           /*
+            *  this signals that the command buffer base post is done
+            */
+           if (ioc_status != MPI_IOCSTATUS_SUCCESS) {
+               printk(KERN_ERR MYNAM ":%s TargetCmdBufPostBaseReq IOCStatus = %04x\n",
+                      ioc->name, ioc_status);
+           }
+           return (1);
+
+       case MPI_FUNCTION_TARGET_ASSIST:
+           /*
+            *  this is the response to a target assist command; we should
+            *  only get here if an error occurred
+            *
+            *  at this point we need to clean up the remains of the I/O
+            *  and repost the command buffer
+            */
+           if (ioc_status != MPI_IOCSTATUS_SUCCESS) {
+               printk(KERN_ERR MYNAM ":%s TargetAssistReq IOCStatus = %04x\n",
+                      ioc->name, ioc_status);
+           }
+           stm_target_reply_error(ioc, (TargetErrorReply_t *)rep);
+           return (0);
+
+       case MPI_FUNCTION_TARGET_STATUS_SEND:
+           /*
+            *  this is the response to a target status send command; we should
+            *  only get here if an error occurred
+            *
+            *  at this point we need to clean up the remains of the I/O
+            *  and repost the command buffer
+            */
+           if (ioc_status != MPI_IOCSTATUS_SUCCESS) {
+               printk(KERN_ERR MYNAM ":%s TargetStatusSendReq IOCStatus = %04x\n",
+                      ioc->name, ioc_status);
+           }
+           stm_target_reply_error(ioc, (TargetErrorReply_t *)rep);
+           return (0);
+
+       case MPI_FUNCTION_TARGET_MODE_ABORT: {
+           TargetModeAbort_t           *req = (TargetModeAbort_t *)mf_req;
+
+           /*
+            *  this signals that the target mode abort is done
+            */
+           if (ioc_status != MPI_IOCSTATUS_SUCCESS) {
+               printk(KERN_ERR MYNAM ":%s TargetModeAbort IOCStatus = %04x\n",
+                      ioc->name, ioc_status);
+           }
+           if (req->AbortType == TARGET_MODE_ABORT_TYPE_ALL_CMD_BUFFERS) {
+               priv->target_mode_abort_pending = 0;
+           } else {
+               u32             reply_word;
+               int             index;
+               volatile int    *io_state;
+
+               /*
+                *  a target mode abort has finished, so check to see if
+                *  the I/O was aborted, but there was no error reply for
+                *  that aborted I/O (this will be the case for I/Os that
+                *  have no outstanding target assist or target status send
+                *  at the time of the abort request) -- so pretend that
+                *  the error reply came in with a status indicating that
+                *  the I/O was aborted
+                */
+               reply_word = le32_to_cpu(req->ReplyWord);
+               index = GET_IO_INDEX(reply_word);
+               io_state = priv->io_state + index;
+               if ((*io_state & IO_STATE_ABORTED) &&
+                   !(*io_state & IO_STATE_DATA_SENT) &&
+                   !(*io_state & IO_STATE_STATUS_SENT)) {
+                   stmapp_target_error(priv, reply_word, index,
+                                       MPI_IOCSTATUS_TARGET_ABORTED, 0);
+               }
+               /*
+               *  see if we were trying to abort a target assist or target
+               *  status send, but the abort didn't work (if the abort had
+               *  worked, the flag we're checking would be clear) -- if so,
+               *  just clear the various SRR flags, and wait for the initiator
+               *  to retry the SRR
+               */
+               if (*io_state & IO_STATE_REQUEST_ABORTED) {
+                   printk(KERN_ERR MYNAM ":%s index %d: io_state = %x\n",
+                          ioc->name, index, *io_state);
+                   printk(KERN_ERR MYNAM ":%s   request was not aborted\n",
+                          ioc->name);
+                   *io_state &= ~IO_STATE_REQUEST_ABORTED;
+                   *io_state &= ~IO_STATE_REISSUE_REQUEST;
+                   *io_state &= ~IO_STATE_ADJUST_OFFSET;
+                   *io_state &= ~IO_STATE_CONVERT_TA_TO_TSS;
+                   *io_state &= ~IO_STATE_REDO_COMMAND;
+               }
+           }
+               TRACE_EXIT_RES(1);
+           return (1);
+       }
+
+       case MPI_FUNCTION_FC_LINK_SRVC_BUF_POST:
+           /*
+            *  if the length is that of a default reply, then this is the
+            *  response to a link service buffer post -- do nothing except
+            *  report errors (none are expected); otherwise this is a
+            *  received ELS, so go handle it
+            */
+           if (ioc_status != MPI_IOCSTATUS_SUCCESS) {
+               if (priv->link_serv_abort_pending &&
+                   ioc_status == MPI_IOCSTATUS_FC_ABORTED) {
+                   return (0);
+               }
+               printk(KERN_ERR MYNAM ":%s FcLinkServBufPostReq IOCStatus = %04x\n",
+                      ioc->name, ioc_status);
+           }
+           if (rep->MsgLength > sizeof(*rep)/sizeof(u32)) {
+               stm_link_service_reply(ioc,
+                                      (LinkServiceBufferPostReply_t *)rep);
+               return (0);
+           }
+           return (1);
+
+       case MPI_FUNCTION_FC_LINK_SRVC_RSP:
+           /*
+            *  this is the response to a link service send -- repost the
+            *  link service command buffer
+            */
+           if (ioc_status != MPI_IOCSTATUS_SUCCESS) {
+               printk(KERN_ERR MYNAM ":%s FcLinkServRspReq IOCStatus = %04x\n",
+                      ioc->name, ioc_status);
+           }
+           stm_link_service_rsp_reply(ioc,
+                                      (LinkServiceRspRequest_t *)mf_req,
+                                      (LinkServiceRspReply_t *)mf_rep);
+           return (1);
+
+       case MPI_FUNCTION_FC_ABORT:
+           /*
+            *  this signals that the target mode abort is done
+            */
+           if (ioc_status != MPI_IOCSTATUS_SUCCESS) {
+               printk(KERN_ERR MYNAM ":%s FcAbort IOCStatus = %04x\n",
+                      ioc->name, ioc_status);
+           }
+           priv->link_serv_abort_pending = 0;
+           return (1);
+
+       case MPI_FUNCTION_FC_PRIMITIVE_SEND:
+           /*
+            *  this signals that the FC primitive send is done
+            */
+           if (ioc_status != MPI_IOCSTATUS_SUCCESS) {
+               printk(KERN_ERR MYNAM ":%s FcPrimitiveSend IOCStatus = %04x\n",
+                      ioc->name, ioc_status);
+           }
+           priv->fc_primitive_send_pending = 0;
+           return (1);
+
+       case MPI_FUNCTION_FC_EX_LINK_SRVC_SEND:
+           /*
+            *  this signals that the extended link service send is done
+            */
+           if (ioc_status != MPI_IOCSTATUS_SUCCESS) {
+               printk(KERN_ERR MYNAM ":%s ExLinkServiceSend IOCStatus = %04x\n",
+                      ioc->name, ioc_status);
+           }
+           priv->ex_link_service_send_pending = 0;
+           return (1);
+
+       default:
+           /*
+            *  don't understand this reply, so dump to the screen
+            */
+           printk(KERN_ERR MYNAM ":%s got a reply (function %02x) that "
+                  "I don't know what to do with\n", ioc->name, rep->Function);
+if(1)
+{
+           u32 *p = (u32 *)mf_req;
+           int i;
+
+           for (i = 0; i < 16; i++) {
+               printk("%s mf_req[%02x] = %08x\n",
+                      ioc->name, i * 4, le32_to_cpu(p[i]));
+           }
+}
+if(1)
+{
+           u32 *p = (u32 *)mf_rep;
+           int i;
+
+           for (i = 0; i < 16; i++) {
+               printk("%s mf_rep[%02x] = %08x\n",
+                      ioc->name, i * 4, le32_to_cpu(p[i]));
+           }
+}
+           break;
+    }
+       TRACE_EXIT();
+    return (0);
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static void
+stm_tgt_reply_high_pri(MPT_ADAPTER *ioc, TargetCmdBufferPostErrorReply_t *rep)
+{
+       MPT_STM_PRIV    *priv = mpt_stm_priv[ioc->id];
+       u32                     reply_word;
+       int                     reason;
+       int                     index;
+
+       TRACE_ENTRY();
+       reply_word = le32_to_cpu(rep->ReplyWord);
+       reason = rep->PriorityReason;
+
+       index = GET_IO_INDEX(reply_word);
+
+       TRACE_DBG("%s: target reply high priority", ioc->name);
+       TRACE_DBG("%s: ReplyWord = %08x, PriorityReason = %02x",
+                       ioc->name, reply_word, reason);
+
+       priv->io_state[index] |= IO_STATE_HIGH_PRIORITY;
+       if (reason == PRIORITY_REASON_NO_DISCONNECT ||
+                       reason == PRIORITY_REASON_SCSI_TASK_MANAGEMENT) {
+               stm_tgt_reply(ioc, reply_word);
+               goto out;       
+       } 
+
+       WARN_ON(1);
+       if (reason == PRIORITY_REASON_TARGET_BUSY) {
+               CMD             *cmd;
+               int             lun;
+               int             tag;
+
+               priv->io_state[index] &= ~IO_STATE_POSTED;
+               cmd = &priv->hw->cmd_buf[index];
+               if (IsScsi(priv)) {
+                       SCSI_CMD        *scsi_cmd = (SCSI_CMD *)cmd->cmd;
+
+                       lun = get2bytes(scsi_cmd->LogicalUnitNumber, 0);
+                       tag = scsi_cmd->Tag;
+               } else if (IsSas(priv)) {
+                       SSP_CMD *ssp_cmd = (SSP_CMD *)cmd->cmd;
+
+                       lun = get2bytes(ssp_cmd->LogicalUnitNumber, 0);
+                       tag = ssp_cmd->InitiatorTag;
+               } else {
+                       FCP_CMD *fcp_cmd = (FCP_CMD *)cmd->cmd;
+
+                       lun = get2bytes(fcp_cmd->FcpLun, 0);
+                       tag = 0;
+               }
+               memset(cmd->rsp, 0, sizeof(cmd->rsp));
+               stmapp_set_status(priv, cmd, STS_TASK_SET_FULL);
+               stm_send_target_status(priv, reply_word, index, 0, lun, tag);
+       } else {
+               stmapp_target_error(priv, reply_word, index,
+                               MPI_IOCSTATUS_TARGET_PRIORITY_IO, reason);
+       }
+out:
+       TRACE_EXIT();
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static void
+stm_target_reply_error(MPT_ADAPTER *ioc,
+                      TargetErrorReply_t *rep)
+{
+    MPT_STM_PRIV       *priv = mpt_stm_priv[ioc->id];
+    u32                        reply_word;
+    int                        index;
+    int                        status;
+    int                        reason;
+    volatile int       *io_state;
+
+       TRACE_ENTRY();
+    reply_word = le32_to_cpu(rep->ReplyWord);
+    status = le16_to_cpu(rep->IOCStatus) & MPI_IOCSTATUS_MASK;
+
+    index = GET_IO_INDEX(reply_word);
+
+    io_state = priv->io_state + index;
+
+       if (status == MPI_IOCSTATUS_TARGET_PRIORITY_IO) {
+               reason = rep->PriorityReason;
+               *io_state |= IO_STATE_HIGH_PRIORITY;
+       } else {
+               reason = 0;
+       }
+
+    TRACE_DBG("%s: target reply error", ioc->name);
+    TRACE_DBG("%s: ReplyWord = %08x, IOCStatus = %04x",
+          ioc->name, reply_word, status);
+
+       if (*io_state & IO_STATE_REQUEST_ABORTED) {
+               TRACE_DBG("%s: index %d: io_state = %x",
+                               ioc->name, index, *io_state);
+               TRACE_DBG("%s:   request was aborted", ioc->name);
+               *io_state &= ~IO_STATE_REQUEST_ABORTED;
+               if (*io_state & IO_STATE_REISSUE_REQUEST) {
+                       *io_state &= ~IO_STATE_REISSUE_REQUEST;
+                       TRACE_DBG("%s:   being reissued", ioc->name);
+                       if (*io_state & IO_STATE_ADJUST_OFFSET) {
+                               *io_state &= ~IO_STATE_ADJUST_OFFSET;
+                               stmapp_srr_adjust_offset(priv, index);
+                       }
+                       if (*io_state & IO_STATE_CONVERT_TA_TO_TSS) {
+                               *io_state &= ~IO_STATE_CONVERT_TA_TO_TSS;
+                               stmapp_srr_convert_ta_to_tss(priv, index);
+                               goto out;
+                       }
+                       if (*io_state & IO_STATE_REDO_COMMAND) {
+                               *io_state &= ~IO_STATE_REDO_COMMAND;
+                               *io_state &= ~IO_STATE_DATA_SENT;
+                               *io_state &= ~IO_STATE_STATUS_SENT;
+                               mpt_free_msg_frame(_HANDLE_IOC_ID, priv->current_mf[index]);
+                               stmapp_tgt_command(priv, reply_word);
+                               goto out;
+                       }
+                       mpt_put_msg_frame(stm_context, _IOC_ID, priv->current_mf[index]);
+                       goto out;
+               }
+       }
+
+    stmapp_target_error(priv, reply_word, index, status, reason);
+out:
+       TRACE_EXIT();
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static void
+stm_target_cleanup(MPT_STM_PRIV *priv,
+                  int index)
+{
+    MPT_ADAPTER                *ioc = priv->ioc;
+    volatile int       *io_state;
+
+       TRACE_ENTRY();
+       io_state = priv->io_state + index;
+       if (*io_state & (IO_STATE_DATA_SENT | IO_STATE_STATUS_SENT)) {
+               *io_state &= ~IO_STATE_DATA_SENT;
+               *io_state &= ~IO_STATE_STATUS_SENT;
+               mpt_free_msg_frame(_HANDLE_IOC_ID, priv->current_mf[index]);
+       }
+       if (*io_state & IO_STATE_STATUS_DEFERRED) {
+               *io_state &= ~IO_STATE_STATUS_DEFERRED;
+               mpt_free_msg_frame(_HANDLE_IOC_ID, priv->status_deferred_mf[index]);
+       }
+       *io_state &= ~IO_STATE_REISSUE_REQUEST;
+       *io_state &= ~IO_STATE_ADJUST_OFFSET;
+       *io_state &= ~IO_STATE_CONVERT_TA_TO_TSS;
+       *io_state &= ~IO_STATE_REDO_COMMAND;
+       *io_state &= ~IO_STATE_REQUEST_ABORTED;
+       *io_state &= ~IO_STATE_INCOMPLETE;
+       //  *io_state &= ~IO_STATE_AUTO_REPOST;
+       *io_state &= ~IO_STATE_ABORTED;
+       *io_state &= ~IO_STATE_POSTED;
+       if ((*io_state & ~IO_STATE_HIGH_PRIORITY) == IO_STATE_AUTO_REPOST) {
+               *io_state = IO_STATE_POSTED;
+       } else if ((*io_state & ~IO_STATE_HIGH_PRIORITY) == 0) {
+               stm_cmd_buf_post(priv, index);
+       }
+       TRACE_EXIT();
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+stm_event_process(MPT_ADAPTER *ioc,
+                 EventNotificationReply_t *rep)
+{
+    MPT_STM_PRIV               *priv = mpt_stm_priv[ioc->id];
+    EventDataScsi_t            *scsi_data;
+    EventDataLinkStatus_t      *link_status_data;
+    EventDataLoopState_t       *loop_state_data;
+    EventDataLogout_t          *logout_data;
+    EventDataSasPhyLinkStatus_t *sas_phy_link_status_data;
+    int                                id;
+    int                                i;
+    int                                ioc_status;
+    int                                event;
+    int                                rate;
+
+       TRACE_ENTRY();
+    if (priv == NULL) {
+               return (1);
+       }
+
+    ioc_status = le16_to_cpu(rep->IOCStatus);
+    event = le32_to_cpu(rep->Event);
+
+       if (ioc_status & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
+               printk("%s Event = %x, IOCLogInfo = %08x\n",
+                               ioc->name, event, le32_to_cpu(rep->IOCLogInfo));
+       }
+
+    switch (event) {
+       case MPI_EVENT_NONE:
+       case MPI_EVENT_LOG_DATA:
+       case MPI_EVENT_STATE_CHANGE:
+       case MPI_EVENT_UNIT_ATTENTION:
+       case MPI_EVENT_EVENT_CHANGE:
+       case MPI_EVENT_INTEGRATED_RAID:
+       case MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE:
+       case MPI_EVENT_ON_BUS_TIMER_EXPIRED:
+       case MPI_EVENT_QUEUE_FULL:
+       case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
+       case MPI_EVENT_SAS_SES:
+       case MPI_EVENT_PERSISTENT_TABLE_FULL:
+       case MPI_EVENT_SAS_DISCOVERY_ERROR:
+           break;
+
+       case MPI_EVENT_RESCAN:
+           printk("%s Rescan\n", ioc->name);
+           break;
+
+       case MPI_EVENT_IOC_BUS_RESET:
+           scsi_data = (EventDataScsi_t *)rep->Data;
+           printk("%s IOC Bus Reset on port %d\n",
+                  ioc->name, scsi_data->BusPort);
+           break;
+
+       case MPI_EVENT_EXT_BUS_RESET:
+           scsi_data = (EventDataScsi_t *)rep->Data;
+           printk("%s Ext Bus Reset on port %d\n",
+                  ioc->name, scsi_data->BusPort);
+           break;
+
+       case MPI_EVENT_LINK_STATUS_CHANGE:
+           link_status_data = (EventDataLinkStatus_t *)rep->Data;
+           printk("%s Link is now %s\n",
+                  ioc->name, link_status_data->State ? "Up" : "Down");
+           break;
+
+       case MPI_EVENT_LOGOUT:
+           logout_data = (EventDataLogout_t *)rep->Data;
+           id = le32_to_cpu(logout_data->NPortID);
+           break;
+
+       case MPI_EVENT_LOOP_STATE_CHANGE:
+           loop_state_data = (EventDataLoopState_t *)rep->Data;
+           if (loop_state_data->Type == MPI_EVENT_LOOP_STATE_CHANGE_LIP) {
+               printk("%s LIP Reset\n", ioc->name);
+               break;
+           } /* fall-through */
+
+       case MPI_EVENT_SAS_PHY_LINK_STATUS:
+           sas_phy_link_status_data = (EventDataSasPhyLinkStatus_t *)rep->Data;
+           rate = (sas_phy_link_status_data->LinkRates &
+                   MPI_EVENT_SAS_PLS_LR_CURRENT_MASK) >>
+                    MPI_EVENT_SAS_PLS_LR_CURRENT_SHIFT;
+           printk("%s Phy %d Handle %x is now %s\n",
+                  ioc->name, sas_phy_link_status_data->PhyNum,
+                  le16_to_cpu(sas_phy_link_status_data->DevHandle),
+                  rate == MPI_EVENT_SAS_PLS_LR_RATE_UNKNOWN ? "offline" :
+                  rate == MPI_EVENT_SAS_PLS_LR_RATE_PHY_DISABLED ? "disabled" :
+                  rate == MPI_EVENT_SAS_PLS_LR_RATE_1_5 ? "online at 1.5 Gb" :
+                  rate == MPI_EVENT_SAS_PLS_LR_RATE_3_0 ? "online at 3.0 Gb" :
+                  "unknown");
+           break;
+
+       default:
+           printk("%s event = %d, ack = %d, length = %d\n",
+                  ioc->name, le32_to_cpu(rep->Event),
+                  rep->AckRequired, le16_to_cpu(rep->EventDataLength));
+           for (i = 0; i < le16_to_cpu(rep->EventDataLength); i++) {
+               printk("%s data[%d] = %08x\n",
+                      ioc->name, i, le32_to_cpu(rep->Data[i]));
+           }
+           break;
+    }
+
+    if (event == MPI_EVENT_EXT_BUS_RESET) {
+#if 0
+       if (IsScsi(priv)) {
+           memset(priv->luns->drop, 0, sizeof(priv->luns->drop));
+       }
+#endif
+    }
+       TRACE_EXIT();
+
+    return (1);
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+stm_reset_process(MPT_ADAPTER *ioc, int phase)
+{
+    MPT_STM_PRIV       *priv = mpt_stm_priv[ioc->id];
+    int                        i;
+
+       TRACE_ENTRY();
+       if (priv == NULL)
+               return (1);
+
+       if (phase == MPT_IOC_PRE_RESET) {
+               printk(KERN_ERR MYNAM ":%s IOC will be reset\n",
+                               ioc->name);
+               priv->in_reset = 1;
+               priv->config_pending = 0;
+               for (i = 0; i < priv->num_cmd_buffers; i++)
+                       priv->io_state[i] = 0;
+       }
+
+       if (phase == MPT_IOC_POST_RESET) {
+               printk(KERN_ERR MYNAM ":%s IOC has been reset, restarting now\n",
+                               ioc->name);
+               mpt_stm_adapter_online(priv);
+       }
+
+       TRACE_EXIT();
+
+    return (1);
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static void
+stm_link_service_reply(MPT_ADAPTER *ioc, LinkServiceBufferPostReply_t *rep)
+{
+    MPT_STM_PRIV       *priv = mpt_stm_priv[ioc->id];
+    FC_ELS             *fc_els_buf;
+    int                        index;
+    int                        rctl;
+    int                        type;
+    int                        sid;
+    int                        did;
+    int                        command;
+    int                        i;
+    u32                        wwnnh;
+    u32                        wwnnl;
+    u32                        wwpnh;
+    u32                        wwpnl;
+    int                        ox_id;
+    int                        rx_id;
+    u32                        offset;
+
+       TRACE_ENTRY();
+    index = le32_to_cpu(rep->TransactionContext);
+    fc_els_buf = &priv->hw->fc_link_serv_buf[index];
+
+    rctl =
+       (le32_to_cpu(rep->Rctl_Did) & MPI_FC_RCTL_MASK) >> MPI_FC_RCTL_SHIFT;
+    type =
+       (le32_to_cpu(rep->Type_Fctl) & MPI_FC_TYPE_MASK) >> MPI_FC_TYPE_SHIFT;
+    sid =
+       (le32_to_cpu(rep->Csctl_Sid) & MPI_FC_SID_MASK) >> MPI_FC_SID_SHIFT;
+    did =
+       (le32_to_cpu(rep->Rctl_Did) & MPI_FC_DID_MASK) >> MPI_FC_DID_SHIFT;
+
+    wwnnh = le32_to_cpu(rep->Wwn.NodeNameHigh);
+    wwnnl = le32_to_cpu(rep->Wwn.NodeNameLow);
+    wwpnh = le32_to_cpu(rep->Wwn.PortNameHigh);
+    wwpnl = le32_to_cpu(rep->Wwn.PortNameLow);
+
+    ox_id = le16_to_cpu(rep->Oxid);
+    rx_id = le16_to_cpu(rep->Rxid);
+
+    /*
+     *  if this is a received PRLI/PRLO, respond by sending our own PRLI/PRLO
+     */
+    if (rctl == ELS && type == 0x01) {
+       command = (be32_to_cpu(fc_els_buf->fc_els[0]) >> 24) & 0xff;
+       switch (command) {
+           case PRLI:
+               TRACE_DBG("%s: PRLI to %06x from %06x (wwn %08x%08x)",
+                               ioc->name, did, sid, wwpnh, wwpnl);
+               i = be32_to_cpu(fc_els_buf->fc_els[4]);
+               fc_els_buf->fc_els[0] = cpu_to_be32(0x02100014);
+               fc_els_buf->fc_els[1] = cpu_to_be32(0x08002100);
+               fc_els_buf->fc_els[2] = cpu_to_be32(0x00000000);
+               fc_els_buf->fc_els[3] = cpu_to_be32(0x00000000);
+               fc_els_buf->fc_els[4] = cpu_to_be32(0x00000012);
+               if (priv->fcp2_capable)
+                   fc_els_buf->fc_els[4] |= cpu_to_be32(0x100);
+               priv->els_state[index] = PRLI;
+               stm_send_els(priv, rep, index, 20);
+               return;
+
+           case PRLO:
+               TRACE_DBG("%s: PRLO to %06x from %06x (wwn %08x%08x)",
+                       ioc->name, did, sid, wwpnh, wwpnl);
+               fc_els_buf->fc_els[0] = cpu_to_be32(0x02100014);
+               fc_els_buf->fc_els[1] = cpu_to_be32(0x08000100);
+               fc_els_buf->fc_els[2] = cpu_to_be32(0x00000000);
+               fc_els_buf->fc_els[3] = cpu_to_be32(0x00000000);
+               fc_els_buf->fc_els[4] = cpu_to_be32(0x00000000);
+               priv->els_state[index] = PRLO;
+               stm_send_els(priv, rep, index, 20);
+               return;
+
+           case RSCN:
+               TRACE_DBG("%s: RSCN", ioc->name);
+               stm_link_serv_buf_post(priv, index);
+               return;
+
+           default:
+               TRACE_DBG("%s: ELS %02x to %06x from %06x (wwn %08x%08x)",
+                       ioc->name, command, did, sid, wwpnh, wwpnl);
+               stm_link_serv_buf_post(priv, index);
+               return;
+       }
+    }
+
+    /*
+     *  if this is a received ABTS, respond by aborting the I/O and then
+     *  accepting it
+     */
+    if (rctl == ABTS && type == 0x00) {
+       TRACE_DBG("%s: ABTS to %06x from %06x (wwn %08x%08x)",
+               ioc->name, did, sid, wwpnh, wwpnl);
+       fc_els_buf->fc_els[0] = cpu_to_be32(0x00000000);
+       fc_els_buf->fc_els[1] = cpu_to_be32((ox_id << 16) | (rx_id << 0));
+       fc_els_buf->fc_els[2] = cpu_to_be32(0x0000ffff);
+       rep->Rctl_Did += cpu_to_le32((BA_ACC - ABTS) << MPI_FC_RCTL_SHIFT);
+       priv->els_state[index] = ABTS;
+       stmapp_abts_process(priv, rx_id, rep, index);
+       stm_send_els(priv, rep, index, 12);
+       return;
+    }
+
+    /*
+     *  if this is a received SRR, respond by aborting any current TargetAssist
+     *  or TargetStatusSend commands, accepting the SRR, and retransmitting the
+     *  requested data or status
+     */
+    if (rctl == FC4LS && type == 0x08) {
+       priv->els_state[index] = FC4LS;
+       command = (be32_to_cpu(fc_els_buf->fc_els[0]) >> 24) & 0xff;
+       switch (command) {
+           case SRR:
+               TRACE_DBG("%s: SRR to %06x from %06x (wwn %08x%08x)",
+                       ioc->name, did, sid, wwpnh, wwpnl);
+               rx_id = be32_to_cpu(fc_els_buf->fc_els[1]) & 0xffff;
+               /*
+                *  if the rx_id is out of range, reject this SRR with
+                *  "invalid OX_ID/RX_ID combination"
+                */
+               if (rx_id >= priv->num_cmd_buffers) {
+                   fc_els_buf->fc_els[0] = cpu_to_be32(0x01000000);
+                   fc_els_buf->fc_els[1] = cpu_to_be32(0x00090300);
+                   stm_send_els(priv, rep, index, 8);
+                   return;
+               }
+               i = (be32_to_cpu(fc_els_buf->fc_els[3]) >> 24) & 0xff;
+               /*
+                *  if the IU to retransmit is not a recognized IU, reject
+                *  this SRR with "logical error"
+                */
+               if (i != 1 && i != 5 && i != 7) {
+                   fc_els_buf->fc_els[0] = cpu_to_be32(0x01000000);
+                   fc_els_buf->fc_els[1] = cpu_to_be32(0x00030000);
+                   stm_send_els(priv, rep, index, 8);
+                   return;
+               }
+               offset = be32_to_cpu(fc_els_buf->fc_els[2]);
+               /*
+                *  go process this SRR further
+                *
+                *  make the call to stm_send_els when any request in progress
+                *  has been aborted
+                *
+                *  note that the address of the LinkServiceBufferPostReply
+                *  that's passed as a parameter to stmapp_abts_process CANNOT
+                *  BE REMEMBERED; its contents must be copied if the call to
+                *  stm_send_els will not be made synchronously
+                */
+               stmapp_srr_process(priv, rx_id, i, offset, rep, index);
+               return;
+
+           default:
+               TRACE_DBG("%s: FC4LS %02x to %06x from %06x (wwn %08x%08x)",
+                       ioc->name, command, did, sid, wwpnh, wwpnl);
+               /*
+                *  the only FC4LS we recognize is SRR; all others get
+                *  rejected with "command not supported"
+                */
+               fc_els_buf->fc_els[0] = cpu_to_be32(0x01000000);
+               fc_els_buf->fc_els[1] = cpu_to_be32(0x000b0000);
+               stm_send_els(priv, rep, index, 8);
+               return;
+       }
+    }
+
+#ifdef TRACING
+       if(trace_mpi)
+       {
+               u32 *p = (u32 *)rep;
+               int i;
+
+               for (i = 0; i < 17; i++) {
+                       TRACE(TRACE_MPI, "%s: fc_els[%02x] = %08x",
+                                       ioc->name, i * 4, le32_to_cpu(p[i]));
+               }
+       }
+       if(trace_mpi)
+       {
+               u32 *p = (u32 *)fc_els_buf;
+               int i;
+
+               for (i = 0; i < (int)le32_to_cpu(rep->TransferLength) / 4; i++) {
+                       TRACE(TRACE_MPI, "%s: fc_els_buf[%02x] = %08x",
+                                       ioc->name, i * 4, le32_to_cpu(p[i]));
+               }
+       }
+#endif
+
+    stm_link_serv_buf_post(priv, index);
+       TRACE_EXIT();
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static void
+stm_link_service_rsp_reply(MPT_ADAPTER *ioc,
+                          LinkServiceRspRequest_t *req,
+                          LinkServiceRspReply_t *rep)
+{
+    MPT_STM_PRIV       *priv = mpt_stm_priv[ioc->id];
+    MPT_STM_SIMPLE     *sge_simple;
+    int                        *p_index;
+    int                        index;
+    int                        sid;
+    int                        did;
+    int                        els;
+    int                        init_index;
+
+       TRACE_ENTRY();
+    sge_simple = (MPT_STM_SIMPLE *)&req->SGL;
+    p_index = (int *)(sge_simple + 1);
+    index = *p_index;
+    els = priv->els_state[index];
+
+    sid = (le32_to_cpu(req->Csctl_Sid) & MPI_FC_SID_MASK) >> MPI_FC_SID_SHIFT;
+    did = (le32_to_cpu(req->Rctl_Did) & MPI_FC_DID_MASK) >> MPI_FC_DID_SHIFT;
+    init_index = le32_to_cpu(rep->InitiatorIndex);
+    /*
+     *  after our link service reponse has been sent, repost the link service
+     *  buffer
+     */
+    priv->els_state[index] = 0;
+    stm_link_serv_buf_post(priv, index);
+       TRACE_EXIT();
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static void
+stm_cmd_buf_post(MPT_STM_PRIV *priv, int index)
+{
+    MPT_ADAPTER        *ioc = priv->ioc;
+    TargetCmdBufferPostRequest_t *req;
+    dma_addr_t dma_addr;
+
+       TRACE_ENTRY();
+       if (priv->exiting) {
+               priv->io_state[index] |= IO_STATE_POSTED;
+               return;
+       }
+
+       if (IsSas(priv)) {
+               stm_cmd_buf_post_list(priv, index);
+               return;
+       }
+
+    /*
+     *  get a free message frame, and post a command buffer
+     */
+    req = (TargetCmdBufferPostRequest_t *)mpt_msg_frame_alloc(ioc,index);
+    memset(req, 0, sizeof(*req));
+
+#ifdef CMD_BUFFER_POST_FLAGS_HIGH_PRIORITY
+       if (priv->io_state[index] & IO_STATE_HIGH_PRIORITY) {
+               req->BufferPostFlags = CMD_BUFFER_POST_FLAGS_HIGH_PRIORITY;
+       }
+#else
+       priv->io_state[index] &= ~IO_STATE_HIGH_PRIORITY;
+#endif
+
+    req->BufferCount = 1;
+    req->Function = MPI_FUNCTION_TARGET_CMD_BUFFER_POST;
+    req->BufferLength = sizeof(priv->hw->cmd_buf[index].cmd);
+    req->Buffer[0].IoIndex = (u16)cpu_to_le16(index);
+    dma_addr = priv->hw_dma +
+       ((u8 *)priv->hw->cmd_buf[index].cmd - (u8 *)priv->hw);
+    req->Buffer[0].u.PhysicalAddress64.Low = cpu_to_le32(dma_addr);
+#if MPT_STM_64_BIT_DMA
+    req->Buffer[0].u.PhysicalAddress64.High = cpu_to_le32((u64)dma_addr>>32);
+    req->BufferPostFlags = CMD_BUFFER_POST_FLAGS_64_BIT_ADDR;
+#endif
+
+    priv->io_state[index] |= IO_STATE_POSTED;
+
+#ifdef TRACING
+       if(trace_mpi) {
+               u32 *p = (u32 *)req;
+               int i;
+
+               TRACE(TRACE_MPI, "%s: stm_cmd_buf_post %d", ioc->name, index);
+               for (i = 0; i < sizeof(*req) / 4; i++) {
+                       TRACE(TRACE_MPI, "%s: req[%02x] = %08x",
+                                       ioc->name, i * 4, le32_to_cpu(p[i]));
+               }
+       }
+#endif
+
+       priv->current_mf[index] = NULL;
+       if (priv->io_state[index] & IO_STATE_HIGH_PRIORITY) {
+               priv->io_state[index] &= ~IO_STATE_HIGH_PRIORITY;
+               mpt_send_handshake_request(stm_context, _IOC_ID,
+                               sizeof(*req), (u32 *)req _HS_SLEEP);
+       } else {
+               mpt_put_msg_frame(stm_context, _IOC_ID, (MPT_FRAME_HDR *)req);
+       }
+
+       TRACE_EXIT();
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static void
+stm_cmd_buf_post_base(MPT_STM_PRIV *priv,
+                     int post_all)
+{
+    MPT_ADAPTER                                *ioc = priv->ioc;
+    TargetCmdBufferPostBaseRequest_t   *req;
+    int                                        i;
+    dma_addr_t                         dma_addr;
+
+       TRACE_ENTRY();
+    req = (TargetCmdBufferPostBaseRequest_t *)mpt_msg_frame_alloc(ioc,-1);
+    memset(req, 0, sizeof(*req));
+
+    if (post_all) {
+       req->BufferPostFlags = CMD_BUFFER_POST_BASE_FLAGS_AUTO_POST_ALL;
+    }
+    req->Function = MPI_FUNCTION_TARGET_CMD_BUF_BASE_POST;
+    req->TotalCmdBuffers = (u16)priv->num_cmd_buffers;
+    req->CmdBufferLength = sizeof(priv->hw->cmd_buf[0].cmd);
+    req->NextCmdBufferOffset = sizeof(priv->hw->cmd_buf[0]);
+    dma_addr = priv->hw_dma +
+       ((u8 *)priv->hw->cmd_buf[0].cmd - (u8 *)priv->hw);
+    req->BaseAddressLow = cpu_to_le32(dma_addr);
+#if MPT_STM_64_BIT_DMA
+    req->BaseAddressHigh = cpu_to_le32((u64)dma_addr>>32);
+#endif
+
+    if (post_all) {
+       for (i = 0; i < priv->num_cmd_buffers; i++) {
+           priv->io_state[i] |= IO_STATE_POSTED;
+       }
+    }
+
+#ifdef TRACING
+       if(trace_mpi)
+       {
+               u32 *p = (u32 *)req;
+               int i;
+
+               TRACE(TRACE_MPI, "%s: stm_cmd_buf_post_base", ioc->name);
+               for (i = 0; i < sizeof(*req) / 4; i++) {
+                       TRACE(TRACE_MPI, "%s: req[%02x] = %08x",
+                                       ioc->name, i * 4, le32_to_cpu(p[i]));
+               }
+       }
+#endif
+
+    mpt_put_msg_frame(stm_context, _IOC_ID, (MPT_FRAME_HDR *)req);
+
+       TRACE_EXIT();
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static void
+stm_cmd_buf_post_list(MPT_STM_PRIV *priv,
+                     int index)
+{
+    MPT_ADAPTER                                *ioc = priv->ioc;
+    TargetCmdBufferPostListRequest_t   *req;
+
+       TRACE_ENTRY();
+    req = (TargetCmdBufferPostListRequest_t *)mpt_msg_frame_alloc(ioc,index);
+    memset(req, 0, sizeof(*req));
+
+    req->Function = MPI_FUNCTION_TARGET_CMD_BUF_LIST_POST;
+    req->CmdBufferCount = 1;
+    req->IoIndex[0] = (u16)cpu_to_le16(index);
+
+    priv->io_state[index] |= IO_STATE_POSTED;
+
+#ifdef TRACING
+       if(trace_mpi)
+       {
+               u32 *p = (u32 *)req;
+               int i;
+
+               TRACE(TRACE_MPI, "%s: stm_cmd_buf_post_list %d", ioc->name, index);
+               for (i = 0; i < sizeof(*req) / 4; i++) {
+                       TRACE(TRACE_MPI, "%s: req[%02x] = %08x",
+                                       ioc->name, i * 4, le32_to_cpu(p[i]));
+               }
+       }
+#endif
+
+       mpt_put_msg_frame(stm_context, _IOC_ID, (MPT_FRAME_HDR *)req);
+       TRACE_EXIT();
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static void
+stm_link_serv_buf_post(MPT_STM_PRIV *priv, int index)
+{
+    MPT_ADAPTER                                *ioc = priv->ioc;
+    LinkServiceBufferPostRequest_t     *req;
+    SGETransaction32_t                 *sge_trans;
+    MPT_STM_SIMPLE                     *sge_simple;
+    dma_addr_t                         dma_addr;
+
+       TRACE_ENTRY();
+    req = (LinkServiceBufferPostRequest_t *)mpt_msg_frame_alloc(ioc,index);
+    memset(req, 0, sizeof(*req));
+
+    req->BufferCount = 1;
+    req->Function = MPI_FUNCTION_FC_LINK_SRVC_BUF_POST;
+    sge_trans = (SGETransaction32_t *)&req->SGL;
+    sge_trans->ContextSize = 4;
+    sge_trans->DetailsLength = 0;
+    sge_trans->Flags = 0;
+    sge_trans->TransactionContext[0] = cpu_to_le32(index);
+    sge_simple = (MPT_STM_SIMPLE *)&sge_trans->TransactionDetails[0];
+    sge_simple->FlagsLength = cpu_to_le32(sizeof(FC_ELS) |
+       MPI_SGE_SET_FLAGS(MPI_SGE_FLAGS_SIMPLE_ELEMENT |
+                         MPI_SGE_FLAGS_LAST_ELEMENT |
+                         MPI_SGE_FLAGS_END_OF_BUFFER |
+                         MPI_SGE_FLAGS_END_OF_LIST |
+                         MPI_SGE_FLAGS_MPT_STM_ADDRESSING |
+                         MPI_SGE_FLAGS_HOST_TO_IOC));
+    dma_addr = priv->hw_dma +
+       ((u8 *)priv->hw->fc_link_serv_buf[index].fc_els - (u8 *)priv->hw);
+    stm_set_dma_addr(sge_simple->Address, dma_addr);
+
+#ifdef TRACING
+       if(trace_mpi)
+       {
+               u32 *p = (u32 *)req;
+               int i;
+
+               TRACE(TRACE_MPI, "%s: stm_link_serv_buf_post %d", ioc->name, index);
+               for (i = 0; i < sizeof(*req) / 4; i++) {
+                       TRACE(TRACE_MPI, "%s: req[%02x] = %08x",
+                                       ioc->name, i * 4, le32_to_cpu(p[i]));
+               }
+       }
+#endif
+       priv->current_mf[index] = NULL;
+    mpt_put_msg_frame(stm_context, _IOC_ID, (MPT_FRAME_HDR *)req);
+       TRACE_EXIT();
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+stm_send_target_status(MPT_STM_PRIV *priv,
+                      u32 reply_word, int index, int flags, int lun, int tag)
+{
+    MPT_ADAPTER                        *ioc = priv->ioc;
+    TargetStatusSendRequest_t  *req;
+    MPT_STM_SIMPLE             *sge_simple;
+    CMD                                *cmd;
+    int                                length;
+    int                                status;
+    int                                init_index;
+       dma_addr_t                      dma_addr;
+       MPT_FRAME_HDR *mf = priv->current_mf[index];
+
+       TRACE_ENTRY();
+    if (priv->io_state[index] & IO_STATE_DATA_SENT) {
+               priv->current_mf[index] = NULL;
+       }
+    req = (TargetStatusSendRequest_t *)mpt_msg_frame_alloc(ioc,index);
+    memset(req, 0, sizeof(*req));
+
+    if (priv->exiting) {
+       flags &= ~TARGET_ASSIST_FLAGS_REPOST_CMD_BUFFER;
+       priv->io_state[index] &= ~IO_STATE_AUTO_REPOST;
+    }
+
+    if (priv->io_state[index] & IO_STATE_HIGH_PRIORITY) {
+       flags |= TARGET_STATUS_SEND_FLAGS_HIGH_PRIORITY;
+       flags |= TARGET_STATUS_SEND_FLAGS_REPOST_CMD_BUFFER;
+       priv->io_state[index] |= IO_STATE_AUTO_REPOST;
+    }
+
+    if (priv->fcp2_capable/* && priv->initiators != NULL*/) {
+       init_index = GET_INITIATOR_INDEX(reply_word);
+       /*init = priv->initiators[init_index];
+       if (init != NULL && init->confirm_capable) {
+           flags |= TARGET_STATUS_SEND_FLAGS_CONFIRMED;
+       }*/
+    }
+
+    cmd = &priv->hw->cmd_buf[index];
+
+    if (flags & TARGET_STATUS_SEND_FLAGS_AUTO_GOOD_STATUS) {
+       length = 0;
+       req->StatusCode = 0;
+    } else {
+       length = 0;
+       if (IsScsi(priv)) {
+           SCSI_RSP    *rsp = (SCSI_RSP *)cmd->rsp;
+
+           length += sizeof(*rsp);
+           length -= sizeof(rsp->SenseData);
+           status = rsp->Status;
+           if (rsp->Valid & SCSI_SENSE_LEN_VALID) {
+               length += be32_to_cpu(rsp->SenseDataListLength);
+               init_index = GET_INITIATOR_INDEX(reply_word);
+               /*
+                *  try to avoid a SCSI firmware bug by not using Auto Repost
+                *  here, unless required (High Priority requires it)
+                */
+               if (!(priv->io_state[index] & IO_STATE_HIGH_PRIORITY)) {
+                   flags &= ~TARGET_STATUS_SEND_FLAGS_REPOST_CMD_BUFFER;
+                   priv->io_state[index] &= ~IO_STATE_AUTO_REPOST;
+               }
+           }
+           if (rsp->Valid & SCSI_RSP_LEN_VALID) {
+               length += be32_to_cpu(rsp->PktFailuresListLength);
+           }
+       } else if (IsSas(priv)) {
+           SSP_RSP     *rsp = (SSP_RSP *)cmd->rsp;
+
+           length += sizeof(*rsp);
+           length -= sizeof(rsp->ResponseSenseData);
+           status = rsp->Status;
+           if (rsp->DataPres & SSP_SENSE_LEN_VALID) {
+               length += be32_to_cpu(rsp->SenseDataLength);
+           }
+           if (rsp->DataPres & SSP_RSP_LEN_VALID) {
+               length += be32_to_cpu(rsp->ResponseDataLength);
+           }
+       } else {
+           FCP_RSP     *rsp = (FCP_RSP *)cmd->rsp;
+
+           length += sizeof(*rsp);
+           length -= sizeof(rsp->FcpSenseData) + sizeof(rsp->FcpResponseData);
+           status = rsp->FcpStatus;
+           if (flags & TARGET_STATUS_SEND_FLAGS_CONFIRMED) {
+               rsp->FcpFlags |= FCP_REQUEST_CONFIRM;
+           }
+           if (rsp->FcpFlags & FCP_SENSE_LEN_VALID) {
+               length += be32_to_cpu(rsp->FcpSenseLength);
+           }
+           if (rsp->FcpFlags & FCP_RSP_LEN_VALID) {
+               length += be32_to_cpu(rsp->FcpResponseLength);
+               /* FCP_RSP_LEN_VALID will only be set for Task Mgmt responses */
+               /* and Task Mgmt responses can't be confirmed */
+               rsp->FcpFlags &= ~FCP_REQUEST_CONFIRM;
+               flags &= ~TARGET_STATUS_SEND_FLAGS_CONFIRMED;
+           }
+       }
+       req->StatusCode = (u8)status;
+    }
+
+    req->StatusFlags = (u8)flags;
+    req->Function = MPI_FUNCTION_TARGET_STATUS_SEND;
+    req->QueueTag = (u16)tag;
+    req->ReplyWord = cpu_to_le32(reply_word);
+    req->LUN[0] = (u8)(lun >> 8);
+    req->LUN[1] = (u8)lun;
+    if (length != 0) {
+       sge_simple = (MPT_STM_SIMPLE *)&req->StatusDataSGE;
+       sge_simple->FlagsLength = cpu_to_le32(length |
+           MPI_SGE_SET_FLAGS(MPI_SGE_FLAGS_SIMPLE_ELEMENT |
+                             MPI_SGE_FLAGS_LAST_ELEMENT |
+                             MPI_SGE_FLAGS_END_OF_BUFFER |
+                             MPI_SGE_FLAGS_END_OF_LIST |
+                             MPI_SGE_FLAGS_MPT_STM_ADDRESSING |
+                             MPI_SGE_FLAGS_HOST_TO_IOC));
+       dma_addr = priv->hw_dma +
+           ((u8 *)priv->hw->cmd_buf[index].rsp - (u8 *)priv->hw);
+       stm_set_dma_addr(sge_simple->Address, dma_addr);
+    }
+
+    /*
+     *  there's a limitation here -- if target data is outstanding, we must
+     *  wait for it to finish before we send the target status
+     */
+       if (priv->io_state[index] & IO_STATE_DATA_SENT) {
+               priv->current_mf[index] = mf;
+               priv->status_deferred_mf[index] = (MPT_FRAME_HDR *)req;
+               priv->io_state[index] |= IO_STATE_STATUS_DEFERRED;
+               TRACE_EXIT_RES(1);
+               return (1);
+       }
+       priv->io_state[index] |= IO_STATE_STATUS_SENT;
+
+#ifdef TRACING
+       if(trace_mpi)
+       {
+               u32 *p = (u32 *)req;
+               int i;
+
+               TRACE(TRACE_MPI, "%s: stm_send_target_status %d",
+                               ioc->name, index);
+               for (i = 0; i < sizeof(*req) / 4; i++) {
+                       TRACE(TRACE_MPI, "%s: req[%02x] = %08x",
+                                       ioc->name, i * 4, le32_to_cpu(p[i]));
+               }
+       }
+#endif
+
+       if (priv->io_state[index] & IO_STATE_HIGH_PRIORITY) {
+               mpt_send_handshake_request(stm_context, _IOC_ID,
+                               sizeof(*req), (u32 *)req _HS_SLEEP);
+       } else {
+               mpt_put_msg_frame(stm_context, _IOC_ID, (MPT_FRAME_HDR *)req);
+       }
+       TRACE_EXIT_RES(1);
+    return (1);
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static void
+stm_send_els(MPT_STM_PRIV *priv,
+            LinkServiceBufferPostReply_t *rep, int index, int length)
+{
+    MPT_ADAPTER                        *ioc = priv->ioc;
+    LinkServiceRspRequest_t    *req;
+    MPT_STM_SIMPLE             *sge_simple;
+    int                                *p_index;
+    dma_addr_t                 dma_addr;
+
+       TRACE_ENTRY();
+    req = (LinkServiceRspRequest_t *)mpt_msg_frame_alloc(ioc,index);
+    memset(req, 0, sizeof(*req));
+
+    req->RspLength = (u8)length;
+    req->Function = MPI_FUNCTION_FC_LINK_SRVC_RSP;
+    memcpy((u8 *)req + 0x0c, (u8 *)rep + 0x1c, 24);
+    sge_simple = (MPT_STM_SIMPLE *)&req->SGL;
+    sge_simple->FlagsLength = cpu_to_le32(length |
+       MPI_SGE_SET_FLAGS(MPI_SGE_FLAGS_SIMPLE_ELEMENT |
+                         MPI_SGE_FLAGS_LAST_ELEMENT |
+                         MPI_SGE_FLAGS_END_OF_BUFFER |
+                         MPI_SGE_FLAGS_END_OF_LIST |
+                         MPI_SGE_FLAGS_MPT_STM_ADDRESSING |
+                         MPI_SGE_FLAGS_HOST_TO_IOC));
+    dma_addr = priv->hw_dma +
+       ((u8 *)priv->hw->fc_link_serv_buf[index].fc_els - (u8 *)priv->hw);
+    stm_set_dma_addr(sge_simple->Address, dma_addr);
+    p_index = (int *)(sge_simple + 1);
+    *p_index = index;
+
+#ifdef TRACING
+       if(trace_mpi)
+       {
+               u32 *p = (u32 *)req;
+               int i;
+
+               TRACE(TRACE_MPI, "%s: stm_send_els %d", ioc->name, index);
+               for (i = 0; i < sizeof(*req) / 4; i++) {
+                       TRACE(TRACE_MPI, "%s: req[%02x] = %08x", 
+                                       ioc->name, i * 4, le32_to_cpu(p[i]));
+               }
+       }
+#endif
+       priv->current_mf[index] = NULL;
+    mpt_put_msg_frame(stm_context, _IOC_ID, (MPT_FRAME_HDR *)req);
+       TRACE_EXIT();
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+stm_port_enable(MPT_STM_PRIV *priv)
+{
+    MPT_ADAPTER                *ioc = priv->ioc;
+    PortEnable_t       *req;
+       int ret;
+
+       TRACE_ENTRY();
+    req = (PortEnable_t *)mpt_msg_frame_alloc(ioc,-1);
+    memset(req, 0, sizeof(*req));
+
+    req->Function = MPI_FUNCTION_PORT_ENABLE;
+
+    priv->port_enable_pending = 1;
+
+    mpt_put_msg_frame(stm_context, _IOC_ID, (MPT_FRAME_HDR *)req);
+
+    ret = stm_wait_for(priv, &priv->port_enable_pending, 60, NO_SLEEP);
+
+       TRACE_EXIT_RES(ret);
+
+       return ret;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+stm_target_mode_abort_command(MPT_STM_PRIV *priv,
+                             u32 reply_word, int index)
+{
+    MPT_ADAPTER                *ioc = priv->ioc;
+    TargetModeAbort_t  *req;
+
+       TRACE_ENTRY();
+    req = (TargetModeAbort_t *)mpt_msg_frame_alloc(ioc,index);
+    memset(req, 0, sizeof(*req));
+
+    req->AbortType = TARGET_MODE_ABORT_TYPE_EXACT_IO;
+    req->Function = MPI_FUNCTION_TARGET_MODE_ABORT;
+    req->ReplyWord = cpu_to_le32(reply_word);
+
+    priv->io_state[index] |= IO_STATE_ABORTED;
+
+       if (IsScsi(priv)) {
+               mpt_send_handshake_request(stm_context, _IOC_ID,
+                               sizeof(*req), (u32 *)req _HS_SLEEP);
+       } else {
+               mpt_put_msg_frame(stm_context, _IOC_ID, (MPT_FRAME_HDR *)req);
+       }
+       TRACE_EXIT();
+
+    return (0);
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+stm_target_mode_abort_request(MPT_STM_PRIV *priv,
+                             u32 reply_word,
+                             u32 msg_context,
+                             int index)
+{
+    MPT_ADAPTER                *ioc = priv->ioc;
+    TargetModeAbort_t  *req;
+
+       TRACE_ENTRY();
+    req = (TargetModeAbort_t *)mpt_msg_frame_alloc(ioc,index);
+    memset(req, 0, sizeof(*req));
+
+    req->AbortType = TARGET_MODE_ABORT_TYPE_EXACT_IO_REQUEST;
+    req->Function = MPI_FUNCTION_TARGET_MODE_ABORT;
+    req->ReplyWord = cpu_to_le32(reply_word);
+    req->MsgContextToAbort = cpu_to_le32(msg_context);
+
+    priv->io_state[index] |= IO_STATE_REQUEST_ABORTED;
+
+       if (IsScsi(priv)) {
+               mpt_send_handshake_request(stm_context, _IOC_ID,
+                               sizeof(*req), (u32 *)req _HS_SLEEP);
+       } else {
+               mpt_put_msg_frame(stm_context, _IOC_ID, (MPT_FRAME_HDR *)req);
+       }
+       TRACE_EXIT();
+
+    return (0);
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+stm_target_mode_abort_all(MPT_STM_PRIV *priv)
+{
+    MPT_ADAPTER                *ioc = priv->ioc;
+    TargetModeAbort_t  *req;
+       int ret;
+       TRACE_ENTRY();
+
+    req = (TargetModeAbort_t *)mpt_msg_frame_alloc(ioc,-1);
+    memset(req, 0, sizeof(*req));
+
+    req->AbortType = TARGET_MODE_ABORT_TYPE_ALL_CMD_BUFFERS;
+    req->Function = MPI_FUNCTION_TARGET_MODE_ABORT;
+
+    priv->target_mode_abort_pending = 1;
+
+       if (IsScsi(priv)) {
+               mpt_send_handshake_request(stm_context, _IOC_ID,
+                               sizeof(*req), (u32 *)req _HS_SLEEP);
+       } else {
+               mpt_put_msg_frame(stm_context, _IOC_ID, (MPT_FRAME_HDR *)req);
+       }
+
+    ret = stm_wait_for(priv, &priv->target_mode_abort_pending, 60, NO_SLEEP);
+       TRACE_EXIT_RES(ret);
+
+       return ret;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+stm_target_mode_abort(MPT_STM_PRIV *priv)
+{
+#ifdef TRACING
+    MPT_ADAPTER                *ioc = priv->ioc;
+#endif
+    int                        i;
+    int                        n;
+
+       TRACE_ENTRY();
+       while (1) {
+               n = 0;
+               for (i = 0; i< priv->num_cmd_buffers; i++) {
+                       if (priv->io_state[i] & IO_STATE_AUTO_REPOST) {
+                               n++;
+                       }
+               }
+
+               if (n == 0)
+                       break;
+
+               TRACE_DBG("%s: %d out of %d commands being auto-reposted, waiting...",
+                               ioc->name, n, priv->num_cmd_buffers);
+               stm_wait(priv, 10, CAN_SLEEP);
+       }
+
+       while (1) {
+               stm_target_mode_abort_all(priv);
+
+               n = 0;
+               for (i = 0; i< priv->num_cmd_buffers; i++) {
+                       if (priv->io_state[i] & IO_STATE_POSTED) {
+                               n++;
+                       }
+               }
+
+               if (n == priv->num_cmd_buffers)
+                       break;
+
+               TRACE_DBG("%s: %d out of %d commands still active, waiting...",
+                               ioc->name, n, priv->num_cmd_buffers);
+               stm_wait(priv, 10, CAN_SLEEP);
+       }
+
+       TRACE_EXIT();
+    return (0);
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+stm_link_serv_abort(MPT_STM_PRIV *priv)
+{
+    MPT_ADAPTER                *ioc = priv->ioc;
+    FcAbortRequest_t   *req;
+       int ret;
+
+       TRACE_ENTRY();
+
+    req = (FcAbortRequest_t *)mpt_msg_frame_alloc(ioc,-1);
+    memset(req, 0, sizeof(*req));
+
+    req->AbortType = FC_ABORT_TYPE_ALL_FC_BUFFERS;
+    req->Function = MPI_FUNCTION_FC_ABORT;
+
+    priv->link_serv_abort_pending = 1;
+
+    mpt_put_msg_frame(stm_context, _IOC_ID, (MPT_FRAME_HDR *)req);
+
+    ret = stm_wait_for(priv, &priv->link_serv_abort_pending, 60, NO_SLEEP);
+
+       TRACE_EXIT_RES(ret);
+
+       return ret;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+stm_reset_link(MPT_STM_PRIV *priv)
+{
+    MPT_ADAPTER                        *ioc = priv->ioc;
+    FcPrimitiveSendRequest_t   *req;
+       int ret;
+
+       TRACE_ENTRY();
+    req = (FcPrimitiveSendRequest_t *)mpt_msg_frame_alloc(ioc,-1);
+    memset(req, 0, sizeof(*req));
+
+    req->SendFlags = MPI_FC_PRIM_SEND_FLAGS_RESET_LINK;
+    req->Function = MPI_FUNCTION_FC_PRIMITIVE_SEND;
+
+    priv->fc_primitive_send_pending = 1;
+
+    mpt_put_msg_frame(stm_context, _IOC_ID, (MPT_FRAME_HDR *)req);
+
+    ret = stm_wait_for(priv, &priv->fc_primitive_send_pending, 60, NO_SLEEP);
+       TRACE_EXIT_RES(ret);
+
+       return ret;
+}
+#if 0
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+stm_login_port(MPT_STM_PRIV *priv, int port_id, int sleep)
+{
+    MPT_ADAPTER                        *ioc = priv->ioc;
+    ExLinkServiceSendRequest_t *req;
+    MPT_STM_SIMPLE             *sge_simple;
+    u32                                *buf;
+    int                                len, ret;
+    dma_addr_t                 dma_addr;
+
+       TRACE_ENTRY();
+    req = (ExLinkServiceSendRequest_t *)mpt_msg_frame_alloc(ioc,index);
+    memset(req, 0, sizeof(*req));
+
+    req->Function = MPI_FUNCTION_FC_EX_LINK_SRVC_SEND;
+    req->MsgFlags_Did = cpu_to_le32(port_id);
+    req->ElsCommandCode        = cpu_to_le32(PLOGI);
+
+    len = 29 * 4;
+    buf = priv->hw->exlink_buf;
+    memset(buf, 0, len);
+
+    buf[0] = cpu_to_be32(PLOGI << 24);
+    /*
+     *  the firmware builds the rest of the PLOGI payload
+     */
+
+    sge_simple = (MPT_STM_SIMPLE *)&req->SGL;
+    sge_simple->FlagsLength = cpu_to_le32(len |
+       MPI_SGE_SET_FLAGS(MPI_SGE_FLAGS_SIMPLE_ELEMENT |
+                         MPI_SGE_FLAGS_END_OF_BUFFER |
+                         MPI_SGE_FLAGS_MPT_STM_ADDRESSING |
+                         MPI_SGE_FLAGS_HOST_TO_IOC));
+    dma_addr = priv->hw_dma + ((u8 *)priv->hw->exlink_buf - (u8 *)priv->hw);
+    stm_set_dma_addr(sge_simple->Address, dma_addr);
+    sge_simple++;
+    sge_simple->FlagsLength = cpu_to_le32(len |
+       MPI_SGE_SET_FLAGS(MPI_SGE_FLAGS_SIMPLE_ELEMENT |
+                         MPI_SGE_FLAGS_LAST_ELEMENT |
+                         MPI_SGE_FLAGS_END_OF_BUFFER |
+                         MPI_SGE_FLAGS_END_OF_LIST |
+                         MPI_SGE_FLAGS_MPT_STM_ADDRESSING |
+                         MPI_SGE_FLAGS_IOC_TO_HOST));
+    dma_addr = priv->hw_dma + ((u8 *)priv->hw->exlink_buf - (u8 *)priv->hw);
+    stm_set_dma_addr(sge_simple->Address, dma_addr);
+
+    priv->ex_link_service_send_pending = 1;
+
+    mpt_put_msg_frame(stm_context, _IOC_ID, mf);
+
+    if (stm_wait_for(priv, &priv->ex_link_service_send_pending, 5, sleep) < 0)
+       return (-1);
+
+    req = (ExLinkServiceSendRequest_t *)mpt_msg_frame_alloc(ioc,index);
+    memset(req, 0, sizeof(*req));
+
+    req->Function = MPI_FUNCTION_FC_EX_LINK_SRVC_SEND;
+    req->MsgFlags_Did = cpu_to_le32(port_id);
+    req->ElsCommandCode        = cpu_to_le32(PRLI);
+
+    len = 5 * 4;
+    buf = priv->hw->exlink_buf;
+    memset(buf, 0, len);
+
+    buf[0] = cpu_to_be32(0x00100014 | (PRLI << 24));
+    buf[1] = cpu_to_be32(0x08002000);
+    buf[2] = cpu_to_be32(0x00000000);
+    buf[3] = cpu_to_be32(0x00000000);
+    buf[4] = cpu_to_be32(0x000000b2);
+
+    sge_simple = (MPT_STM_SIMPLE *)&req->SGL;
+    sge_simple->FlagsLength = cpu_to_le32(len |
+       MPI_SGE_SET_FLAGS(MPI_SGE_FLAGS_SIMPLE_ELEMENT |
+                         MPI_SGE_FLAGS_END_OF_BUFFER |
+                         MPI_SGE_FLAGS_MPT_STM_ADDRESSING |
+                         MPI_SGE_FLAGS_HOST_TO_IOC));
+    dma_addr = priv->hw_dma + ((u8 *)priv->hw->exlink_buf - (u8 *)priv->hw);
+    stm_set_dma_addr(sge_simple->Address, dma_addr);
+    sge_simple++;
+    sge_simple->FlagsLength = cpu_to_le32(len |
+       MPI_SGE_SET_FLAGS(MPI_SGE_FLAGS_SIMPLE_ELEMENT |
+                         MPI_SGE_FLAGS_LAST_ELEMENT |
+                         MPI_SGE_FLAGS_END_OF_BUFFER |
+                         MPI_SGE_FLAGS_END_OF_LIST |
+                         MPI_SGE_FLAGS_MPT_STM_ADDRESSING |
+                         MPI_SGE_FLAGS_IOC_TO_HOST));
+    dma_addr = priv->hw_dma + ((u8 *)priv->hw->exlink_buf - (u8 *)priv->hw);
+    stm_set_dma_addr(sge_simple->Address, dma_addr);
+
+    priv->ex_link_service_send_pending = 1;
+
+    mpt_put_msg_frame(stm_context, _IOC_ID, mf);
+
+    ret = stm_wait_for(priv, &priv->ex_link_service_send_pending, 5, sleep);
+
+       TRACE_EXIT_RES(ret);
+
+       return ret;
+}
+
+static int
+stm_logout_port(MPT_STM_PRIV *priv,
+               int port_id, int sleep)
+{
+    MPT_ADAPTER                        *ioc = priv->ioc;
+    ExLinkServiceSendRequest_t *req;
+    MPT_STM_SIMPLE             *sge_simple;
+    u32                                *buf;
+    int                                len, ret;
+    dma_addr_t                 dma_addr;
+
+       TRACE_ENTRY();
+    req = (ExLinkServiceSendRequest_t *)mpt_msg_frame_alloc(ioc,index);
+    memset(req, 0, sizeof(*req));
+
+    req->Function = MPI_FUNCTION_FC_EX_LINK_SRVC_SEND;
+    req->MsgFlags_Did = cpu_to_le32(port_id);
+    req->ElsCommandCode        = cpu_to_le32(LOGO);
+
+    len = 4 * 4;
+    buf = priv->hw->exlink_buf;
+    memset(buf, 0, len);
+
+    buf[0] = cpu_to_be32(LOGO << 24);
+    /*
+     *  the firmware builds the rest of the LOGO payload
+     */
+
+    sge_simple = (MPT_STM_SIMPLE *)&req->SGL;
+    sge_simple->FlagsLength = cpu_to_le32(len |
+       MPI_SGE_SET_FLAGS(MPI_SGE_FLAGS_SIMPLE_ELEMENT |
+                         MPI_SGE_FLAGS_END_OF_BUFFER |
+                         MPI_SGE_FLAGS_MPT_STM_ADDRESSING |
+                         MPI_SGE_FLAGS_HOST_TO_IOC));
+    dma_addr = priv->hw_dma + ((u8 *)priv->hw->exlink_buf - (u8 *)priv->hw);
+    stm_set_dma_addr(sge_simple->Address, dma_addr);
+    sge_simple++;
+    sge_simple->FlagsLength = cpu_to_le32(len |
+       MPI_SGE_SET_FLAGS(MPI_SGE_FLAGS_SIMPLE_ELEMENT |
+                         MPI_SGE_FLAGS_LAST_ELEMENT |
+                         MPI_SGE_FLAGS_END_OF_BUFFER |
+                         MPI_SGE_FLAGS_END_OF_LIST |
+                         MPI_SGE_FLAGS_MPT_STM_ADDRESSING |
+                         MPI_SGE_FLAGS_IOC_TO_HOST));
+    dma_addr = priv->hw_dma + ((u8 *)priv->hw->exlink_buf - (u8 *)priv->hw);
+    stm_set_dma_addr(sge_simple->Address, dma_addr);
+
+    priv->ex_link_service_send_pending = 1;
+
+    mpt_put_msg_frame(stm_context, _IOC_ID, mf);
+
+    ret = stm_wait_for(priv, &priv->ex_link_service_send_pending, 5, sleep);
+
+       TRACE_EXIT_RES(ret);
+
+       return ret;
+}
+
+static int
+stm_process_logout_port(MPT_STM_PRIV *priv,
+                       int port_id, int sleep)
+{
+    MPT_ADAPTER                        *ioc = priv->ioc;
+    ExLinkServiceSendRequest_t *req;
+    MPT_STM_SIMPLE             *sge_simple;
+    u32                                *buf;
+    int                                len, ret;
+    dma_addr_t                 dma_addr;
+
+       TRACE_ENTRY();
+    req = (ExLinkServiceSendRequest_t *)mpt_msg_frame_alloc(ioc,index);
+    memset(req, 0, sizeof(*req));
+
+    req->Function = MPI_FUNCTION_FC_EX_LINK_SRVC_SEND;
+    req->MsgFlags_Did = cpu_to_le32(port_id);
+    req->ElsCommandCode        = cpu_to_le32(PRLO);
+
+    len = 5 * 4;
+    buf = priv->hw->exlink_buf;
+    memset(buf, 0, len);
+
+    buf[0] = cpu_to_be32(0x00100014 | (PRLO << 24));
+    buf[1] = cpu_to_be32(0x08002000);
+    buf[2] = cpu_to_be32(0x00000000);
+    buf[3] = cpu_to_be32(0x00000000);
+    buf[4] = cpu_to_be32(0x00000000);
+
+    sge_simple = (MPT_STM_SIMPLE *)&req->SGL;
+    sge_simple->FlagsLength = cpu_to_le32(len |
+       MPI_SGE_SET_FLAGS(MPI_SGE_FLAGS_SIMPLE_ELEMENT |
+                         MPI_SGE_FLAGS_END_OF_BUFFER |
+                         MPI_SGE_FLAGS_MPT_STM_ADDRESSING |
+                         MPI_SGE_FLAGS_HOST_TO_IOC));
+    dma_addr = priv->hw_dma + ((u8 *)priv->hw->exlink_buf - (u8 *)priv->hw);
+    stm_set_dma_addr(sge_simple->Address, dma_addr);
+    sge_simple++;
+    sge_simple->FlagsLength = cpu_to_le32(len |
+       MPI_SGE_SET_FLAGS(MPI_SGE_FLAGS_SIMPLE_ELEMENT |
+                         MPI_SGE_FLAGS_LAST_ELEMENT |
+                         MPI_SGE_FLAGS_END_OF_BUFFER |
+                         MPI_SGE_FLAGS_END_OF_LIST |
+                         MPI_SGE_FLAGS_MPT_STM_ADDRESSING |
+                         MPI_SGE_FLAGS_IOC_TO_HOST));
+    dma_addr = priv->hw_dma + ((u8 *)priv->hw->exlink_buf - (u8 *)priv->hw);
+    stm_set_dma_addr(sge_simple->Address, dma_addr);
+
+    priv->ex_link_service_send_pending = 1;
+
+    mpt_put_msg_frame(stm_context, _IOC_ID, mf);
+
+    ret = stm_wait_for(priv, &priv->ex_link_service_send_pending, 5, sleep);
+
+       TRACE_EXIT_RES(ret);
+
+       return ret;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+stm_get_hard_address(MPT_STM_PRIV *priv, int port_id, int *hard_address, 
+               int sleep)
+{
+    MPT_ADAPTER                        *ioc = priv->ioc;
+    ExLinkServiceSendRequest_t *req;
+    MPT_STM_SIMPLE             *sge_simple;
+    u32                                *buf;
+    int                                len;
+    dma_addr_t                 dma_addr;
+
+       TRACE_ENTRY();
+    req = (ExLinkServiceSendRequest_t *)mpt_msg_frame_alloc(ioc,index);
+    memset(req, 0, sizeof(*req));
+
+    req->Function = MPI_FUNCTION_FC_EX_LINK_SRVC_SEND;
+    req->MsgFlags_Did = cpu_to_le32(port_id);
+    req->ElsCommandCode        = cpu_to_le32(ADISC);
+
+    len = 7 * 4;
+    buf = priv->hw->exlink_buf;
+    memset(buf, 0, len);
+
+    buf[0] = cpu_to_be32(ADISC << 24);
+    buf[1] = cpu_to_be32(0x00000000);  /* or get HardALPA from FCPortPage1 */
+    buf[2] = cpu_to_be32(priv->wwpn.High);
+    buf[3] = cpu_to_be32(priv->wwpn.Low);
+    buf[4] = cpu_to_be32(priv->wwnn.High);
+    buf[5] = cpu_to_be32(priv->wwnn.Low);
+    buf[6] = cpu_to_be32(priv->port_id);
+
+    sge_simple = (MPT_STM_SIMPLE *)&req->SGL;
+    sge_simple->FlagsLength = cpu_to_le32(len |
+       MPI_SGE_SET_FLAGS(MPI_SGE_FLAGS_SIMPLE_ELEMENT |
+                         MPI_SGE_FLAGS_END_OF_BUFFER |
+                         MPI_SGE_FLAGS_MPT_STM_ADDRESSING |
+                         MPI_SGE_FLAGS_HOST_TO_IOC));
+    dma_addr = priv->hw_dma + ((u8 *)priv->hw->exlink_buf - (u8 *)priv->hw);
+    stm_set_dma_addr(sge_simple->Address, dma_addr);
+    sge_simple++;
+    sge_simple->FlagsLength = cpu_to_le32(len |
+       MPI_SGE_SET_FLAGS(MPI_SGE_FLAGS_SIMPLE_ELEMENT |
+                         MPI_SGE_FLAGS_LAST_ELEMENT |
+                         MPI_SGE_FLAGS_END_OF_BUFFER |
+                         MPI_SGE_FLAGS_END_OF_LIST |
+                         MPI_SGE_FLAGS_MPT_STM_ADDRESSING |
+                         MPI_SGE_FLAGS_IOC_TO_HOST));
+    dma_addr = priv->hw_dma + ((u8 *)priv->hw->exlink_buf - (u8 *)priv->hw);
+    stm_set_dma_addr(sge_simple->Address, dma_addr);
+
+    priv->ex_link_service_send_pending = 1;
+
+    mpt_put_msg_frame(stm_context, _IOC_ID, mf);
+
+    if (stm_wait_for(priv, &priv->ex_link_service_send_pending, 5, sleep) < 0)
+       return (-1);
+
+    if ((be32_to_cpu(buf[0]) >> 24) != LS_ACC)
+       return (-2);
+
+    *hard_address = be32_to_cpu(buf[1]);
+
+       TRACE_EXIT();
+
+    return (0);
+}
+#endif
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+stm_scsi_configuration(MPT_STM_PRIV *priv,
+                      int sleep)
+{
+#ifdef TRACING
+    MPT_ADAPTER                *ioc = priv->ioc;
+#endif
+    SCSIPortPage0_t    *ScsiPort0;
+    SCSIPortPage1_t    *ScsiPort1;
+    SCSIPortPage2_t    *ScsiPort2;
+    int                        id;
+    int                        cap;
+    int                        wcap;
+    int                        ncap;
+    int                        sync;
+    int                        flags;
+    int                        i;
+
+       TRACE_ENTRY();
+    memset(priv->hw->config_buf, 0, sizeof(priv->hw->config_buf));
+    if (stm_get_config_page(priv, MPI_CONFIG_PAGETYPE_SCSI_PORT, 2, 0, sleep)) {
+       return (-1);
+    }
+    ScsiPort2 = &priv->SCSIPortPage2;
+       memcpy(&priv->SCSIPortPage2, priv->hw->config_buf, sizeof(SCSIPortPage2_t));
+
+    id = 0;//le32_to_cpu(ScsiPort2->PortSettings) & MPI_SCSIPORTPAGE2_PORT_HOST_ID_MASK;
+    TRACE_DBG("%s scsi id is %d", ioc->name, id);
+    priv->port_id = id;
+
+    memset(priv->hw->config_buf, 0, sizeof(priv->hw->config_buf));
+    if (stm_get_config_page(priv, MPI_CONFIG_PAGETYPE_SCSI_PORT, 0, 0, sleep)) {
+       return (-1);
+    }
+       memcpy(&priv->SCSIPortPage0, priv->hw->config_buf, sizeof(SCSIPortPage0_t));
+    ScsiPort0 = &priv->SCSIPortPage0;
+
+    cap = le32_to_cpu(ScsiPort0->Capabilities);
+    TRACE_DBG("%s target %d capabilities = %08x",
+          ioc->name, id, cap);
+
+    memset(priv->hw->config_buf, 0, sizeof(priv->hw->config_buf));
+    memset(&priv->SCSIPortPage1, 0, sizeof(priv->SCSIPortPage1));
+    ScsiPort1 = &priv->SCSIPortPage1;
+    ScsiPort1->Configuration = cpu_to_le32(id | (1 << (id + 16)));
+    for (i = 1; i <= priv->num_aliases; i++) {
+       id = (priv->port_id + i) & 15;
+       TRACE_DBG("%s alias %d is target %d",
+              ioc->name, i, id);
+       ScsiPort1->Configuration |= cpu_to_le32(1 << (id + 16));
+    }
+//  ScsiPort1->TargetConfig = MPI_SCSIPORTPAGE1_TARGCONFIG_INIT_TARG;
+    ScsiPort1->TargetConfig = MPI_SCSIPORTPAGE1_TARGCONFIG_TARG_ONLY;
+//     ScsiPort1->IDConfig = 0x7;
+       memcpy(priv->hw->config_buf, (u32 *)ScsiPort1, sizeof(*ScsiPort1));
+    stm_set_config_page(priv, MPI_CONFIG_PAGETYPE_SCSI_PORT, 1, 0, sleep);
+
+    wcap = cap & ~MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK;
+    ncap = wcap & ~MPI_SCSIPORTPAGE0_CAP_WIDE;
+
+    memset(priv->hw->config_buf, 0, sizeof(priv->hw->config_buf));
+    memset(priv->SCSIDevicePage1, 0, sizeof(SCSIDevicePage1_t) * NUM_SCSI_DEVICES);
+
+    for (i = 0; i < NUM_SCSI_DEVICES; i++) {
+       int wide = 0;
+    SCSIDevicePage1_t  *ScsiDevice1 = &priv->SCSIDevicePage1[i];
+       sync = ScsiPort2->DeviceSettings[i].SyncFactor;
+       flags = le16_to_cpu(ScsiPort2->DeviceSettings[i].DeviceFlags);
+       if (flags & MPI_SCSIPORTPAGE2_DEVICE_WIDE_DISABLE)
+           cap = ncap;
+       else {
+           cap = wcap;
+               wide = 1;
+       }
+       /*cap &= ~MPI_SCSIDEVPAGE1_RP_IU;
+       cap &= ~MPI_SCSIDEVPAGE1_RP_DT;
+       cap &= ~MPI_SCSIDEVPAGE1_RP_QAS;*/
+       ScsiDevice1->RequestedParameters = cpu_to_le32(cap | (sync << 8));
+       TRACE_DBG("%s initiator %d parameters = %08x, %s %s",
+              ioc->name, i, le32_to_cpu(ScsiDevice1->RequestedParameters),
+                  sync ? "SYNC" : " ", 
+                  wide ? "WIDE" : " ");
+       memcpy(priv->hw->config_buf, ScsiDevice1, sizeof(*ScsiDevice1));
+       stm_set_config_page(priv, MPI_CONFIG_PAGETYPE_SCSI_DEVICE, 1, i, sleep);
+    }
+       TRACE_EXIT();
+
+    return (0);
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+stm_sas_configuration(MPT_STM_PRIV *priv,
+                      int sleep)
+{
+    return (0);
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+stm_fc_configuration(MPT_STM_PRIV *priv, int sleep)
+{
+    MPT_ADAPTER                *ioc = priv->ioc;
+    U64                        wwnn;
+    U64                        wwpn;
+    int                        port_id;
+    int                        protocol;
+    int                        flags;
+    int                        current_speed;
+    int                        port_state;
+    int                        target;
+    char               *attach;
+    char               *speed;
+    FCPortPage0_t      *FcPort0;
+    FCDevicePage0_t    *FcDevice0;
+    int                        page;
+
+       TRACE_ENTRY();
+    memset(priv->hw->config_buf, 0, sizeof(priv->hw->config_buf));
+    if (stm_get_config_page(priv, MPI_CONFIG_PAGETYPE_FC_PORT, 0, 0, sleep)) {
+       return (-1);
+    }
+    FcPort0 = (FCPortPage0_t *)priv->hw->config_buf;
+    flags = le32_to_cpu(FcPort0->Flags) &
+       MPI_FCPORTPAGE0_FLAGS_ATTACH_TYPE_MASK;
+    current_speed = le32_to_cpu(FcPort0->CurrentSpeed);
+    port_state = FcPort0->PortState;
+
+    switch (flags) {
+       case MPI_FCPORTPAGE0_FLAGS_ATTACH_NO_INIT:
+           attach = NULL;
+           break;
+       case MPI_FCPORTPAGE0_FLAGS_ATTACH_POINT_TO_POINT:
+           attach = "point to point";
+           break;
+       case MPI_FCPORTPAGE0_FLAGS_ATTACH_PRIVATE_LOOP:
+           attach = "private loop";
+           break;
+       case MPI_FCPORTPAGE0_FLAGS_ATTACH_FABRIC_DIRECT:
+           attach = "fabric direct attach";
+           break;
+       case MPI_FCPORTPAGE0_FLAGS_ATTACH_PUBLIC_LOOP:
+           attach = "public loop";
+           break;
+       default:
+           attach = "unknown";
+           break;
+    }
+
+    switch (current_speed) {
+       case MPI_FCPORTPAGE0_CURRENT_SPEED_1GBIT:
+           speed = "1 Gbaud";
+           break;
+       case MPI_FCPORTPAGE0_CURRENT_SPEED_2GBIT:
+           speed = "2 Gbaud";
+           break;
+       case MPI_FCPORTPAGE0_CURRENT_SPEED_10GBIT:
+           speed = "10 Gbaud";
+           break;
+       default:
+           speed = "unknown";
+           break;
+    }
+
+    if (priv->port_flags != flags ||
+       priv->port_speed != current_speed ||
+       priv->port_state != port_state) {
+       priv->port_flags = flags;
+       priv->port_speed = current_speed;
+       priv->port_state = port_state;
+       priv->device_changed = 1;
+       if (attach) {
+           printk("%s link is online, type is %s, speed is %s\n",
+                  ioc->name, attach, speed);
+       } else {
+           printk("%s link is offline\n", ioc->name);
+       }
+    }
+
+    wwnn.Low = le32_to_cpu(FcPort0->WWNN.Low);
+    wwnn.High = le32_to_cpu(FcPort0->WWNN.High);
+    wwpn.Low = le32_to_cpu(FcPort0->WWPN.Low);
+    wwpn.High = le32_to_cpu(FcPort0->WWPN.High);
+    port_id = le32_to_cpu(FcPort0->PortIdentifier);
+    protocol = le32_to_cpu(FcPort0->Flags) & MPI_FCPORTPAGE0_FLAGS_PROT_MASK;
+
+    if (priv->wwpn.Low != wwpn.Low ||
+       priv->wwpn.High != wwpn.High ||
+       priv->port_id != port_id) {
+       priv->wwnn.Low = wwnn.Low;
+       priv->wwnn.High = wwnn.High;
+       priv->wwpn.Low = wwpn.Low;
+       priv->wwpn.High = wwpn.High;
+       priv->port_id = port_id;
+       priv->protocol = protocol;
+       priv->device_changed = 1;
+       if (attach) {
+           printk("%s port is wwn %08x%08x, port id %x\n",
+                  ioc->name, wwpn.High, wwpn.Low, port_id);
+       } else {
+           printk(
+                  "%s port is wwn %08x%08x\n",
+                  ioc->name, wwpn.High, wwpn.Low);
+       }
+    }
+
+    page = MPI_FC_DEVICE_PAGE0_PGAD_FORM_NEXT_DID + 0xffffff;
+
+    while (1) {
+       memset(priv->hw->config_buf, 0, sizeof(priv->hw->config_buf));
+       if (stm_get_config_page(priv, MPI_CONFIG_PAGETYPE_FC_DEVICE,
+                               0, page, sleep)) {
+           break;
+       }
+       FcDevice0 = (FCDevicePage0_t *)priv->hw->config_buf;
+
+       wwnn.Low = le32_to_cpu(FcDevice0->WWNN.Low);
+       wwnn.High = le32_to_cpu(FcDevice0->WWNN.High);
+       wwpn.Low = le32_to_cpu(FcDevice0->WWPN.Low);
+       wwpn.High = le32_to_cpu(FcDevice0->WWPN.High);
+       port_id = le32_to_cpu(FcDevice0->PortIdentifier);
+       protocol = FcDevice0->Protocol;
+       if (FcDevice0->Flags & MPI_FC_DEVICE_PAGE0_FLAGS_TARGETID_BUS_VALID) {
+           target = FcDevice0->CurrentTargetID;
+       } else {
+           target = -1;
+       }
+
+#if 0
+       printk("%s using ADISC to get hard address of port id %x\n",
+              ioc->name, port_id);
+       if (stm_get_hard_address(priv, port_id, &i, sleep))
+           printk("%s ADISC failed!\n", ioc->name);
+       else
+           printk("%s port id's %x hard address is %x\n",
+                  ioc->name, port_id, i);
+#endif
+
+       page = MPI_FC_DEVICE_PAGE0_PGAD_FORM_NEXT_DID + port_id;
+
+    }
+       TRACE_EXIT();
+
+    return (0);
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+stm_fc_enable_els(MPT_STM_PRIV *priv,
+                 int els, int sleep)
+{
+    FCPortPage8_t      *FcPort8;
+       TRACE_ENTRY();
+    memset(priv->hw->config_buf, 0, sizeof(priv->hw->config_buf));
+    if (stm_get_config_page(priv, MPI_CONFIG_PAGETYPE_FC_PORT, 8, 0, sleep)) {
+       return (-1);
+    }
+    FcPort8 = (FCPortPage8_t *)priv->hw->config_buf;
+    /* clear the ELS bit */
+    FcPort8->BitVector[els / 32] &= ~cpu_to_le32(1 << (els & 31));
+    if (stm_set_config_page(priv, MPI_CONFIG_PAGETYPE_FC_PORT, 8, 0, sleep)) {
+       return (-1);
+    }
+       TRACE_EXIT();
+
+    return (0);
+}
+#if 0
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+stm_fc_enable_immediate_errors(MPT_STM_PRIV *priv,
+                              int sleep)
+{
+    FCPortPage1_t      *FcPort1;
+
+    memset(priv->hw->config_buf, 0, sizeof(priv->hw->config_buf));
+    if (stm_get_config_page(priv, MPI_CONFIG_PAGETYPE_FC_PORT, 1, 0, sleep)) {
+       return (-1);
+    }
+    FcPort1 = (FCPortPage1_t *)priv->hw->config_buf;
+    /* set the Immediate Error Reply bit */
+    FcPort1->Flags |= cpu_to_le32(MPI_FCPORTPAGE1_FLAGS_IMMEDIATE_ERROR_REPLY);
+    if (stm_set_config_page(priv, MPI_CONFIG_PAGETYPE_FC_PORT, 1, 0, sleep)) {
+       return (-1);
+    }
+
+    return (0);
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+stm_fc_enable_target_mode_oxid(MPT_STM_PRIV *priv,
+                              int sleep)
+{
+    FCPortPage1_t      *FcPort1;
+       TRACE_ENTRY();
+    memset(priv->hw->config_buf, 0, sizeof(priv->hw->config_buf));
+    if (stm_get_config_page(priv, MPI_CONFIG_PAGETYPE_FC_PORT, 1, 0, sleep)) {
+       return (-1);
+    }
+    FcPort1 = (FCPortPage1_t *)priv->hw->config_buf;
+    /* set the Target Mode OX_ID bit */
+    FcPort1->Flags |= cpu_to_le32(MPI_FCPORTPAGE1_FLAGS_TARGET_MODE_OXID);
+    if (stm_set_config_page(priv, MPI_CONFIG_PAGETYPE_FC_PORT, 1, 0, sleep)) {
+       return (-1);
+    }
+       TRACE_EXIT();
+
+    return (0);
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+stm_fc_set_wwn(MPT_STM_PRIV *priv,
+              WwnFormat_t *wwn,
+              int sleep)
+{
+    FCPortPage1_t      *FcPort1;
+       TRACE_ENTRY();
+    memset(priv->hw->config_buf, 0, sizeof(priv->hw->config_buf));
+    if (stm_get_config_page(priv, MPI_CONFIG_PAGETYPE_FC_PORT, 1, 0, sleep)) {
+       return (-1);
+    }
+    FcPort1 = (FCPortPage1_t *)priv->hw->config_buf;
+    /* set the WWPN and WWNN */
+    FcPort1->NoSEEPROMWWPN.Low = cpu_to_le32(wwn->PortNameLow);
+    FcPort1->NoSEEPROMWWPN.High = cpu_to_le32(wwn->PortNameHigh);
+    FcPort1->NoSEEPROMWWNN.Low = cpu_to_le32(wwn->NodeNameLow);
+    FcPort1->NoSEEPROMWWNN.High = cpu_to_le32(wwn->NodeNameHigh);
+    /* set the Ignore SEEPROM WWNs bit */
+    FcPort1->Flags |=
+       cpu_to_le32(MPI_FCPORTPAGE1_FLAGS_FORCE_USE_NOSEEPROM_WWNS);
+    if (stm_set_config_page(priv, MPI_CONFIG_PAGETYPE_FC_PORT, 1, 0, sleep)) {
+       return (-1);
+    }
+
+    stm_reset_link(priv);
+       TRACE_EXIT();
+    return (0);
+}
+#endif
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+stm_fc_enable_aliases(MPT_STM_PRIV *priv, int num_aliases, int sleep)
+{
+    FCPortPage1_t      *FcPort1;
+       TRACE_ENTRY();
+    memset(priv->hw->config_buf, 0, sizeof(priv->hw->config_buf));
+    if (stm_get_config_page(priv, MPI_CONFIG_PAGETYPE_FC_PORT, 1, 0, sleep)) {
+       return (-1);
+    }
+    FcPort1 = (FCPortPage1_t *)priv->hw->config_buf;
+    if (set_aliases_in_fcportpage1) {
+       /* set the number of aliases requested */
+       FcPort1->NumRequestedAliases = (u8)num_aliases;
+    } else {
+       /* make sure the value in the page is low enough */
+       if (FcPort1->NumRequestedAliases > NUM_ALIASES) {
+           FcPort1->NumRequestedAliases = NUM_ALIASES;
+       }
+    }
+
+    if (num_aliases > 0) {
+       FcPort1->TopologyConfig = MPI_FCPORTPAGE1_TOPOLOGY_NLPORT;
+    }
+    if (stm_set_config_page(priv, MPI_CONFIG_PAGETYPE_FC_PORT, 1, 0, sleep)) {
+       return (-1);
+    }
+       TRACE_EXIT();
+    return (0);
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+stm_get_config_page(MPT_STM_PRIV *priv, int type, int number, int address,
+                   int sleep)
+{
+    MPT_ADAPTER                *ioc = priv->ioc;
+    ConfigReply_t      *rep;
+    int                        ioc_status;
+    int                        i;
+    int                        length;
+
+       TRACE_ENTRY();
+    rep = &priv->config_rep;
+    memset(rep, 0, sizeof(*rep));
+
+    i = stm_do_config_action(priv, MPI_CONFIG_ACTION_PAGE_HEADER,
+                            type, number, address, 0, sleep);
+    if (i) {
+       if (!priv->in_reset) {
+           printk(KERN_ERR MYNAM
+                  ":%s timed out getting config page header\n", ioc->name);
+       }
+       return (-1);
+    }
+
+    if (priv->in_reset) {
+       printk(KERN_ERR MYNAM
+              ":%s reset while getting config page header\n", ioc->name);
+       return (-1);
+    }
+
+    ioc_status = le16_to_cpu(rep->IOCStatus) & MPI_IOCSTATUS_MASK;
+    if (type > MPI_CONFIG_PAGETYPE_EXTENDED) {
+       length = rep->ExtPageLength;
+    } else {
+       length = rep->Header.PageLength;
+    }
+    if (ioc_status != MPI_IOCSTATUS_SUCCESS || length == 0) {
+       if (ioc_status != MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
+           printk(KERN_ERR MYNAM
+                  ":%s failed to get config page header\n", ioc->name);
+           printk(KERN_ERR MYNAM
+                  ":%s   IOCStatus = %04x, PageLength = %x\n",
+                  ioc->name, ioc_status, length);
+           printk(KERN_ERR MYNAM
+                  ":%s   type = %d, number = %d, address = %x\n",
+                  ioc->name, type, number, address);
+       }
+       return (-1);
+    }
+
+    i = stm_do_config_action(priv, MPI_CONFIG_ACTION_PAGE_READ_CURRENT,
+                            type, number, address, length, sleep);
+    if (i) {
+       if (!priv->in_reset) {
+           printk(KERN_ERR MYNAM
+                  ":%s timed out getting config page\n", ioc->name);
+       }
+       return (-1);
+    }
+
+    if (priv->in_reset) {
+       printk(KERN_ERR MYNAM
+              ":%s reset while getting config page\n", ioc->name);
+       return (-1);
+    }
+
+    ioc_status = le16_to_cpu(rep->IOCStatus) & MPI_IOCSTATUS_MASK;
+    if (ioc_status != MPI_IOCSTATUS_SUCCESS) {
+       if (type == 6 && number == 0) {
+           /* no error messages, please! */
+       } else {
+           printk(KERN_ERR MYNAM
+                  ":%s failed to get config page\n", ioc->name);
+           printk(KERN_ERR MYNAM
+                  ":%s   IOCStatus = %04x, PageLength = %x\n",
+                  ioc->name, ioc_status, length);
+           printk(KERN_ERR MYNAM
+                  ":%s   type = %d, number = %d, address = %x\n",
+                  ioc->name, type, number, address);
+       }
+       return (-1);
+    }
+
+#ifdef TRACING
+       if(trace_mpi)
+       {
+               u32 *p = (u32 *)priv->hw->config_buf;
+               int i;
+
+               TRACE(TRACE_MPI, "%s config page %02x/%02x/%08x read",
+                               ioc->name, type, number, address);
+               for (i = 0; i < length; i++) {
+                       TRACE(TRACE_MPI, "%s page[%02x] = %08x",
+                                       ioc->name, i * 4, le32_to_cpu(p[i]));
+               }
+       }
+#endif
+       TRACE_EXIT();
+
+    return (0);
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+stm_set_config_page(MPT_STM_PRIV *priv,
+                   int type,
+                   int number,
+                   int address,
+                   int sleep)
+{
+    MPT_ADAPTER                *ioc = priv->ioc;
+    ConfigReply_t      *rep;
+    int                        ioc_status;
+    int                        i;
+    int                        length;
+
+       TRACE_ENTRY();
+    rep = &priv->config_rep;
+    memset(rep, 0, sizeof(*rep));
+
+    i = stm_do_config_action(priv, MPI_CONFIG_ACTION_PAGE_HEADER,
+                            type, number, address, 0, sleep);
+    if (i) {
+       if (!priv->in_reset) {
+           printk(KERN_ERR MYNAM
+                  ":%s timed out getting config page header\n", ioc->name);
+       }
+       return (-1);
+    }
+
+    if (priv->in_reset) {
+       printk(KERN_ERR MYNAM
+              ":%s reset while getting config page header\n", ioc->name);
+       return (-1);
+    }
+
+    ioc_status = le16_to_cpu(rep->IOCStatus) & MPI_IOCSTATUS_MASK;
+    if (type > MPI_CONFIG_PAGETYPE_EXTENDED) {
+       length = rep->ExtPageLength;
+    } else {
+       length = rep->Header.PageLength;
+    }
+    if (ioc_status != MPI_IOCSTATUS_SUCCESS || length == 0) {
+       if (ioc_status != MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
+           printk(KERN_ERR MYNAM
+                  ":%s failed to get config page header\n", ioc->name);
+           printk(KERN_ERR MYNAM
+                  ":%s   IOCStatus = %04x, PageLength = %x\n",
+                  ioc->name, ioc_status, length);
+           printk(KERN_ERR MYNAM
+                  ":%s   type = %d, number = %d, address = %x\n",
+                  ioc->name, type, number, address);
+       }
+       return (-1);
+    }
+
+    *(ConfigPageHeader_t *)priv->hw->config_buf = rep->Header;
+
+    i = stm_do_config_action(priv, MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT,
+                            type, number, address, length, sleep);
+    if (i) {
+       if (!priv->in_reset) {
+           printk(KERN_ERR MYNAM
+                  ":%s timed out setting config page\n", ioc->name);
+       }
+       return (-1);
+    }
+
+    if (priv->in_reset) {
+       printk(KERN_ERR MYNAM
+              ":%s reset while setting config page\n", ioc->name);
+       return (-1);
+    }
+
+    ioc_status = le16_to_cpu(rep->IOCStatus) & MPI_IOCSTATUS_MASK;
+    if (ioc_status != MPI_IOCSTATUS_SUCCESS) {
+       printk(KERN_ERR MYNAM
+              ":%s failed to set config page\n", ioc->name);
+       printk(KERN_ERR MYNAM
+              ":%s   IOCStatus = %04x, PageLength = %x\n",
+              ioc->name, ioc_status, length);
+       printk(KERN_ERR MYNAM
+              ":%s   type = %d, number = %d, address = %x\n",
+              ioc->name, type, number, address);
+       printk(KERN_ERR MYNAM
+              ":%s   Header = %08x\n",
+              ioc->name, le32_to_cpu(*(u32 *)priv->hw->config_buf));
+       return (-1);
+    }
+
+#ifdef TRACING
+       if(trace_mpi)
+       {
+               u32 *p = (u32 *)priv->hw->config_buf;
+               int i;
+
+               TRACE(TRACE_MPI, "%s config page %02x/%02x/%08x written",
+                               ioc->name, type, number, address);
+               for (i = 0; i < length; i++) {
+                       TRACE(TRACE_MPI, "%s page[%02x] = %08x",
+                                       ioc->name, i * 4, le32_to_cpu(p[i]));
+               }
+       }
+#endif
+       TRACE_EXIT();
+
+    return (0);
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+stm_do_config_action(MPT_STM_PRIV *priv, int action,
+                    int type, int number, int address, int length, int sleep)
+{
+    MPT_ADAPTER                *ioc = priv->ioc;
+    MPT_FRAME_HDR      *mf;
+    Config_t           *req;
+    MPT_STM_SIMPLE     *sge_simple;
+    dma_addr_t         dma_addr;
+       int ret;
+
+       TRACE_ENTRY();
+    if (priv->in_reset) {
+       printk(KERN_ERR MYNAM ":%s reset while doing config action %x\n",
+              ioc->name, action);
+       return (-1);
+    }
+
+    /*
+     *  get a message frame, and send the config action request
+     */
+    mf = priv->config_mf;
+    if (mf == NULL) {
+       mf = mpt_msg_frame_alloc(ioc,-1);
+       if (mf == NULL) {
+           printk(KERN_ERR MYNAM
+                  ":%s failed to get message frame\n", ioc->name);
+           return (-1);
+       } else {
+           TRACE_DBG(
+                   "%s in stm_do_config_action, got mf index %d",
+                   ioc->name, MF_TO_INDEX(mf));
+           priv->config_mf = mf;
+       }
+    }
+
+    req = (Config_t *)mf;
+    memset(req, 0, sizeof(*req));
+
+    req->Function = MPI_FUNCTION_CONFIG;
+    req->Action = (u8)action;
+    if (action == MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT ||
+       action == MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM) {
+       req->Header = *(ConfigPageHeader_t *)priv->hw->config_buf;
+    } else {
+       if (type > MPI_CONFIG_PAGETYPE_EXTENDED) {
+           req->Header.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
+           req->ExtPageType = (u8)type;
+           req->ExtPageLength = (u16)length;
+       } else {
+           req->Header.PageType = (u8)type;
+       }
+       req->Header.PageNumber = (u8)number;
+       req->Header.PageLength = (u8)length;
+    }
+    req->PageAddress = cpu_to_le32(address);
+    if (length) {
+       sge_simple = (MPT_STM_SIMPLE *)&req->PageBufferSGE;
+       sge_simple->FlagsLength = cpu_to_le32((length * 4) |
+           MPI_SGE_SET_FLAGS(MPI_SGE_FLAGS_SIMPLE_ELEMENT |
+                             MPI_SGE_FLAGS_LAST_ELEMENT |
+                             MPI_SGE_FLAGS_END_OF_BUFFER |
+                             MPI_SGE_FLAGS_END_OF_LIST |
+                             MPI_SGE_FLAGS_MPT_STM_ADDRESSING));
+       if (action == MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT ||
+           action == MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM) {
+           sge_simple->FlagsLength |=
+               cpu_to_le32(MPI_SGE_SET_FLAGS(MPI_SGE_FLAGS_HOST_TO_IOC));
+       }
+       dma_addr = priv->hw_dma + ((u8 *)priv->hw->config_buf - (u8 *)priv->hw);
+       stm_set_dma_addr(sge_simple->Address, dma_addr);
+    }
+
+#if 1
+    priv->config_pending = 1;
+
+    mpt_put_msg_frame(stm_context, _IOC_ID, (MPT_FRAME_HDR *)req);
+
+    ret = (stm_wait_for(priv, &priv->config_pending, 10, sleep));
+#else
+    ret = (mpt_handshake_req_reply_wait(ioc, sizeof(*req), (u32 *)req,
+                                        sizeof(priv->config_rep),
+                                        (u16 *)&priv->config_rep, 10, sleep));
+#endif
+       TRACE_EXIT_RES(ret);
+
+       return ret;
+}
+
+static void
+stm_wait(MPT_STM_PRIV *priv, int milliseconds, int sleep)
+{
+    MPT_ADAPTER                *ioc = priv->ioc;
+
+       TRACE_ENTRY();
+       if (mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_OPERATIONAL) {
+               printk(KERN_ERR MYNAM
+                               ":%s IOC is not operational (doorbell = %x)\n",
+                               ioc->name, mpt_GetIocState(ioc, 0));
+       } else {
+               if (sleep == CAN_SLEEP) {
+                       set_current_state(TASK_INTERRUPTIBLE);
+                       schedule_timeout(milliseconds);
+               } else {
+#ifndef __linux__
+                       if (priv->poll_enabled) {
+                               _mpt_poll(priv->ioc);
+                       }
+#endif
+                       mdelay(milliseconds);
+               }
+       }
+       TRACE_EXIT();
+}
+
+static int
+stm_wait_for(MPT_STM_PRIV *priv, volatile int *flag, int seconds, int sleep)
+{
+    MPT_ADAPTER                *ioc = priv->ioc;
+    int                        i;
+
+       TRACE_ENTRY();
+       for (i = 0; i < seconds * ((sleep == CAN_SLEEP) ? HZ : 1000); i++) {
+               if (!(*flag)) {
+                       return (0);
+               }
+               if (mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_OPERATIONAL) {
+                       printk(KERN_ERR MYNAM
+                                       ":%s IOC is not operational (doorbell = %x)\n",
+                                       ioc->name, mpt_GetIocState(ioc, 0));
+                       return (-1);
+               }
+               if (sleep == CAN_SLEEP) {
+                       set_current_state(TASK_INTERRUPTIBLE);
+                       schedule_timeout(1);
+               } else {
+#ifndef __linux__
+                       if (priv->poll_enabled) {
+                               _mpt_poll(priv->ioc);
+                       }
+#endif
+                       mdelay(1);
+               }
+       }
+
+    /* timed out, so return failure */
+
+    printk(KERN_ERR MYNAM ":%s timed out in stm_wait_for!\n", ioc->name);
+       TRACE_EXIT();
+
+    return (-1);
+}
+
+static int __init
+_mpt_stm_init(void)
+{
+       int i;
+
+       TRACE_ENTRY();
+
+       for (i = 0; i < MPT_MAX_ADAPTERS; i++) {
+               mpt_stm_priv[i] = NULL;
+       }
+
+       stm_context = mpt_register(stm_reply, MPTSTM_DRIVER);
+       if (stm_context < 0) {
+               printk(KERN_ERR MYNAM
+                               ": failed to register with MPT driver core\n");
+               return (-EBUSY);
+       }
+
+       if (mpt_event_register(stm_context, stm_event_process)) {
+               printk(KERN_WARNING MYNAM
+                               ": failed to register for event notification\n");
+       }
+
+       if (mpt_reset_register(stm_context, stm_reset_process)) {
+               printk(KERN_WARNING MYNAM
+                               ": failed to register for reset process\n");
+       }
+
+       TRACE_DBG(": assigned context of %d", stm_context);
+
+       mpt_stm_index = stm_context;
+       TRACE_EXIT();
+
+       return 0;
+}
+
+static int
+mpt_stm_adapter_install(MPT_ADAPTER *ioc)
+{
+    MPT_STM_PRIV               *priv;
+    int                                max_aliases;
+
+       TRACE_ENTRY();
+       priv = kmalloc(sizeof(*priv), GFP_KERNEL);
+       if (priv == NULL) {
+               printk(KERN_ERR MYNAM
+                               ":%s failed to allocate private structure\n", ioc->name);
+               if (priv != NULL)
+                       kfree(priv);
+               return (-1);
+       }
+       memset(priv, 0, sizeof(*priv));
+       if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
+               priv->enable_target_mode = 1;
+       }
+
+       priv->ioc = ioc;
+
+       priv->num_sge_chain = ioc->req_sz / sizeof(MPT_STM_SIMPLE);
+       priv->num_sge_target_assist = (ioc->req_sz -
+                       offsetof(TargetAssistRequest_t, SGL)) / sizeof(MPT_STM_SIMPLE);
+
+       priv->num_cmd_buffers = NUM_CMD_BUFFERS;
+       if (priv->num_cmd_buffers > ioc->pfacts[0].MaxPostedCmdBuffers) {
+               priv->num_cmd_buffers = ioc->pfacts[0].MaxPostedCmdBuffers;
+       }
+       priv->num_els_buffers = NUM_ELS_BUFFERS;
+
+       priv->poll_enabled = 1;
+
+       priv->hw = pci_alloc_consistent(ioc->pcidev, sizeof(*priv->hw),
+                       &priv->hw_dma);
+       if (priv->hw == NULL) {
+               printk(KERN_ERR MYNAM
+                               ":%s failed to allocate hardware structure\n", ioc->name);
+               kfree(priv);
+               return (-1);
+       }
+       memset(priv->hw, 0, sizeof(*priv->hw));
+       printk(KERN_INFO ":%s priv = %p, priv->hw = %p, priv->hw_dma = %llx\n",
+                       ioc->name, priv, priv->hw, (u64)priv->hw_dma);
+
+       mpt_stm_priv[ioc->id] = priv;
+
+       max_aliases = 0;
+       if (IsScsi(priv)) {
+               max_aliases = 14;
+       }
+       if (IsFc(priv)) {
+               memset(priv->hw->config_buf, 0, sizeof(priv->hw->config_buf));
+               if (!stm_get_config_page(priv, MPI_CONFIG_PAGETYPE_FC_PORT, 0, 0,
+                                       NO_SLEEP)) {
+                       max_aliases =
+                               ((FCPortPage0_t *)priv->hw->config_buf)->MaxAliasesSupported;
+               }
+       }
+
+       if (num_aliases < max_aliases) {
+               priv->num_aliases = num_aliases;
+       } else {
+               priv->num_aliases = max_aliases;
+       }
+
+       TRACE_EXIT();
+
+    return (0);
+}
+
+static int
+mpt_stm_adapter_online(MPT_STM_PRIV *priv)
+{
+    MPT_ADAPTER                *ioc;
+    int                        i;
+
+       TRACE_ENTRY();
+    ioc = priv->ioc;
+
+    priv->fcp2_capable = 0;
+#ifdef MPT_STM_ALLOW_FCP2
+    switch (ioc->pcidev->device) {
+       case MPI_MANUFACTPAGE_DEVICEID_FC919:
+       case MPI_MANUFACTPAGE_DEVICEID_FC929:
+           if (ioc->facts.FWVersion.Word >= 0x01630002) {
+               /* firmware version 1.99.00.02 (and later) is FCP-2 capable */
+               priv->fcp2_capable = 1;
+           }
+           break;
+       case MPI_MANUFACTPAGE_DEVICEID_FC919X:
+       case MPI_MANUFACTPAGE_DEVICEID_FC929X:
+           if (ioc->facts.FWVersion.Word >= 0x01013200) {
+               /* firmware version 1.01.50 (and later) is FCP-2 capable */
+               priv->fcp2_capable = 1;
+           }
+           break;
+       case MPI_MANUFACTPAGE_DEVICEID_FC939X:
+       case MPI_MANUFACTPAGE_DEVICEID_FC949X:
+           priv->fcp2_capable = 1;
+           break;
+       default:
+           break;
+    }
+#endif
+
+    priv->port_enable_pending = 0;
+    priv->target_mode_abort_pending = 0;
+    priv->link_serv_abort_pending = 0;
+    priv->fc_primitive_send_pending = 0;
+
+    priv->config_pending = 0;
+    priv->config_mf = NULL;
+
+    priv->port_flags = 0;
+    priv->port_speed = 0;
+
+    priv->in_reset = 0;
+    priv->poll_enabled = 1;
+
+    for (i = 0; i < priv->num_cmd_buffers; i++)
+       priv->io_state[i] = 0;
+
+    if (IsScsi(priv)) {
+       stm_scsi_configuration(priv, NO_SLEEP);
+    }
+
+    if (IsSas(priv)) {
+       stm_sas_configuration(priv, NO_SLEEP);
+    }
+
+       if (priv->enable_target_mode) {
+               if (IsSas(priv)) {
+                       stm_cmd_buf_post_base(priv, 1);
+               } else {
+                       for (i = 0; i < priv->num_cmd_buffers; i++) {
+                               stm_cmd_buf_post(priv, i);
+                       }
+               }
+
+               if (IsFc(priv)) {
+                       for (i = 0; i < priv->num_els_buffers; i++) {
+                               stm_link_serv_buf_post(priv, i);
+                       }
+
+                       stm_fc_enable_els(priv, RSCN, NO_SLEEP);
+
+#ifdef STMAPP_VERIFY_OXIDS
+                       stm_fc_enable_target_mode_oxid(priv, NO_SLEEP);
+#endif
+
+                       stm_fc_enable_aliases(priv, priv->num_aliases, NO_SLEEP);
+               }
+       }
+
+    stm_port_enable(priv);
+
+    if (IsFc(priv)) {
+       stm_reset_link(priv);
+    }
+
+    if (IsFc(priv)) {
+       /* wait up to 5 seconds for the link to come up */
+       for (i = 0; i < 50; i++) {
+           stm_fc_configuration(priv, NO_SLEEP);
+           if (priv->port_flags != MPI_FCPORTPAGE0_FLAGS_ATTACH_NO_INIT) {
+               break;
+           }
+           mdelay(100);
+       }
+    }
+       TRACE_EXIT();
+
+    return (0);
+}
+
+static void
+_mpt_stm_exit(void)
+{
+       TRACE_ENTRY();
+       if (stm_context > 0) {
+               mpt_reset_deregister(stm_context);
+               mpt_event_deregister(stm_context);
+
+               mpt_device_driver_deregister(MPTSTM_DRIVER);
+
+               mpt_deregister(stm_context);
+               stm_context = 0;
+       }
+
+    mpt_stm_index = 0;
+       TRACE_EXIT();
+}
+
+static void
+mpt_stm_adapter_dispose(MPT_STM_PRIV *priv)
+{
+       MPT_ADAPTER             *ioc;
+
+       TRACE_ENTRY();
+       priv->exiting = 1;
+
+       ioc = priv->ioc;
+
+       if (mpt_GetIocState(ioc, 1) == MPI_IOC_STATE_OPERATIONAL) {
+               if (priv->enable_target_mode && priv->tgt->target_enable) {
+                       stm_target_mode_abort(priv);
+
+                       if (IsFc(priv)) {
+                               stm_link_serv_abort(priv);
+                       }
+               }
+       }
+
+       mpt_stm_priv[ioc->id] = NULL;
+       if (priv->hw != NULL) {
+               pci_free_consistent(ioc->pcidev, sizeof(*priv->hw),
+                               priv->hw, priv->hw_dma);
+       }
+       if (priv->config_mf != NULL) {
+               mpt_free_msg_frame(_HANDLE_IOC_ID, priv->config_mf);
+       }
+       kfree(priv);
+
+       TRACE_EXIT();
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static void
+stmapp_set_status(MPT_STM_PRIV *priv, CMD *cmd, int status)
+{
+       TRACE_ENTRY();
+    if (IsScsi(priv)) {
+       SCSI_RSP        *rsp = (SCSI_RSP *)cmd->rsp;
+
+       rsp->Status = (u8)status;
+    } else if (IsSas(priv)) {
+       SSP_RSP         *rsp = (SSP_RSP *)cmd->rsp;
+
+       rsp->Status = (u8)status;
+    } else {
+       FCP_RSP         *rsp = (FCP_RSP *)cmd->rsp;
+
+       rsp->FcpStatus = (u8)status;
+    }
+       TRACE_EXIT();
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static void
+stmapp_abts_process(MPT_STM_PRIV *priv,
+                   int rx_id, LinkServiceBufferPostReply_t *rep, int index)
+{
+#ifdef DEBUG
+    MPT_ADAPTER                *ioc = priv->ioc;
+#endif
+    volatile int       *io_state;
+    CMD                        *cmd;
+
+       TRACE_ENTRY();
+       io_state = priv->io_state + rx_id;
+
+       if (*io_state & IO_STATE_ABORTED) {
+               return;
+       }
+
+       if (*io_state & IO_STATE_POSTED) {
+               return;
+       }
+
+       cmd = &priv->hw->cmd_buf[rx_id];
+
+       TRACE_DBG("%s index %d: io_state = %x",
+                       ioc->name, rx_id, *io_state);
+       TRACE_DBG("%s reply_word = %x, alias = %d, lun = %d, tag = %x",
+                       ioc->name, cmd->reply_word, cmd->alias, cmd->lun, cmd->tag);
+
+       /*
+        *  if we are processing an SRR, there could be some other flags set
+        *  in io_state that we need to get rid of; ABTS overrides SRR
+        */
+       *io_state &= ~IO_STATE_REQUEST_ABORTED;
+    *io_state &= ~IO_STATE_REISSUE_REQUEST;
+    *io_state &= ~IO_STATE_ADJUST_OFFSET;
+    *io_state &= ~IO_STATE_CONVERT_TA_TO_TSS;
+    *io_state &= ~IO_STATE_REDO_COMMAND;
+
+    /*
+     *  if we get here, the firmware thinks a command is active,
+     *  so it should be aborted
+     */
+    TRACE_DBG("%s index %d needs to be aborted", ioc->name, rx_id);
+    stm_target_mode_abort_command(priv, cmd->reply_word, rx_id);
+
+       TRACE_EXIT();
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static void
+stmapp_srr_process(MPT_STM_PRIV *priv, int rx_id, int r_ctl, u32 offset,
+                  LinkServiceBufferPostReply_t *rep, int index)
+{
+#ifdef DEBUG
+    MPT_ADAPTER                *ioc = priv->ioc;
+#endif
+    FC_ELS             *fc_els_buf;
+    volatile int       *io_state;
+    u32                        msg_context;
+    CMD                        *cmd;
+    int                        need_abort = 0;
+    u32                        rel_off;
+    u32                        dat_len;
+    u32                        adjust;
+    u32                        block_size = 512;
+
+       TRACE_ENTRY();
+    fc_els_buf = &priv->hw->fc_link_serv_buf[index];
+    io_state = priv->io_state + rx_id;
+
+    if (*io_state & IO_STATE_ABORTED) {
+       /*
+        *  the initiator wants to continue an I/O that we're aborting;
+        *  just accept this SRR, and continue aborting
+        */
+       fc_els_buf->fc_els[0] = cpu_to_be32(0x02000000);
+       stm_send_els(priv, rep, index, 4);
+       return;
+    }
+
+    if (*io_state & IO_STATE_POSTED) {
+       /*
+        *  the firmware should prevent this from happening, but if it does,
+        *  reject this SRR with "invalid OX_ID/RX_ID combination"
+        */
+       fc_els_buf->fc_els[0] = cpu_to_be32(0x01000000);
+       fc_els_buf->fc_els[1] = cpu_to_be32(0x00090300);
+       stm_send_els(priv, rep, index, 8);
+       return;
+    }
+
+    cmd = &priv->hw->cmd_buf[rx_id];
+
+    TRACE_DBG("%s index %d: r_ctl = %x, io_state = %x",
+           ioc->name, rx_id, r_ctl, *io_state);
+    TRACE_DBG("%s reply_word = %x, alias = %d, lun = %d, tag = %x",
+           ioc->name, cmd->reply_word, cmd->alias, cmd->lun, cmd->tag);
+
+    if (*io_state & (IO_STATE_DATA_SENT | IO_STATE_STATUS_SENT)) {
+       /*
+        *  if we get here, the firmware thinks a request is active,
+        *  so it should be aborted
+        */
+       TRACE_DBG("%s index %d needs to be aborted",
+               ioc->name, rx_id);
+       if (*io_state & IO_STATE_DATA_SENT) {
+           TargetAssistRequest_t       *req;
+
+           req = (TargetAssistRequest_t *)priv->current_mf[rx_id];
+           msg_context = le32_to_cpu(req->MsgContext);
+           rel_off = le32_to_cpu(req->RelativeOffset);
+           dat_len = le32_to_cpu(req->DataLength);
+           TRACE_DBG("%s SRR offset = %x, TA offset = %x, TA length = %x",
+                   ioc->name, offset, rel_off, dat_len);
+           if (r_ctl == 1 || r_ctl == 5) {
+               if (offset < rel_off && (offset % block_size) == 0) {
+                   TRACE_DBG("%s request can be reissued",
+                           ioc->name);
+                   adjust = rel_off + dat_len - offset;
+                   *io_state |= IO_STATE_INCOMPLETE;
+                   *io_state |= IO_STATE_REDO_COMMAND;
+                   *io_state |= IO_STATE_REISSUE_REQUEST;
+                   need_abort = 1;
+               }
+               if (offset >= rel_off && offset <= rel_off + dat_len) {
+                   TRACE_DBG("%s request can be reissued",
+                           ioc->name);
+                   if (offset != rel_off) {
+                       if (offset != rel_off + dat_len) {
+                           //cmd->offset = offset;
+                           *io_state |= IO_STATE_ADJUST_OFFSET;
+                       } else {
+                           *io_state |= IO_STATE_CONVERT_TA_TO_TSS;
+                       }
+                   }
+                   *io_state |= IO_STATE_REISSUE_REQUEST;
+                   need_abort = 1;
+               }
+           } else if (r_ctl == 7) {
+               if (*io_state & IO_STATE_STATUS_SENT) {
+                   TRACE_DBG("%s request can be reissued",
+                           ioc->name);
+                   *io_state |= IO_STATE_CONVERT_TA_TO_TSS;
+                   *io_state |= IO_STATE_REISSUE_REQUEST;
+                   need_abort = 1;
+               }
+               if (*io_state & IO_STATE_STATUS_DEFERRED) {
+                   TRACE_DBG("%s request can be reissued",
+                           ioc->name);
+                   *io_state |= IO_STATE_REISSUE_REQUEST;
+                   need_abort = 1;
+               }
+           } else {
+               TRACE_DBG("%s request cannot be reissued",
+                       ioc->name);
+           }
+       } else {
+           TargetStatusSendRequest_t   *req;
+
+           req = (TargetStatusSendRequest_t *)priv->current_mf[rx_id];
+           msg_context = le32_to_cpu(req->MsgContext);
+           if (r_ctl == 7) {
+               TRACE_DBG("%s request can be reissued",
+                       ioc->name);
+               *io_state |= IO_STATE_REISSUE_REQUEST;
+               need_abort = 1;
+           } else {
+               TRACE_DBG("%s request cannot be reissued",
+                       ioc->name);
+           }
+       }
+       if (need_abort) {
+           stm_target_mode_abort_request(priv, cmd->reply_word, msg_context,
+                                         rx_id);
+       }
+    }
+
+    if (*io_state & IO_STATE_REISSUE_REQUEST) {
+       /*
+        *  if we can continue this I/O, accept this SRR
+        */
+       fc_els_buf->fc_els[0] = cpu_to_be32(0x02000000);
+       stm_send_els(priv, rep, index, 4);
+    } else {
+       /*
+        *  we can't continue the I/O, so reject this SRR with "unable to
+        *  supply requested data"
+        */
+       fc_els_buf->fc_els[0] = cpu_to_be32(0x01000000);
+       fc_els_buf->fc_els[1] = cpu_to_be32(0x00092a00);
+       stm_send_els(priv, rep, index, 8);
+    }
+       TRACE_EXIT();
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static void
+stmapp_srr_convert_ta_to_tss(MPT_STM_PRIV *priv, int index)
+{
+    MPT_ADAPTER                *ioc = priv->ioc;
+    volatile int       *io_state;
+    CMD                        *cmd;
+    u32                        reply_word;
+    int                        lun;
+    int                        tag;
+    int                        flags;
+
+       TRACE_ENTRY();
+    io_state = priv->io_state + index;
+
+    cmd = &priv->hw->cmd_buf[index];
+
+    reply_word = cmd->reply_word;
+    lun = cmd->lun;
+    tag = cmd->tag;
+
+    *io_state &= ~IO_STATE_DATA_SENT;
+    *io_state &= ~IO_STATE_STATUS_SENT;
+    mpt_free_msg_frame(_HANDLE_IOC_ID, priv->current_mf[index]);
+
+    flags = TARGET_STATUS_SEND_FLAGS_AUTO_GOOD_STATUS;
+    if (*io_state & IO_STATE_AUTO_REPOST) {
+       flags |= TARGET_STATUS_SEND_FLAGS_REPOST_CMD_BUFFER;
+    }
+    stm_send_target_status(priv, reply_word, index, flags, lun, tag);
+       TRACE_EXIT();
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static void
+stmapp_srr_adjust_offset(MPT_STM_PRIV *priv, int index)
+{
+    CMD                                *cmd;
+    TargetAssistRequest_t      *req;
+    u32                                old_offset;
+    u32                                new_offset = 0;
+    u32                                offset;
+    MPT_STM_SIMPLE             *sge_simple;
+    MPT_STM_CHAIN              *sge_chain = NULL;
+    u32                                flags_length;
+    int                                type;
+    int                                old_length;
+    int                                new_length;
+    int                                length;
+    dma_addr_t                 dma_addr;
+    int                                n;
+
+       TRACE_ENTRY();
+    cmd = &priv->hw->cmd_buf[index];
+    req = (TargetAssistRequest_t *)priv->current_mf[index];
+
+    old_offset = le32_to_cpu(req->RelativeOffset);
+
+    /* walk the SGL, skipping along until we get to the right offset */
+    offset = old_offset;
+    sge_simple = (MPT_STM_SIMPLE *)&req->SGL;
+    n = 0;
+    while (1) {
+       flags_length = le32_to_cpu(sge_simple->FlagsLength);
+       type = MPI_SGE_GET_FLAGS(flags_length) & MPI_SGE_FLAGS_ELEMENT_MASK;
+       if (type == MPI_SGE_FLAGS_CHAIN_ELEMENT) {
+           if (sge_chain == NULL) {
+               sge_chain = (MPT_STM_CHAIN *)sge_simple;
+               stm_get_dma_addr(dma_addr, sge_chain->Address);
+               sge_simple = (MPT_STM_SIMPLE *)
+                   ((u8 *)priv->hw + (dma_addr - priv->hw_dma));
+           } else {
+               sge_chain = (MPT_STM_CHAIN *)sge_simple;
+               sge_simple = (MPT_STM_SIMPLE *)(sge_chain + 1);
+           }
+           n = 0;
+       } else {
+           length = MPI_SGE_LENGTH(flags_length);
+           if (offset + length > new_offset) {
+               break;
+           }
+           offset += length;
+           sge_simple++;
+           n++;
+       }
+    }
+
+    /* fix up the current SGE */
+    flags_length -= new_offset - offset;
+    sge_simple->FlagsLength = le32_to_cpu(flags_length);
+    stm_get_dma_addr(dma_addr, sge_simple->Address);
+    dma_addr += new_offset - offset;
+    stm_set_dma_addr(sge_simple->Address, dma_addr);
+
+    /* if we have skipped any SGEs, we need to use a chain to point to */
+    /* the new "first" SGE */
+    if (sge_simple != (MPT_STM_SIMPLE *)&req->SGL) {
+       /* see if we've already walked past a chain */
+       if (sge_chain == NULL) {
+           /* all we have to do here is move the SGEs in the request frame */
+           memmove(&req->SGL, sge_simple,
+                   (priv->num_sge_target_assist - n) *
+                       sizeof(MPT_STM_SIMPLE));
+           if (req->ChainOffset != 0) {
+               req->ChainOffset -= n * sizeof(MPT_STM_SIMPLE) / sizeof(u32);
+           }
+       } else {
+           /* we have to build a chain on top of the first SGE */
+           length = le16_to_cpu(sge_chain->Length) -
+               n * sizeof(MPT_STM_SIMPLE);
+           offset = sge_chain->NextChainOffset;
+           sge_chain = (MPT_STM_CHAIN *)&req->SGL;
+           sge_chain->Length = cpu_to_le16(length);
+           sge_chain->NextChainOffset = (u8)offset;
+           sge_chain->Flags =
+               (u8)(MPI_SGE_FLAGS_CHAIN_ELEMENT |
+                    MPI_SGE_FLAGS_MPT_STM_ADDRESSING);
+           dma_addr = priv->hw_dma + ((u8 *)sge_simple - (u8 *)priv->hw);
+           stm_set_dma_addr(sge_chain->Address, dma_addr);
+           req->ChainOffset = (u32 *)sge_chain - (u32 *)req;
+       }
+    }
+
+    /* fix up the offset and length */
+    old_length = le32_to_cpu(req->DataLength);
+    new_length = old_length - (new_offset - old_offset);
+
+    req->RelativeOffset = cpu_to_le32(new_offset);
+    req->DataLength = cpu_to_le32(new_length);
+       TRACE_EXIT();
+}
+
+static void 
+stmapp_target_error_prioprity_io(MPT_STM_PRIV *priv,
+               u32 reply_word, int index, int status, int reason,
+               int lun, int tag)
+{
+    MPT_ADAPTER                *ioc = priv->ioc;
+       struct mpt_cmd *mpt_cmd;
+       struct scst_cmd *scst_cmd;
+    volatile int       *io_state;
+    CMD                        *cmd;
+
+       /*
+        *  we want stm_target_cleanup to do everything except repost the
+        *  command buffer, so fake it out a bit
+        */
+       TRACE_ENTRY();
+    io_state = priv->io_state + index;
+       *io_state |= IO_STATE_AUTO_REPOST;
+       scst_cmd = priv->scst_cmd[index];
+       mpt_cmd = (struct mpt_cmd *)scst_cmd_get_tgt_priv(scst_cmd);
+       mpt_cmd->state = MPT_STATE_PROCESSED;
+
+       mpt_msg_frame_free(priv, index);
+       /* stm_target_cleanup(priv, index); */
+       *io_state = IO_STATE_HIGH_PRIORITY;
+
+       cmd = &priv->hw->cmd_buf[index];
+       memset(cmd->rsp, 0, sizeof(cmd->rsp));
+
+       switch (reason) {
+               case PRIORITY_REASON_CMD_PARITY_ERR:
+                       printk(KERN_ERR MYNAM ":%s "
+                                       "detected parity error during Command phase\n",
+                                       ioc->name);
+                       stmapp_set_sense_info(priv, cmd,
+                                       SK_ABORTED_COMMAND, 0x47, 0x00);
+                       break;
+               case PRIORITY_REASON_MSG_OUT_PARITY_ERR:
+                       printk(KERN_ERR MYNAM ":%s "
+                                       "detected parity error during Message Out phase\n",
+                                       ioc->name);
+                       stmapp_set_sense_info(priv, cmd,
+                                       SK_ABORTED_COMMAND, 0x43, 0x00);
+                       break;
+               case PRIORITY_REASON_CMD_CRC_ERR:
+                       printk(KERN_ERR MYNAM ":%s "
+                                       "detected CRC error while receiving CMD_IU\n",
+                                       ioc->name);
+                       stmapp_set_sense_info(priv, cmd,
+                                       SK_ABORTED_COMMAND, 0x47, 0x03);
+                       break;
+               case PRIORITY_REASON_PROTOCOL_ERR:
+                       printk(KERN_ERR MYNAM ":%s "
+                                       "received Initiator Detected Error message\n",
+                                       ioc->name);
+                       stmapp_set_sense_info(priv, cmd,
+                                       SK_ABORTED_COMMAND, 0x48, 0x00);
+                       break;
+               case PRIORITY_REASON_DATA_OUT_PARITY_ERR:
+                       printk(KERN_ERR MYNAM ":%s "
+                                       "detected parity error during Data Out phase\n",
+                                       ioc->name);
+                       stmapp_set_sense_info(priv, cmd,
+                                       SK_ABORTED_COMMAND, 0x47, 0x02);
+                       break;
+               case PRIORITY_REASON_DATA_OUT_CRC_ERR:
+                       printk(KERN_ERR MYNAM ":%s "
+                                       "detected CRC error during Data Out phase\n",
+                                       ioc->name);
+                       stmapp_set_sense_info(priv, cmd,
+                                       SK_ABORTED_COMMAND, 0x47, 0x01);
+                       break;
+               default:
+                       printk(KERN_ERR MYNAM ":%s unknown PriorityReason = %x\n",
+                                       ioc->name, reason);
+                       stmapp_set_sense_info(priv, cmd,
+                                       SK_ABORTED_COMMAND, 0x00, 0x00);
+       }
+
+       stm_send_target_status(priv, reply_word, index, 0, lun, tag);
+
+       TRACE_EXIT();
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static void
+stmapp_target_error(MPT_STM_PRIV *priv,
+                   u32 reply_word, int index, int status, int reason)
+{
+    MPT_ADAPTER                *ioc = priv->ioc;
+    volatile int       *io_state;
+    CMD                        *cmd;
+    int                        lun = 0;
+    int                        tag = 0;
+
+       TRACE_ENTRY();
+    TRACE_DBG("%s target error, index %d, status %x, reason %x",
+           ioc->name, index, status, reason);
+
+    io_state = priv->io_state + index;
+
+    if (*io_state & IO_STATE_DATA_SENT) {
+       TargetAssistRequest_t   *req;
+
+       req = (TargetAssistRequest_t *)priv->current_mf[index];
+       lun = get2bytes(req->LUN, 0);
+       tag = req->QueueTag;
+    }
+
+    if (*io_state & IO_STATE_STATUS_SENT) {
+       TargetStatusSendRequest_t       *req;
+
+       req = (TargetStatusSendRequest_t *)priv->current_mf[index];
+       lun = get2bytes(req->LUN, 0);
+       tag = req->QueueTag;
+    }
+
+    /*
+     *  if the status is Target Priority I/O, the I/O is still
+     *  active and a response is needed
+     */
+    if (status == MPI_IOCSTATUS_TARGET_PRIORITY_IO) {
+               stmapp_target_error_prioprity_io(priv, reply_word, index, status,
+                               reason, lun, tag);
+               return;
+    }
+
+    /*
+     *  if the status is Target Transfer Count Mismatch, Target Data Offset
+     *  Error, Target Too Much Write Data, Target IU Too Short, EEDP Guard
+     *  Error, EEDP Reference Tag Error, or EEDP Application Tag Error, thes
+     *  I/O is still active and a response is needed
+     */
+    if (status == MPI_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH ||
+       status == MPI_IOCSTATUS_TARGET_DATA_OFFSET_ERROR   ||
+       status == MPI_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA ||
+       status == MPI_IOCSTATUS_TARGET_IU_TOO_SHORT ||
+       status == MPI_IOCSTATUS_EEDP_GUARD_ERROR ||
+       status == MPI_IOCSTATUS_EEDP_REF_TAG_ERROR ||
+       status == MPI_IOCSTATUS_EEDP_APP_TAG_ERROR) {
+       /*
+        *  we want stm_target_cleanup to do everything except repost the
+        *  command buffer, so fake it out a bit
+        */
+       *io_state |= IO_STATE_AUTO_REPOST;
+       stm_target_cleanup(priv, index);
+       *io_state = 0;
+
+       cmd = &priv->hw->cmd_buf[index];
+       memset(cmd->rsp, 0, sizeof(cmd->rsp));
+
+       switch (status) {
+           case MPI_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH:
+               printk(KERN_ERR MYNAM ":%s transfer count mismatch\n",
+                      ioc->name);
+               stmapp_set_sense_info(priv, cmd,
+                                     SK_ABORTED_COMMAND, 0x4b, 0x00);
+               break;
+           case MPI_IOCSTATUS_TARGET_DATA_OFFSET_ERROR:
+               printk(KERN_ERR MYNAM ":%s data offset error\n",
+                      ioc->name);
+               stmapp_set_sense_info(priv, cmd,
+                                     SK_ABORTED_COMMAND, 0x4b, 0x05);
+               break;
+           case MPI_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA:
+               printk(KERN_ERR MYNAM ":%s too much write data\n",
+                      ioc->name);
+               stmapp_set_sense_info(priv, cmd,
+                                     SK_ABORTED_COMMAND, 0x4b, 0x02);
+               break;
+           case MPI_IOCSTATUS_TARGET_IU_TOO_SHORT:
+               printk(KERN_ERR MYNAM ":%s IU too short\n",
+                      ioc->name);
+               stmapp_set_sense_info(priv, cmd,
+                                     SK_ABORTED_COMMAND, 0x0e, 0x01);
+               break;
+           case MPI_IOCSTATUS_EEDP_GUARD_ERROR:
+               printk(KERN_ERR MYNAM ":%s EEDP Guard Error\n",
+                      ioc->name);
+               stmapp_set_sense_info(priv, cmd,
+                                     SK_ABORTED_COMMAND, 0x10, 0x01);
+               break;
+           case MPI_IOCSTATUS_EEDP_REF_TAG_ERROR:
+               printk(KERN_ERR MYNAM ":%s EEDP Reference Tag Error\n",
+                      ioc->name);
+               stmapp_set_sense_info(priv, cmd,
+                                     SK_ABORTED_COMMAND, 0x10, 0x03);
+               break;
+           case MPI_IOCSTATUS_EEDP_APP_TAG_ERROR:
+               printk(KERN_ERR MYNAM ":%s EEDP Application Tag Error\n",
+                      ioc->name);
+               stmapp_set_sense_info(priv, cmd,
+                                     SK_ABORTED_COMMAND, 0x10, 0x02);
+               break;
+       }
+
+       stm_send_target_status(priv, reply_word, index, 0, lun, tag);
+       return;
+    }
+
+    /*
+     *  the SCSI firmware has a bug, where if the Status Data Not Sent error
+     *  is returned, and the original command requested Auto Repost, the
+     *  command buffer is reposted, even though an error is generated; so,
+     *  ignore the error here, so that we don't post this command buffer again
+     *  (that is, treat this as a successful completion, which is what it is)
+     */
+       if (IsScsi(priv) && status == MPI_IOCSTATUS_TARGET_STS_DATA_NOT_SENT) {
+               if (*io_state & IO_STATE_AUTO_REPOST) {
+                       stm_tgt_reply(ioc, reply_word);
+                       TRACE_EXIT();
+                       return;
+               }
+       }
+
+    *io_state &= ~IO_STATE_AUTO_REPOST;
+    stm_target_cleanup(priv, index);
+       TRACE_EXIT();
+}
+
+static void
+stmapp_set_sense_info(MPT_STM_PRIV *priv,
+                     CMD *cmd,
+                     int sense_key,
+                     int asc,
+                     int ascq)
+{
+    u8 *info;
+
+       TRACE_ENTRY();
+    if (IsScsi(priv)) {
+       SCSI_RSP        *rsp = (SCSI_RSP *)cmd->rsp;
+
+       rsp->Status = STS_CHECK_CONDITION;
+       rsp->Valid |= SCSI_SENSE_LEN_VALID;
+       rsp->SenseDataListLength = cpu_to_be32(14);
+       info = rsp->SenseData;
+       if (rsp->Valid & SCSI_RSP_LEN_VALID) {
+           info += be32_to_cpu(rsp->PktFailuresListLength);
+       }
+    } else if (IsSas(priv)) {
+       SSP_RSP         *rsp = (SSP_RSP *)cmd->rsp;
+
+       rsp->Status = STS_CHECK_CONDITION;
+       rsp->DataPres |= SSP_SENSE_LEN_VALID;
+       rsp->SenseDataLength = cpu_to_be32(14);
+       info = rsp->ResponseSenseData;
+       if (rsp->DataPres & SSP_RSP_LEN_VALID) {
+           info += be32_to_cpu(rsp->ResponseDataLength);
+       }
+    } else {
+       FCP_RSP         *rsp = (FCP_RSP *)cmd->rsp;
+
+       rsp->FcpStatus = STS_CHECK_CONDITION;
+       rsp->FcpFlags |= FCP_SENSE_LEN_VALID;
+       rsp->FcpSenseLength = cpu_to_be32(14);
+       info = rsp->FcpSenseData - sizeof(rsp->FcpResponseData);
+       if (rsp->FcpFlags & FCP_RSP_LEN_VALID) {
+           info += be32_to_cpu(rsp->FcpResponseLength);
+       }
+    }
+    info[0] = 0x70;
+    info[2] = (u8)sense_key;
+    info[7] = 6;
+    info[12] = (u8)asc;
+    info[13] = (u8)ascq;
+       TRACE_EXIT();
+}
+
+#define MPT_PROC_LOG_ENTRY_NAME "trace_level"
+#ifdef TRACING
+static struct scst_proc_log mpt_spec_tbl[] = 
+{
+       { TRACE_MPI,    "mpt_mpi" },
+       { 0, NULL }
+};
+#endif
+
+static int mpt_proc_log_entry_read(char *buffer, char **start,
+               off_t offset, int length, int *eof,
+               void *data)
+{
+       int res = 0;
+
+       TRACE_ENTRY();
+#ifdef TRACING
+       res = scst_proc_log_entry_read(buffer, start, offset, length, eof,
+                       data, trace_flag, mpt_spec_tbl);
+#endif
+
+       TRACE_EXIT_RES(res);
+       return res;
+}
+
+static int mpt_proc_log_entry_write(struct file *file, const char *buf,
+               unsigned long length, void *data)
+{
+       int res = 0;
+
+       TRACE_ENTRY();
+
+#ifdef TRACING
+       res = scst_proc_log_entry_write(file, buf, length, data,
+                       &trace_flag, (TRACE_FUNCTION | TRACE_OUT_OF_MEM | TRACE_MGMT | \
+                                   TRACE_MINOR | TRACE_SPECIAL), mpt_spec_tbl);
+#endif
+
+       TRACE_EXIT_RES(res);
+       return res;
+}
+
+static int mpt_proc_log_entry_build(struct scst_tgt_template *templ)
+{
+       int res = 0;
+       struct proc_dir_entry *p, *root;
+
+       TRACE_ENTRY();
+       root = scst_proc_get_tgt_root(templ);
+
+       if (root) {
+               p = create_proc_read_entry(MPT_PROC_LOG_ENTRY_NAME,
+                               S_IFREG | S_IRUGO | S_IWUSR, root,
+                               mpt_proc_log_entry_read,
+                               (void *)templ->name);
+               if (p == NULL) {
+                       PRINT_ERROR("Not enough memory to register "
+                                       "target driver %s entry %s in /proc",
+                                       templ->name, MPT_PROC_LOG_ENTRY_NAME);
+                       res = -ENOMEM;
+                       goto out;
+               }
+               p->write_proc = mpt_proc_log_entry_write;
+       }
+out:
+
+       TRACE_EXIT_RES(res);
+
+       return res;
+}
+
+static void mpt_proc_log_entry_clean(struct scst_tgt_template *templ)
+{
+       struct proc_dir_entry *root;
+
+       TRACE_ENTRY();
+       root = scst_proc_get_tgt_root(templ);
+
+       if (root) {
+               remove_proc_entry(MPT_PROC_LOG_ENTRY_NAME, root);
+       }
+
+       TRACE_EXIT();
+}
+
+static int __init mpt_target_init(void)
+{
+       int res = 0;
+
+       TRACE_ENTRY();
+       
+       if (scst_register_target_template(&tgt_template) < 0) {
+               res = -ENODEV;
+               goto out;
+       }
+
+       res = mpt_proc_log_entry_build(&tgt_template);
+       if (res < 0) {
+               goto out_unreg_target;
+       }
+
+ out:
+       TRACE_EXIT_RES(res);
+
+       return res;
+
+out_unreg_target:
+       scst_unregister_target_template(&tgt_template);
+       goto out;
+}
+
+static void __exit mpt_target_exit(void)
+{
+       TRACE_ENTRY();
+
+       mpt_proc_log_entry_clean(&tgt_template);
+       scst_unregister_target_template(&tgt_template);
+       _mpt_stm_exit();
+       
+       TRACE_EXIT();
+       return;
+}
+
+#ifdef DEBUG
+unsigned long trace_flag = TRACE_FUNCTION | TRACE_OUT_OF_MEM | TRACE_SPECIAL;
+#else
+# ifdef TRACING
+unsigned long trace_flag = TRACE_OUT_OF_MEM | TRACE_MGMT | TRACE_SPECIAL;
+# endif
+#endif
+
+module_init(mpt_target_init);
+module_exit(mpt_target_exit);
+
+MODULE_AUTHOR("Hu Gang <hugang@soulinfo.com>");
+MODULE_DESCRIPTION("Fusion MPT SCSI Target Mode Driver for SCST Version 0.1");
+MODULE_LICENSE("GPL");
diff --git a/mpt/mpt_scst.h b/mpt/mpt_scst.h
new file mode 100644 (file)
index 0000000..830d555
--- /dev/null
@@ -0,0 +1,366 @@
+#ifndef __MPT_SCST_H
+#define __MPT_SCST_H
+
+#if defined(MODULE) && !defined(__GENKSYMS__)
+#include <linux/config.h>
+#include <linux/module.h>
+#endif
+
+#ifdef __linux__
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/miscdevice.h>
+#include <linux/proc_fs.h>
+#include <linux/smp_lock.h>
+#include <linux/highmem.h>
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/div64.h>
+#endif
+
+#define _HS_SLEEP ,0
+#define _IOC_ID ioc
+#define _HANDLE_IOC_ID ioc
+
+#ifndef MPT_STM_64_BIT_DMA  /* determines the size of DMA addresses */
+#define MPT_STM_64_BIT_DMA 1
+#endif
+
+#include "linux_compat.h"
+#include "mptbase.h"
+
+#ifndef MPI_IOCLOGINFO_FC_LINK_ALREADY_INITIALIZED
+#define MPI_IOCLOGINFO_FC_LINK_ALREADY_INITIALIZED 0x24000002
+#endif
+
+#define MF_TO_INDEX(mf) le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx)
+
+#include "scsi3.h"
+
+/*****************************************************************************/
+#ifdef MPI_STM_IO_DEBUG
+#define dioprintk printk
+#else
+#define dioprintk printk
+#endif
+
+typedef MPI_TARGET_FCP_CMD_BUFFER FCP_CMD;
+
+typedef MPI_TARGET_SCSI_SPI_CMD_BUFFER SCSI_CMD;
+
+#define SSP_CMD_FRAME          0x06
+#define        SSP_TASK_FRAME          0x16
+
+typedef MPI_TARGET_SSP_CMD_BUFFER SSP_CMD;
+typedef MPI_TARGET_SSP_TASK_BUFFER SSP_TASK;
+
+#define FCP_REQUEST_CONFIRM    (1<<4)
+#define FCP_RESID_UNDER                (1<<3)
+#define FCP_RESID_OVER         (1<<2)
+#define FCP_SENSE_LEN_VALID    (1<<1)
+#define FCP_RSP_LEN_VALID      (1<<0)
+
+typedef struct _FCP_RSP  /* this struct is wrong in rev 1.02.04 of mpi_targ.h */
+{
+    U8      Reserved0[8];                               /* 00h */
+    U8      Reserved1[2];                               /* 08h */
+    U8      FcpFlags;                                   /* 0Ah */
+    U8      FcpStatus;                                  /* 0Bh */
+    U32     FcpResid;                                   /* 0Ch */
+    U32     FcpSenseLength;                             /* 10h */
+    U32     FcpResponseLength;                          /* 14h */
+    U8      FcpResponseData[8];                         /* 18h */
+    U8      FcpSenseData[32]; /* Pad to 64 bytes */     /* 20h */
+} FCP_RSP;
+
+#define SCSI_SENSE_LEN_VALID   (1<<1)
+#define SCSI_RSP_LEN_VALID     (1<<0)
+
+typedef MPI_TARGET_SCSI_SPI_STATUS_IU SCSI_RSP;
+
+#define SSP_SENSE_LEN_VALID    (1<<1)
+#define SSP_RSP_LEN_VALID      (1<<0)
+
+typedef MPI_TARGET_SSP_RSP_IU SSP_RSP;
+
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+/*
+ *  Fusion MPT STM private structures
+ */
+
+#define IsFc(priv)      \
+    (priv->ioc->pfacts[0].PortType == MPI_PORTFACTS_PORTTYPE_FC)
+#define IsScsi(priv)    \
+    (priv->ioc->pfacts[0].PortType == MPI_PORTFACTS_PORTTYPE_SCSI)
+#define IsSas(priv)    \
+    (priv->ioc->pfacts[0].PortType == MPI_PORTFACTS_PORTTYPE_SAS)
+
+#define ABORT_ALL              (-1)
+
+#define NUM_CMD_BUFFERS                128
+#define NUM_ELS_BUFFERS                64
+
+#define NUM_ALIASES            0  /* 0 to 125, hardware restriction */
+
+#define ELS                    0x22
+#define FC4LS                  0x32
+#define ABTS                   0x81
+#define BA_ACC                 0x84
+
+#define LS_RJT                 0x01
+#define LS_ACC                 0x02
+#define PLOGI                  0x03
+#define LOGO                   0x05
+#define SRR                    0x14
+#define PRLI                   0x20
+#define PRLO                   0x21
+#define ADISC                  0x52
+#define RSCN                   0x61
+
+typedef struct _MPT_SGE
+{
+    u32                        length;
+#if MPT_STM_64_BIT_DMA
+    u64                        address;
+#else
+    u32                        address;
+#endif
+} MPT_SGE;
+
+#define NUM_SGES       64
+#define NUM_CHAINS     (NUM_SGES/8)    /* one chain for every 8 SGEs */
+
+typedef struct _CMD {
+    u8                 cmd[64];
+    u8                 rsp[64];
+    MPT_SGE            chain_sge[NUM_SGES+NUM_CHAINS];
+    u32                        reply_word;
+    int                        alias;
+    int                        lun;
+    int                        tag;
+} CMD;
+
+typedef struct _FC_ELS {
+    u32                        fc_els[32];
+} FC_ELS;
+
+typedef struct _MPT_STM_HW {
+    CMD                        cmd_buf[NUM_CMD_BUFFERS];
+    FC_ELS             fc_link_serv_buf[NUM_ELS_BUFFERS];
+    u32                        config_buf[256];
+    u32                        ctsend_buf[256];
+    u32                        exlink_buf[32];
+} MPT_STM_HW;
+
+typedef struct _MPT_SGL
+{
+    u32                        num_sges;
+    MPT_SGE            sge[NUM_SGES];
+} MPT_SGL;
+
+typedef struct _MPT_STM_PRIV
+{
+    MPT_ADAPTER                *ioc;
+    int                        enable_target_mode;
+    int                        fcp2_capable;
+    int                        num_sge_chain;
+    int                        num_sge_target_assist;
+    int                        num_cmd_buffers;
+    int                        num_els_buffers;
+    int                        num_aliases;
+    MPT_STM_HW         *hw;
+    dma_addr_t         hw_dma;
+    U64                        wwnn;
+    U64                        wwpn;
+    int                        port_id;
+    int                        protocol;
+    volatile int       port_flags;
+    volatile int       port_speed;
+    volatile int       port_state;
+    volatile int       device_changed;
+    int                        port_enable_loginfo;
+    volatile int       port_enable_pending;
+    volatile int       target_mode_abort_pending;
+    volatile int       link_serv_abort_pending;
+    volatile int       fc_primitive_send_pending;
+    volatile int       ex_link_service_send_pending;
+    volatile int       config_pending;
+    volatile int       in_reset;
+    volatile int       poll_enabled;
+    volatile int       exiting;
+    MPT_FRAME_HDR      *config_mf;
+    ConfigReply_t      config_rep;
+    volatile int       io_state[NUM_CMD_BUFFERS];
+    volatile int       els_state[NUM_ELS_BUFFERS];
+    MPT_FRAME_HDR      *current_mf[NUM_CMD_BUFFERS];
+    MPT_FRAME_HDR      *status_deferred_mf[NUM_CMD_BUFFERS];
+    MPT_SGL            sgl;
+       SCSIPortPage0_t SCSIPortPage0;
+       SCSIPortPage1_t SCSIPortPage1;
+       SCSIPortPage2_t SCSIPortPage2;
+#define NUM_SCSI_DEVICES       16
+       SCSIDevicePage1_t SCSIDevicePage1[NUM_SCSI_DEVICES];
+       struct mpt_tgt *tgt;
+       struct scst_cmd *scst_cmd[NUM_CMD_BUFFERS];
+} MPT_STM_PRIV;
+
+#define IO_STATE_POSTED                        0x1
+#define IO_STATE_DATA_SENT             0x2
+#define IO_STATE_STATUS_SENT           0x4
+#define IO_STATE_STATUS_DEFERRED       0x8
+#define IO_STATE_INCOMPLETE            0x10
+#define IO_STATE_AUTO_REPOST           0x20
+#define IO_STATE_ABORTED               0x40
+#define IO_STATE_HIGH_PRIORITY         0x80
+#define IO_STATE_REQUEST_ABORTED       0x100
+#define IO_STATE_REISSUE_REQUEST       0x200
+#define IO_STATE_ADJUST_OFFSET         0x400
+#define IO_STATE_CONVERT_TA_TO_TSS     0x800
+#define IO_STATE_REDO_COMMAND          0x1000
+
+#define get2bytes(x, y) ((x[y] << 8) + x[y+1])
+#define get3bytes(x, y) ((x[y] << 16) + (x[y+1] << 8) + x[y+2])
+#define get4bytes(x, y) ((x[y] << 24) + (x[y+1] << 16) + (x[y+2] << 8) + x[y+3])
+#define get8bytes(x, y) (((u64)get4bytes(x, y) << 32) + get4bytes(x, y+4))
+
+#define InitiatorIndex_0100 Reserved_0100_InitiatorIndex
+#define FWVersion_0101 Reserved_0101_FWVersion
+#define EventDataSasPhyLinkStatus_t MpiEventDataSasPhyLinkStatus_t
+
+#ifndef MPI_FCPORTPAGE1_FLAGS_FORCE_USE_NOSEEPROM_WWNS 
+#define MPI_FCPORTPAGE1_FLAGS_FORCE_USE_NOSEEPROM_WWNS  (0x02000000)
+#endif
+
+#ifndef PRIORITY_REASON_TARGET_BUSY
+#define PRIORITY_REASON_TARGET_BUSY             (0x09)
+#endif
+
+#if MPT_STM_64_BIT_DMA
+#define MPT_STM_SIMPLE SGESimple64_t
+#define MPT_STM_CHAIN SGEChain64_t
+#define MPI_SGE_FLAGS_MPT_STM_ADDRESSING MPI_SGE_FLAGS_64_BIT_ADDRESSING
+#define stm_get_dma_addr(x, y)                \
+    x = le32_to_cpu(y.Low);                   \
+    if (sizeof(dma_addr_t) == sizeof(u64))    \
+        x |= (u64)le32_to_cpu(y.High)<<32;
+#define stm_set_dma_addr(x, y)                \
+    x.Low = cpu_to_le32(y);                   \
+    if (sizeof(dma_addr_t) == sizeof(u64))    \
+        x.High = cpu_to_le32((u64)y>>32);     \
+    else                                      \
+        x.High = 0;
+#else
+#define MPT_STM_SIMPLE SGESimple32_t
+#define MPT_STM_CHAIN SGEChain32_t
+#define MPI_SGE_FLAGS_MPT_STM_ADDRESSING MPI_SGE_FLAGS_32_BIT_ADDRESSING
+#define stm_get_dma_addr(x, y)                \
+    x = le32_to_cpu(y);
+#define stm_set_dma_addr(x, y)                \
+    x = cpu_to_le32(y);
+#endif
+
+#ifndef MPT_MAX_ADAPTERS
+#define MPT_MAX_ADAPTERS 18
+#endif
+
+#ifndef MPI_MANUFACTPAGE_DEVICEID_FC949X
+#define MPI_MANUFACTPAGE_DEVICEID_FC949X 0x640
+#endif
+#ifndef MPI_MANUFACTPAGE_DEVICEID_FC939X
+#define MPI_MANUFACTPAGE_DEVICEID_FC939X 0x642
+#endif
+
+#ifndef MPI_IOCSTATUS_EEDP_GUARD_ERROR
+#define MPI_IOCSTATUS_EEDP_GUARD_ERROR 0x4d
+#endif
+#ifndef MPI_IOCSTATUS_EEDP_REF_TAG_ERROR
+#define MPI_IOCSTATUS_EEDP_REF_TAG_ERROR 0x4e
+#endif
+#ifndef MPI_IOCSTATUS_EEDP_APP_TAG_ERROR
+#define MPI_IOCSTATUS_EEDP_APP_TAG_ERROR 0x4f
+#endif
+
+#define MPT_MAX_CDB_LEN 16
+#define MPT_TIMEOUT 30
+
+/* Immediate notify status constants */
+#define IMM_NTFY_LIP_RESET          MPI_EVENT_LOOP_STATE_CHANGE
+#define IMM_NTFY_IOCB_OVERFLOW      0x0016
+#define IMM_NTFY_ABORT_TASK         0x0020
+#define IMM_NTFY_PORT_LOGOUT        MPI_EVENT_LOGOUT
+#define IMM_NTFY_PORT_CONFIG        MPI_EVENT_LINK_STATUS_CHANGE
+#define IMM_NTFY_GLBL_TPRLO         MPI_EVENT_LINK_STATUS_CHANGE
+#define IMM_NTFY_GLBL_LOGO          MPI_EVENT_LINK_STATUS_CHANGE
+#define IMM_NTFY_RESOURCE           0x0034
+#define IMM_NTFY_MSG_RX             0x0036
+
+/* Immediate notify task flags */
+#define IMM_NTFY_ABORT_TS           0x01
+#define IMM_NTFY_CLEAR_TS           0x04
+#define IMM_NTFY_LUN_RESET1         0x08
+#define IMM_NTFY_LUN_RESET2         0x10
+#define IMM_NTFY_TARGET_RESET       0x20
+#define IMM_NTFY_CLEAR_ACA          0x40
+
+/* Command's states */
+#define MPT_STATE_NEW              1    /* New command and SCST processes it */
+#define MPT_STATE_NEED_DATA        2    /* SCST needs data to process */
+#define MPT_STATE_DATA_IN          3    /* Data arrived and SCST processes it */
+#define MPT_STATE_DATA_OUT                4
+#define MPT_STATE_PROCESSED        5    /* SCST done processing */
+
+/* Target's flags */
+#define MPT_TGT_SHUTDOWN            0   /* The driver is being released */
+#define MPT_TGT_ENABLE_64BIT_ADDR   1   /* 64-bits PCI addressing anables */
+
+/* Session's flags */
+#define MPT_SESS_INITING            0   /* The session is being unregistered */
+#define MPT_SESS_SHUTDOWN           1   /* The session is being unregistered */
+
+struct mpt_cmd 
+{
+       struct mpt_sess *sess;
+       struct scst_cmd *scst_cmd;
+       MPT_STM_PRIV *priv;
+       CMD *CMD;
+       u32 reply_word;
+       struct list_head delayed_cmds_entry;
+       int state;
+       dma_addr_t dma_handle;
+};
+
+struct mpt_sess 
+{
+       struct scst_session *scst_sess;
+       struct mpt_tgt *tgt;
+       int init_index;
+       unsigned long sess_flags;
+       struct list_head delayed_cmds;
+};
+
+struct mpt_tgt
+{
+       struct scst_tgt *scst_tgt;
+       MPT_STM_PRIV *priv;
+       int datasegs_per_cmd, datasegs_per_cont;
+       unsigned long tgt_flags;
+       atomic_t sess_count;
+       wait_queue_head_t waitQ;
+       struct mpt_sess *sess[256];
+       int target_enable;
+       int target_id;
+};
+
+struct mpt_mgmt_cmd
+{
+       struct mpt_sess *sess;
+       int task_mgmt;
+};
+       
+#endif
diff --git a/mpt/scsi3.h b/mpt/scsi3.h
new file mode 100644 (file)
index 0000000..0d9330a
--- /dev/null
@@ -0,0 +1,718 @@
+/*
+ *  linux/drivers/message/fusion/scsi3.h
+ *      SCSI-3 definitions and macros.
+ *      (Ultimately) SCSI-3 definitions; for now, inheriting
+ *      SCSI-2 definitions.
+ *
+ *  Copyright (c) 1996-2004 Steven J. Ralston
+ *  Written By: Steven J. Ralston (19960517)
+ *  (mailto:sjralston1@netscape.net)
+ *  (mailto:mpt_linux_developer@lsil.com)
+ *
+ *  $Id: scst-0.9.5-lsi-2.6.15.patch,v 1.1 2006/12/02 23:40:42 ehabbinga Exp $
+ */
+
+#ifndef SCSI3_H_INCLUDED
+#define SCSI3_H_INCLUDED
+/***************************************************************************/
+
+/****************************************************************************
+ *
+ *  Includes
+ */
+#ifdef __KERNEL__
+#include <linux/types.h>
+#else
+    #ifndef U_STUFF_DEFINED
+    #define U_STUFF_DEFINED
+    typedef unsigned char u8;
+    typedef unsigned short u16;
+    typedef unsigned int u32;
+    #endif
+#endif
+
+/****************************************************************************
+ *
+ *  Defines
+ */
+
+/*
+ *    SCSI Commands
+ */
+#define CMD_TestUnitReady      0x00
+#define CMD_RezeroUnit         0x01  /* direct-access devices */
+#define CMD_Rewind             0x01  /* sequential-access devices */
+#define CMD_RequestSense       0x03
+#define CMD_FormatUnit         0x04
+#define CMD_ReassignBlock      0x07
+#define CMD_Read6              0x08
+#define CMD_Write6             0x0A
+#define CMD_WriteFilemark      0x10
+#define CMD_Space              0x11
+#define CMD_Inquiry            0x12
+#define CMD_ModeSelect6        0x15
+#define CMD_ModeSense6         0x1A
+#define CMD_Reserve6           0x16
+#define CMD_Release6           0x17
+#define CMD_Erase              0x19
+#define CMD_StartStopUnit      0x1B  /* direct-access devices */
+#define CMD_LoadUnload         0x1B  /* sequential-access devices */
+#define CMD_ReceiveDiagnostic  0x1C
+#define CMD_SendDiagnostic     0x1D
+#define CMD_ReadCapacity       0x25
+#define CMD_Read10             0x28
+#define CMD_Write10            0x2A
+#define CMD_WriteVerify        0x2E
+#define CMD_Verify             0x2F
+#define CMD_SynchronizeCache   0x35
+#define CMD_ReadDefectData     0x37
+#define CMD_WriteBuffer        0x3B
+#define CMD_ReadBuffer         0x3C
+#define CMD_ReadLong           0x3E
+#define CMD_WriteLong          0x3F
+#define CMD_WriteSame          0x41
+#define CMD_LogSelect          0x4C
+#define CMD_LogSense           0x4D
+#define CMD_ModeSelect10       0x55
+#define CMD_Reserve10          0x56
+#define CMD_Release10          0x57
+#define CMD_ModeSense10        0x5A
+#define CMD_PersistReserveIn   0x5E
+#define CMD_PersistReserveOut  0x5F
+#define CMD_Read16             0x88
+#define CMD_Write16            0x8A
+#define CMD_WriteVerify16      0x8E
+#define CMD_WriteSame16        0x93
+#define CMD_ServiceActionIn    0x9E
+#define CMD_ServiceActionOut   0x9F
+#define CMD_ReportLuns         0xA0
+#define CMD_Read12             0xA8
+#define CMD_Write12            0xAA
+#define CMD_WriteVerify12      0xAE
+
+/*
+ *    Control byte field
+ */
+#define CONTROL_BYTE_NACA_BIT  0x04
+#define CONTROL_BYTE_Flag_BIT  0x02
+#define CONTROL_BYTE_Link_BIT  0x01
+
+/*
+ *    SCSI Messages
+ */
+#define MSG_COMPLETE             0x00
+#define MSG_EXTENDED             0x01
+#define MSG_SAVE_POINTERS        0x02
+#define MSG_RESTORE_POINTERS     0x03
+#define MSG_DISCONNECT           0x04
+#define MSG_IDERROR              0x05
+#define MSG_ABORT                0x06
+#define MSG_REJECT               0x07
+#define MSG_NOP                  0x08
+#define MSG_PARITY_ERROR         0x09
+#define MSG_LINKED_CMD_COMPLETE  0x0a
+#define MSG_LCMD_COMPLETE_W_FLG  0x0b
+#define MSG_BUS_DEVICE_RESET     0x0c
+#define MSG_ABORT_TAG            0x0d
+#define MSG_CLEAR_QUEUE          0x0e
+#define MSG_INITIATE_RECOVERY    0x0f
+
+#define MSG_RELEASE_RECOVRY      0x10
+#define MSG_TERMINATE_IO         0x11
+
+#define MSG_SIMPLE_QUEUE         0x20
+#define MSG_HEAD_OF_QUEUE        0x21
+#define MSG_ORDERED_QUEUE        0x22
+#define MSG_IGNORE_WIDE_RESIDUE  0x23
+
+#define MSG_IDENTIFY             0x80
+#define MSG_IDENTIFY_W_DISC      0xc0
+
+/*
+ *    SCSI Phases
+ */
+#define PHS_DATA_OUT  0x00
+#define PHS_DATA_IN   0x01
+#define PHS_COMMAND   0x02
+#define PHS_STATUS    0x03
+#define PHS_MSG_OUT   0x06
+#define PHS_MSG_IN    0x07
+
+/*
+ *    Statuses
+ */
+#define STS_GOOD                        0x00
+#define STS_CHECK_CONDITION             0x02
+#define STS_CONDITION_MET               0x04
+#define STS_BUSY                        0x08
+#define STS_INTERMEDIATE                0x10
+#define STS_INTERMEDIATE_CONDITION_MET  0x14
+#define STS_RESERVATION_CONFLICT        0x18
+#define STS_COMMAND_TERMINATED          0x22
+#define STS_TASK_SET_FULL               0x28
+#define    STS_QUEUE_FULL               0x28
+#define STS_ACA_ACTIVE                  0x30
+
+#define STS_VALID_MASK                  0x3e
+
+#define SCSI_STATUS(x)  ((x) & STS_VALID_MASK)
+
+/*
+ *    SCSI QTag Types
+ */
+#define QTAG_SIMPLE     0x20
+#define QTAG_HEAD_OF_Q  0x21
+#define QTAG_ORDERED    0x22
+
+/*
+ *    SCSI Sense Key Definitons
+ */
+#define SK_NO_SENSE         0x00
+#define SK_RECOVERED_ERROR  0x01
+#define SK_NOT_READY        0x02
+#define SK_MEDIUM_ERROR     0x03
+#define SK_HARDWARE_ERROR   0x04
+#define SK_ILLEGAL_REQUEST  0x05
+#define SK_UNIT_ATTENTION   0x06
+#define SK_DATA_PROTECT     0x07
+#define SK_BLANK_CHECK      0x08
+#define SK_VENDOR_SPECIFIC  0x09
+#define SK_COPY_ABORTED     0x0a
+#define SK_ABORTED_COMMAND  0x0b
+#define SK_EQUAL            0x0c
+#define SK_VOLUME_OVERFLOW  0x0d
+#define SK_MISCOMPARE       0x0e
+#define SK_RESERVED         0x0f
+
+
+
+#define SCSI_MAX_INQUIRY_BYTES  96
+#define SCSI_STD_INQUIRY_BYTES  36
+
+#undef USE_SCSI_COMPLETE_INQDATA
+/*
+ *      Structure definition for SCSI Inquiry Data
+ *
+ *  NOTE: The following structure is 96 bytes in size
+ *      iff USE_SCSI_COMPLETE_INQDATA IS defined above (i.e. w/ "#define").
+ *      If USE_SCSI_COMPLETE_INQDATA is NOT defined above (i.e. w/ "#undef")
+ *      then the following structure is only 36 bytes in size.
+ *  THE CHOICE IS YOURS!
+ */
+typedef struct SCSI_Inquiry_Data
+{
+#ifdef USE_SCSI_COMPLETE_INQDATA
+    u8   InqByte[SCSI_MAX_INQUIRY_BYTES];
+#else
+    u8   InqByte[SCSI_STD_INQUIRY_BYTES];
+#endif
+
+/*
+ * the following structure works only for little-endian (Intel,
+ * LSB first (1234) byte order) systems with 4-byte ints.
+ *
+        u32    Periph_Device_Type    : 5,
+               Periph_Qualifier      : 3,
+               Device_Type_Modifier  : 7,
+               Removable_Media       : 1,
+               ANSI_Version          : 3,
+               ECMA_Version          : 3,
+               ISO_Version           : 2,
+               Response_Data_Format  : 4,
+               reserved_0            : 3,
+               AERC                  : 1  ;
+        u32    Additional_Length     : 8,
+               reserved_1            :16,
+               SftReset              : 1,
+               CmdQue                : 1,
+               reserved_2            : 1,
+               Linked                : 1,
+               Sync                  : 1,
+               WBus16                : 1,
+               WBus32                : 1,
+               RelAdr                : 1  ;
+        u8     Vendor_ID[8];
+        u8     Product_ID[16];
+        u8     Revision_Level [4];
+#ifdef USE_SCSI_COMPLETE_INQDATA
+        u8     Vendor_Specific[20];
+        u8     reserved_3[40];
+#endif
+ *
+ */
+
+} SCSI_Inquiry_Data_t;
+
+#define INQ_PERIPHINFO_BYTE            0
+#define   INQ_Periph_Qualifier_MASK      0xe0
+#define   INQ_Periph_Device_Type_MASK    0x1f
+
+#define INQ_Peripheral_Qualifier(inqp) \
+    (int)((*((u8*)(inqp)+INQ_PERIPHINFO_BYTE) & INQ_Periph_Qualifier_MASK) >> 5)
+#define INQ_Peripheral_Device_Type(inqp) \
+    (int)(*((u8*)(inqp)+INQ_PERIPHINFO_BYTE) & INQ_Periph_Device_Type_MASK)
+
+
+#define INQ_DEVTYPEMOD_BYTE            1
+#define   INQ_RMB_BIT                    0x80
+#define   INQ_Device_Type_Modifier_MASK  0x7f
+
+#define INQ_Removable_Medium(inqp) \
+    (int)(*((u8*)(inqp)+INQ_DEVTYPEMOD_BYTE) & INQ_RMB_BIT)
+#define INQ_Device_Type_Modifier(inqp) \
+    (int)(*((u8*)(inqp)+INQ_DEVTYPEMOD_BYTE) & INQ_Device_Type_Modifier_MASK)
+
+
+#define INQ_VERSIONINFO_BYTE           2
+#define   INQ_ISO_Version_MASK           0xc0
+#define   INQ_ECMA_Version_MASK          0x38
+#define   INQ_ANSI_Version_MASK          0x07
+
+#define INQ_ISO_Version(inqp) \
+    (int)(*((u8*)(inqp)+INQ_VERSIONINFO_BYTE) & INQ_ISO_Version_MASK)
+#define INQ_ECMA_Version(inqp) \
+    (int)(*((u8*)(inqp)+INQ_VERSIONINFO_BYTE) & INQ_ECMA_Version_MASK)
+#define INQ_ANSI_Version(inqp) \
+    (int)(*((u8*)(inqp)+INQ_VERSIONINFO_BYTE) & INQ_ANSI_Version_MASK)
+
+
+#define INQ_BYTE3                      3
+#define   INQ_AERC_BIT                   0x80
+#define   INQ_TrmTsk_BIT                 0x40
+#define   INQ_NormACA_BIT                0x20
+#define   INQ_RDF_MASK                   0x0F
+
+#define INQ_AER_Capable(inqp) \
+    (int)(*((u8*)(inqp)+INQ_BYTE3) & INQ_AERC_BIT)
+#define INQ_TrmTsk(inqp) \
+    (int)(*((u8*)(inqp)+INQ_BYTE3) & INQ_TrmTsk_BIT)
+#define INQ_NormACA(inqp) \
+    (int)(*((u8*)(inqp)+INQ_BYTE3) & INQ_NormACA_BIT)
+#define INQ_Response_Data_Format(inqp) \
+    (int)(*((u8*)(inqp)+INQ_BYTE3) & INQ_RDF_MASK)
+
+
+#define INQ_CAPABILITY_BYTE            7
+#define   INQ_RelAdr_BIT                 0x80
+#define   INQ_WBus32_BIT                 0x40
+#define   INQ_WBus16_BIT                 0x20
+#define   INQ_Sync_BIT                   0x10
+#define   INQ_Linked_BIT                 0x08
+  /*      INQ_Reserved BIT               0x40 */
+#define   INQ_CmdQue_BIT                 0x02
+#define   INQ_SftRe_BIT                  0x01
+
+#define IS_RelAdr_DEV(inqp) \
+    (int)(*((u8*)(inqp)+INQ_CAPABILITY_BYTE) & INQ_RelAdr_BIT)
+#define IS_WBus32_DEV(inqp) \
+    (int)(*((u8*)(inqp)+INQ_CAPABILITY_BYTE) & INQ_WBus32_BIT)
+#define IS_WBus16_DEV(inqp) \
+    (int)(*((u8*)(inqp)+INQ_CAPABILITY_BYTE) & INQ_WBus16_BIT)
+#define IS_Sync_DEV(inqp) \
+    (int)(*((u8*)(inqp)+INQ_CAPABILITY_BYTE) & INQ_Sync_BIT)
+#define IS_Linked_DEV(inqp) \
+    (int)(*((u8*)(inqp)+INQ_CAPABILITY_BYTE) & INQ_Linked_BIT)
+#define IS_CmdQue_DEV(inqp) \
+    (int)(*((u8*)(inqp)+INQ_CAPABILITY_BYTE) & INQ_CmdQue_BIT)
+#define IS_SftRe_DEV(inqp) \
+    (int)(*((u8*)(inqp)+INQ_CAPABILITY_BYTE) & INQ_SftRe_BIT)
+
+#define INQ_Width_BITS \
+    (INQ_WBus32_BIT | INQ_WBus16_BIT)
+#define IS_Wide_DEV(inqp) \
+    (int)(*((u8*)(inqp)+INQ_CAPABILITY_BYTE) & INQ_Width_BITS)
+
+
+/*
+ *      SCSI peripheral device types
+ */
+#define SCSI_TYPE_DAD               0x00  /* Direct Access Device */
+#define SCSI_TYPE_SAD               0x01  /* Sequential Access Device */
+#define SCSI_TYPE_TAPE  SCSI_TYPE_SAD
+#define SCSI_TYPE_PRT               0x02  /* Printer */
+#define SCSI_TYPE_PROC              0x03  /* Processor */
+#define SCSI_TYPE_WORM              0x04
+#define SCSI_TYPE_CDROM             0x05
+#define SCSI_TYPE_SCAN              0x06  /* Scanner */
+#define SCSI_TYPE_OPTICAL           0x07  /* Magneto/Optical */
+#define SCSI_TYPE_CHANGER           0x08
+#define SCSI_TYPE_COMM              0x09  /* Communications device */
+#define SCSI_TYPE_UNKNOWN           0x1f
+#define SCSI_TYPE_UNCONFIGURED_LUN  0x7f
+
+#define SCSI_TYPE_MAX_KNOWN         SCSI_TYPE_COMM
+
+/*
+ *      Peripheral Qualifiers
+ */
+#define DEVICE_PRESENT     0x00
+#define LUN_NOT_PRESENT    0x01
+#define LUN_NOT_SUPPORTED  0x03
+
+/*
+ *      ANSI Versions
+ */
+#ifndef SCSI_1
+#define SCSI_1  0x01
+#endif
+#ifndef SCSI_2
+#define SCSI_2  0x02
+#endif
+#ifndef SCSI_3
+#define SCSI_3  0x03
+#endif
+
+
+#define SCSI_MAX_SENSE_BYTES  255
+#define SCSI_STD_SENSE_BYTES   18
+#define SCSI_PAD_SENSE_BYTES      (SCSI_MAX_SENSE_BYTES - SCSI_STD_SENSE_BYTES)
+
+#undef USE_SCSI_COMPLETE_SENSE
+/*
+ *      Structure definition for SCSI Sense Data
+ *
+ *  NOTE: The following structure is 255 bytes in size
+ *      iiff USE_SCSI_COMPLETE_SENSE IS defined above (i.e. w/ "#define").
+ *      If USE_SCSI_COMPLETE_SENSE is NOT defined above (i.e. w/ "#undef")
+ *      then the following structure is only 19 bytes in size.
+ *  THE CHOICE IS YOURS!
+ *
+ */
+typedef struct SCSI_Sense_Data
+{
+#ifdef USE_SCSI_COMPLETE_SENSE
+    u8       SenseByte[SCSI_MAX_SENSE_BYTES];
+#else
+    u8       SenseByte[SCSI_STD_SENSE_BYTES];
+#endif
+
+/*
+ * the following structure works only for little-endian (Intel,
+ * LSB first (1234) byte order) systems with 4-byte ints.
+ *
+    u8     Error_Code                :4,            // 0x00
+           Error_Class               :3,
+           Valid                     :1
+     ;
+    u8     Segment_Number                           // 0x01
+     ;
+    u8     Sense_Key                 :4,            // 0x02
+           Reserved                  :1,
+           Incorrect_Length_Indicator:1,
+           End_Of_Media              :1,
+           Filemark                  :1
+     ;
+    u8     Information_MSB;                         // 0x03
+    u8     Information_Byte2;                       // 0x04
+    u8     Information_Byte1;                       // 0x05
+    u8     Information_LSB;                         // 0x06
+    u8     Additional_Length;                       // 0x07
+
+    u32    Command_Specific_Information;            // 0x08 - 0x0b
+
+    u8     Additional_Sense_Code;                   // 0x0c
+    u8     Additional_Sense_Code_Qualifier;         // 0x0d
+    u8     Field_Replaceable_Unit_Code;             // 0x0e
+    u8     Illegal_Req_Bit_Pointer   :3,            // 0x0f
+           Illegal_Req_Bit_Valid     :1,
+           Illegal_Req_Reserved      :2,
+           Illegal_Req_Cmd_Data      :1,
+           Sense_Key_Specific_Valid  :1
+     ;
+    u16    Sense_Key_Specific_Data;                 // 0x10 - 0x11
+
+#ifdef USE_SCSI_COMPLETE_SENSE
+    u8     Additional_Sense_Data[SCSI_PAD_SENSE_BYTES];
+#else
+    u8     Additional_Sense_Data[1];
+#endif
+ *
+ */
+
+} SCSI_Sense_Data_t;
+
+
+#define SD_ERRCODE_BYTE                0
+#define   SD_Valid_BIT                   0x80
+#define   SD_Error_Code_MASK             0x7f
+#define SD_Valid(sdp) \
+    (int)(*((u8*)(sdp)+SD_ERRCODE_BYTE) & SD_Valid_BIT)
+#define SD_Error_Code(sdp) \
+    (int)(*((u8*)(sdp)+SD_ERRCODE_BYTE) & SD_Error_Code_MASK)
+
+
+#define SD_SEGNUM_BYTE                 1
+#define SD_Segment_Number(sdp)  (int)(*((u8*)(sdp)+SD_SEGNUM_BYTE))
+
+
+#define SD_SENSEKEY_BYTE               2
+#define   SD_Filemark_BIT                0x80
+#define   SD_EOM_BIT                     0x40
+#define   SD_ILI_BIT                     0x20
+#define   SD_Sense_Key_MASK              0x0f
+#define SD_Filemark(sdp) \
+    (int)(*((u8*)(sdp)+SD_SENSEKEY_BYTE) & SD_Filemark_BIT)
+#define SD_EOM(sdp) \
+    (int)(*((u8*)(sdp)+SD_SENSEKEY_BYTE) & SD_EOM_BIT)
+#define SD_ILI(sdp) \
+    (int)(*((u8*)(sdp)+SD_SENSEKEY_BYTE) & SD_ILI_BIT)
+#define SD_Sense_Key(sdp) \
+    (int)(*((u8*)(sdp)+SD_SENSEKEY_BYTE) & SD_Sense_Key_MASK)
+
+
+#define SD_INFO3_BYTE                  3
+#define SD_INFO2_BYTE                  4
+#define SD_INFO1_BYTE                  5
+#define SD_INFO0_BYTE                  6
+#define SD_Information3(sdp)  (int)(*((u8*)(sdp)+SD_INFO3_BYTE))
+#define SD_Information2(sdp)  (int)(*((u8*)(sdp)+SD_INFO2_BYTE))
+#define SD_Information1(sdp)  (int)(*((u8*)(sdp)+SD_INFO1_BYTE))
+#define SD_Information0(sdp)  (int)(*((u8*)(sdp)+SD_INFO0_BYTE))
+
+
+#define SD_ADDL_LEN_BYTE               7
+#define SD_Additional_Sense_Length(sdp) \
+    (int)(*((u8*)(sdp)+SD_ADDL_LEN_BYTE))
+#define SD_Addl_Sense_Len  SD_Additional_Sense_Length
+
+
+#define SD_CMD_SPECIFIC3_BYTE          8
+#define SD_CMD_SPECIFIC2_BYTE          9
+#define SD_CMD_SPECIFIC1_BYTE         10
+#define SD_CMD_SPECIFIC0_BYTE         11
+#define SD_Cmd_Specific_Info3(sdp)  (int)(*((u8*)(sdp)+SD_CMD_SPECIFIC3_BYTE))
+#define SD_Cmd_Specific_Info2(sdp)  (int)(*((u8*)(sdp)+SD_CMD_SPECIFIC2_BYTE))
+#define SD_Cmd_Specific_Info1(sdp)  (int)(*((u8*)(sdp)+SD_CMD_SPECIFIC1_BYTE))
+#define SD_Cmd_Specific_Info0(sdp)  (int)(*((u8*)(sdp)+SD_CMD_SPECIFIC0_BYTE))
+
+
+#define SD_ADDL_SENSE_CODE_BYTE       12
+#define SD_Additional_Sense_Code(sdp) \
+    (int)(*((u8*)(sdp)+SD_ADDL_SENSE_CODE_BYTE))
+#define SD_Addl_Sense_Code  SD_Additional_Sense_Code
+#define SD_ASC  SD_Additional_Sense_Code
+
+
+#define SD_ADDL_SENSE_CODE_QUAL_BYTE  13
+#define SD_Additional_Sense_Code_Qualifier(sdp) \
+    (int)(*((u8*)(sdp)+SD_ADDL_SENSE_CODE_QUAL_BYTE))
+#define SD_Addl_Sense_Code_Qual  SD_Additional_Sense_Code_Qualifier
+#define SD_ASCQ  SD_Additional_Sense_Code_Qualifier
+
+
+#define SD_FIELD_REPL_UNIT_CODE_BYTE  14
+#define SD_Field_Replaceable_Unit_Code(sdp) \
+    (int)(*((u8*)(sdp)+SD_FIELD_REPL_UNIT_CODE_BYTE))
+#define SD_Field_Repl_Unit_Code  SD_Field_Replaceable_Unit_Code
+#define SD_FRUC  SD_Field_Replaceable_Unit_Code
+#define SD_FRU  SD_Field_Replaceable_Unit_Code
+
+
+/*
+ *  Sense-Key Specific offsets and macros.
+ */
+#define SD_SKS2_BYTE                  15
+#define   SD_SKS_Valid_BIT               0x80
+#define   SD_SKS_Cmd_Data_BIT            0x40
+#define   SD_SKS_Bit_Ptr_Valid_BIT       0x08
+#define   SD_SKS_Bit_Ptr_MASK            0x07
+#define SD_SKS1_BYTE                  16
+#define SD_SKS0_BYTE                  17
+#define SD_Sense_Key_Specific_Valid(sdp) \
+    (int)(*((u8*)(sdp)+SD_SKS2_BYTE) & SD_SKS_Valid_BIT)
+#define SD_SKS_Valid  SD_Sense_Key_Specific_Valid
+#define SD_SKS_CDB_Error(sdp)  \
+    (int)(*((u8*)(sdp)+SD_SKS2_BYTE) & SD_SKS_Cmd_Data_BIT)
+#define SD_Was_Illegal_Request  SD_SKS_CDB_Error
+#define SD_SKS_Bit_Pointer_Valid(sdp)  \
+    (int)(*((u8*)(sdp)+SD_SKS2_BYTE) & SD_SKS_Bit_Ptr_Valid_BIT)
+#define SD_SKS_Bit_Pointer(sdp)  \
+    (int)(*((u8*)(sdp)+SD_SKS2_BYTE) & SD_SKS_Bit_Ptr_MASK)
+#define SD_Field_Pointer(sdp)  \
+    (int)( ((u16)(*((u8*)(sdp)+SD_SKS1_BYTE)) << 8) \
+      + *((u8*)(sdp)+SD_SKS0_BYTE) )
+#define SD_Bad_Byte  SD_Field_Pointer
+#define SD_Actual_Retry_Count  SD_Field_Pointer
+#define SD_Progress_Indication  SD_Field_Pointer
+
+/*
+ *  Mode Sense Write Protect Mask
+ */
+#define WRITE_PROTECT_MASK      0X80
+
+/*
+ *  Medium Type Codes
+ */
+#define OPTICAL_DEFAULT                 0x00
+#define OPTICAL_READ_ONLY_MEDIUM        0x01
+#define OPTICAL_WRITE_ONCE_MEDIUM       0x02
+#define OPTICAL_READ_WRITABLE_MEDIUM    0x03
+#define OPTICAL_RO_OR_WO_MEDIUM         0x04
+#define OPTICAL_RO_OR_RW_MEDIUM         0x05
+#define OPTICAL_WO_OR_RW_MEDIUM         0x06
+
+
+
+/*
+ *    Structure definition for READ6, WRITE6 (6-byte CDB)
+ */
+typedef struct SCSI_RW6_CDB
+{
+    u32    OpCode      :8,
+           LBA_HI      :5,    /* 5 MSBit's of the LBA */
+           Lun         :3,
+           LBA_MID     :8,    /* NOTE: total of 21 bits in LBA */
+           LBA_LO      :8  ;  /* Max LBA = 0x001fffff          */
+    u8     BlockCount;
+    u8     Control;
+} SCSI_RW6_t;
+
+#define MAX_RW6_LBA  ((u32)0x001fffff)
+
+/*
+ *  Structure definition for READ10, WRITE10 (10-byte CDB)
+ *
+ *    NOTE: ParityCheck bit is applicable only for VERIFY and WRITE VERIFY for
+ *    the ADP-92 DAC only.  In the SCSI2 spec. this same bit is defined as a
+ *    FUA (forced unit access) bit for READs and WRITEs.  Since this driver
+ *    does not use the FUA, this bit is defined as it is used by the ADP-92.
+ *    Also, for READ CAPACITY, only the OpCode field is used.
+ */
+typedef struct SCSI_RW10_CDB
+{
+    u8     OpCode;
+    u8     Reserved1;
+    u32    LBA;
+    u8     Reserved2;
+    u16    BlockCount;
+    u8     Control;
+} SCSI_RW10_t;
+
+#define PARITY_CHECK  0x08    /* parity check bit - byte[1], bit 3 */
+
+    /*
+     *  Structure definition for data returned by READ CAPACITY cmd;
+     *  READ CAPACITY data
+     */
+    typedef struct READ_CAP_DATA
+    {
+        u32    MaxLBA;
+        u32    BlockBytes;
+    } SCSI_READ_CAP_DATA_t, *pSCSI_READ_CAP_DATA_t;
+
+
+/*
+ *  Structure definition for FORMAT UNIT CDB (6-byte CDB)
+ */
+typedef struct _SCSI_FORMAT_UNIT
+{
+    u8     OpCode;
+    u8     Reserved1;
+    u8     VendorSpecific;
+    u16    Interleave;
+    u8     Control;
+} SCSI_FORMAT_UNIT_t;
+
+/*
+ *    Structure definition for REQUEST SENSE (6-byte CDB)
+ */
+typedef struct _SCSI_REQUEST_SENSE
+{
+    u8     OpCode;
+    u8     Reserved1;
+    u8     Reserved2;
+    u8     Reserved3;
+    u8     AllocLength;
+    u8     Control;
+} SCSI_REQ_SENSE_t;
+
+/*
+ *  Structure definition for REPORT LUNS (12-byte CDB)
+ */
+typedef struct _SCSI_REPORT_LUNS
+{
+    u8     OpCode;
+    u8     Reserved1[5];
+    u32    AllocationLength;
+    u8     Reserved2;
+    u8     Control;
+} SCSI_REPORT_LUNS_t, *pSCSI_REPORT_LUNS_t;
+
+    /*
+     *  (per-level) LUN information bytes
+     */
+/*
+ *  Following doesn't work on ARMCC compiler
+ *  [apparently] because it pads every struct
+ *  to be multiple of 4 bytes!
+ *  So SCSI_LUN_LEVELS_t winds up being 16
+ *  bytes instead of 8!
+ *
+    typedef struct LUN_INFO
+    {
+        u8     AddrMethod_plus_LunOrBusNumber;
+        u8     LunOrTarget;
+    } SCSI_LUN_INFO_t, *pSCSI_LUN_INFO_t;
+
+    typedef struct LUN_LEVELS
+    {
+        SCSI_LUN_INFO_t  LUN_0;
+        SCSI_LUN_INFO_t  LUN_1;
+        SCSI_LUN_INFO_t  LUN_2;
+        SCSI_LUN_INFO_t  LUN_3;
+    } SCSI_LUN_LEVELS_t, *pSCSI_LUN_LEVELS_t;
+*/
+    /*
+     *  All 4 levels (8 bytes) of LUN information
+     */
+    typedef struct LUN_LEVELS
+    {
+        u8     LVL1_AddrMethod_plus_LunOrBusNumber;
+        u8     LVL1_LunOrTarget;
+        u8     LVL2_AddrMethod_plus_LunOrBusNumber;
+        u8     LVL2_LunOrTarget;
+        u8     LVL3_AddrMethod_plus_LunOrBusNumber;
+        u8     LVL3_LunOrTarget;
+        u8     LVL4_AddrMethod_plus_LunOrBusNumber;
+        u8     LVL4_LunOrTarget;
+    } SCSI_LUN_LEVELS_t, *pSCSI_LUN_LEVELS_t;
+
+    /*
+     *  Structure definition for data returned by REPORT LUNS cmd;
+     *  LUN reporting parameter list format
+     */
+    typedef struct LUN_REPORT
+    {
+        u32                LunListLength;
+        u32                Reserved;
+        SCSI_LUN_LEVELS_t  LunInfo[1];
+    } SCSI_LUN_REPORT_t, *pSCSI_LUN_REPORT_t;
+
+/****************************************************************************
+ *
+ *  Externals
+ */
+
+/****************************************************************************
+ *
+ *  Public Typedefs & Related Defines
+ */
+
+/****************************************************************************
+ *
+ *  Macros (embedded, above)
+ */
+
+/****************************************************************************
+ *
+ *  Public Variables
+ */
+
+/****************************************************************************
+ *
+ *  Public Prototypes (module entry points)
+ */
+
+
+/***************************************************************************/
+#endif
diff --git a/scst/kernel/in-tree/Makefile.scsi.Linux-2.6.15.patch b/scst/kernel/in-tree/Makefile.scsi.Linux-2.6.15.patch
new file mode 100644 (file)
index 0000000..7a740f1
--- /dev/null
@@ -0,0 +1,10 @@
+--- Makefile.orig      2006-12-11 14:29:39.000000000 -0700
++++ Makefile   2006-12-11 14:29:52.000000000 -0700
+@@ -81,6 +81,7 @@
+ obj-$(CONFIG_SCSI_QLOGIC_FC)  += qlogicfc.o 
+ obj-$(CONFIG_SCSI_QLOGIC_1280)        += qla1280.o 
+ obj-$(CONFIG_SCSI_QLA2XXX)    += qla2xxx/
++obj-$(CONFIG_SCSI_TARGET)     += scsi_tgt/
+ obj-$(CONFIG_SCSI_LPFC)               += lpfc/
+ obj-$(CONFIG_SCSI_PAS16)      += pas16.o
+ obj-$(CONFIG_SCSI_SEAGATE)    += seagate.o
index 2c30e14..1f0805e 100644 (file)
@@ -49,6 +49,10 @@ all:
 scst:
        $(MAKE) -C $(KDIR) SUBDIRS=$(shell pwd) BUILD_DEV=n
 
+MODS_VERS := $(shell ls Modules.symvers 2>/dev/null)
+# It's renamed in 2.6.18
+MOD_VERS := $(shell ls Module.symvers 2>/dev/null)
+
 install: all
        $(MAKE) -C $(KDIR) SUBDIRS=$(shell pwd) BUILD_DEV=m \
                modules_install
@@ -56,6 +60,14 @@ install: all
        install -m 644 ../include/scsi_tgt.h $(INSTALL_DIR_H)
        install -m 644 ../include/scst_debug.h $(INSTALL_DIR_H)
        install -m 644 ../include/scst_debug.c $(INSTALL_DIR_H)
+ifneq ($(MODS_VERS),)
+       rm -f $(INSTALL_DIR_H)/Module.symvers
+       install -m 644 Modules.symvers $(INSTALL_DIR_H)
+endif
+ifneq ($(MOD_VERS),)
+       rm -f $(INSTALL_DIR_H)/Modules.symvers
+       install -m 644 Module.symvers $(INSTALL_DIR_H)
+endif
        -depmod -a
 
 uninstall: