changeset 9907:98086c85a8f7

PSARC 2008/443 Driver for LSI MPT2.0 compliant SAS controller 6770908 Solaris needs driver for LSI SAS2004/SAS2008 with IT/IR firmware 6846720 memory leak in scsi_hba_bus_config_iports() 6847050 reboot fails after run "stmsboot -d -D mpt_sas" on das_x86 system
author jiang wu - Sun Microsystems - Beijing China <Javen.Wu@Sun.COM>
date Fri, 19 Jun 2009 20:12:07 +0800
parents bfc3790e8ac6
children 4b4177fc63d9
files usr/src/cmd/mdb/Makefile.common usr/src/cmd/mdb/common/modules/mpt_sas/mpt_sas.c usr/src/cmd/mdb/intel/amd64/mpt_sas/Makefile usr/src/cmd/mdb/intel/ia32/mpt_sas/Makefile usr/src/cmd/mdb/sparc/v9/mpt_sas/Makefile usr/src/cmd/stmsboot/stmsboot.sh usr/src/cmd/stmsboot/stmsboot_util.c usr/src/pkgdefs/SUNWmdb/prototype_i386 usr/src/pkgdefs/SUNWmdb/prototype_sparc usr/src/pkgdefs/SUNWmdbr/prototype_i386 usr/src/pkgdefs/SUNWmdbr/prototype_sparc usr/src/pkgdefs/SUNWmptsas/Makefile usr/src/pkgdefs/SUNWmptsas/pkginfo.tmpl usr/src/pkgdefs/SUNWmptsas/postinstall usr/src/pkgdefs/SUNWmptsas/postremove usr/src/pkgdefs/SUNWmptsas/prototype_com usr/src/pkgdefs/SUNWmptsas/prototype_i386 usr/src/pkgdefs/SUNWmptsas/prototype_sparc usr/src/pkgdefs/common_files/i.mptsasconf usr/src/tools/scripts/bfu.sh usr/src/uts/common/Makefile.files usr/src/uts/common/Makefile.rules usr/src/uts/common/io/scsi/adapters/mpt_sas/mpt_sas.conf usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas.c usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas_impl.c usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas_init.c usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas_raid.c usr/src/uts/common/io/scsi/impl/scsi_hba.c usr/src/uts/common/io/warlock/mptsas.wlcmd usr/src/uts/common/sys/scsi/adapters/mpt_sas/mpi/mpi2.h usr/src/uts/common/sys/scsi/adapters/mpt_sas/mpi/mpi2_cnfg.h usr/src/uts/common/sys/scsi/adapters/mpt_sas/mpi/mpi2_init.h usr/src/uts/common/sys/scsi/adapters/mpt_sas/mpi/mpi2_ioc.h usr/src/uts/common/sys/scsi/adapters/mpt_sas/mpi/mpi2_sas.h usr/src/uts/common/sys/scsi/adapters/mpt_sas/mpi/mpi2_type.h usr/src/uts/common/sys/scsi/adapters/mpt_sas/mptsas_ioctl.h usr/src/uts/common/sys/scsi/adapters/mpt_sas/mptsas_var.h usr/src/uts/intel/Makefile.intel.shared usr/src/uts/intel/mpt_sas/Makefile usr/src/uts/sparc/Makefile.sparc.shared usr/src/uts/sparc/mpt_sas/Makefile
diffstat 41 files changed, 26078 insertions(+), 34 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/cmd/mdb/Makefile.common	Fri Jun 19 18:13:27 2009 +0800
+++ b/usr/src/cmd/mdb/Makefile.common	Fri Jun 19 20:12:07 2009 +0800
@@ -72,6 +72,7 @@
 	logindmux \
 	mac \
 	md \
+	mpt_sas \
 	mr_sas \
 	nca \
 	nsctl \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/common/modules/mpt_sas/mpt_sas.c	Fri Jun 19 20:12:07 2009 +0800
@@ -0,0 +1,844 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <limits.h>
+#include <sys/mdb_modapi.h>
+#include <sys/sysinfo.h>
+#include <sys/sunmdi.h>
+#include <sys/scsi/scsi.h>
+
+#pragma pack(1)
+#include <sys/scsi/adapters/mpt_sas/mpi/mpi2_type.h>
+#include <sys/scsi/adapters/mpt_sas/mpi/mpi2.h>
+#include <sys/scsi/adapters/mpt_sas/mpi/mpi2_cnfg.h>
+#include <sys/scsi/adapters/mpt_sas/mpi/mpi2_init.h>
+#include <sys/scsi/adapters/mpt_sas/mpi/mpi2_ioc.h>
+#include <sys/scsi/adapters/mpt_sas/mpi/mpi2_sas.h>
+#pragma pack()
+
+#include <sys/scsi/adapters/mpt_sas/mptsas_var.h>
+
+struct {
+
+	int	value;
+	char	*text;
+} devinfo_array[] = {
+	{ MPI2_SAS_DEVICE_INFO_SEP,		"SEP" },
+	{ MPI2_SAS_DEVICE_INFO_ATAPI_DEVICE,	"ATAPI device" },
+	{ MPI2_SAS_DEVICE_INFO_LSI_DEVICE,	"LSI device" },
+	{ MPI2_SAS_DEVICE_INFO_DIRECT_ATTACH,	"direct attach" },
+	{ MPI2_SAS_DEVICE_INFO_SSP_TARGET,	"SSP tgt" },
+	{ MPI2_SAS_DEVICE_INFO_STP_TARGET,	"STP tgt" },
+	{ MPI2_SAS_DEVICE_INFO_SMP_TARGET,	"SMP tgt" },
+	{ MPI2_SAS_DEVICE_INFO_SATA_DEVICE,	"SATA dev" },
+	{ MPI2_SAS_DEVICE_INFO_SSP_INITIATOR,	"SSP init" },
+	{ MPI2_SAS_DEVICE_INFO_STP_INITIATOR,	"STP init" },
+	{ MPI2_SAS_DEVICE_INFO_SMP_INITIATOR,	"SMP init" },
+	{ MPI2_SAS_DEVICE_INFO_SATA_HOST,	"SATA host" }
+};
+
+static int
+atoi(const char *p)
+{
+	int n;
+	int c = *p++;
+
+	for (n = 0; c >= '0' && c <= '9'; c = *p++) {
+		n *= 10; /* two steps to avoid unnecessary overflow */
+		n += '0' - c; /* accum neg to avoid surprises at MAX */
+	}
+	return (-n);
+}
+
+int
+construct_path(uintptr_t addr, char *result)
+{
+	struct	dev_info	d;
+	char	devi_node[PATH_MAX];
+	char	devi_addr[PATH_MAX];
+
+	if (mdb_vread(&d, sizeof (d), addr) == -1) {
+		mdb_warn("couldn't read dev_info");
+		return (DCMD_ERR);
+	}
+
+	if (d.devi_parent) {
+		construct_path((uintptr_t)d.devi_parent, result);
+		mdb_readstr(devi_node, sizeof (devi_node),
+		    (uintptr_t)d.devi_node_name);
+		mdb_readstr(devi_addr, sizeof (devi_addr),
+		    (uintptr_t)d.devi_addr);
+		mdb_snprintf(result+strlen(result),
+		    PATH_MAX-strlen(result),
+		    "/%s%s%s", devi_node, (*devi_addr ? "@" : ""),
+		    devi_addr);
+	}
+	return (DCMD_OK);
+}
+
+/* ARGSUSED */
+int
+mdi_info_cb(uintptr_t addr, const void *data, void *cbdata)
+{
+	struct	mdi_pathinfo	pi;
+	struct	mdi_client	c;
+	char	dev_path[PATH_MAX];
+	char	string[PATH_MAX];
+	int	mdi_target = 0, mdi_lun = 0;
+	int	target = *(int *)cbdata;
+
+	if (mdb_vread(&pi, sizeof (pi), addr) == -1) {
+		mdb_warn("couldn't read mdi_pathinfo");
+		return (DCMD_ERR);
+	}
+	mdb_readstr(string, sizeof (string), (uintptr_t)pi.pi_addr);
+	mdi_target = atoi(string);
+	mdi_lun = atoi(strchr(string, ',')+1);
+	if (target != mdi_target)
+		return (0);
+
+	if (mdb_vread(&c, sizeof (c), (uintptr_t)pi.pi_client) == -1) {
+		mdb_warn("couldn't read mdi_client");
+		return (-1);
+	}
+
+	*dev_path = NULL;
+	if (construct_path((uintptr_t)c.ct_dip, dev_path) != DCMD_OK)
+		strcpy(dev_path, "unknown");
+
+	mdb_printf("LUN %d: %s\n", mdi_lun, dev_path);
+	mdb_printf("       dip: %p %s path", c.ct_dip,
+	    (pi.pi_preferred ? "preferred" : ""));
+	switch (pi.pi_state & MDI_PATHINFO_STATE_MASK) {
+		case MDI_PATHINFO_STATE_INIT:
+			mdb_printf(" initializing");
+			break;
+		case MDI_PATHINFO_STATE_ONLINE:
+			mdb_printf(" online");
+			break;
+		case MDI_PATHINFO_STATE_STANDBY:
+			mdb_printf(" standby");
+			break;
+		case MDI_PATHINFO_STATE_FAULT:
+			mdb_printf(" fault");
+			break;
+		case MDI_PATHINFO_STATE_OFFLINE:
+			mdb_printf(" offline");
+			break;
+		default:
+			mdb_printf(" invalid state");
+			break;
+	}
+	mdb_printf("\n");
+	return (0);
+}
+
+void
+mdi_info(struct mptsas m, int target)
+{
+	struct	dev_info	d;
+	struct	mdi_phci	p;
+
+	if (mdb_vread(&d, sizeof (d), (uintptr_t)m.m_dip) == -1) {
+		mdb_warn("couldn't read m_dip");
+		return;
+	}
+
+	if (MDI_PHCI(&d)) {
+		if (mdb_vread(&p, sizeof (p), (uintptr_t)d.devi_mdi_xhci)
+		    == -1) {
+			mdb_warn("couldn't read m_dip.devi_mdi_xhci");
+			return;
+		}
+		if (p.ph_path_head)
+			mdb_pwalk("mdipi_phci_list", (mdb_walk_cb_t)mdi_info_cb,
+			    &target, (uintptr_t)p.ph_path_head);
+		return;
+	}
+}
+
+void
+print_cdb(mptsas_cmd_t *m)
+{
+	struct	scsi_pkt	pkt;
+	uchar_t	cdb[512];	/* an arbitrarily large number */
+	int	j;
+
+	if (mdb_vread(&pkt, sizeof (pkt), (uintptr_t)m->cmd_pkt) == -1) {
+		mdb_warn("couldn't read cmd_pkt");
+		return;
+	}
+
+	/*
+	 * We use cmd_cdblen here because 5.10 doesn't
+	 * have the cdb length in the pkt
+	 */
+	if (mdb_vread(&cdb, m->cmd_cdblen, (uintptr_t)pkt.pkt_cdbp) == -1) {
+		mdb_warn("couldn't read pkt_cdbp");
+		return;
+	}
+
+	mdb_printf("%3d,%-3d [ ",
+	    pkt.pkt_address.a_target, pkt.pkt_address.a_lun);
+
+	for (j = 0; j < m->cmd_cdblen; j++)
+		mdb_printf("%02x ", cdb[j]);
+
+	mdb_printf("]\n");
+}
+
+
+void
+display_ports(struct mptsas m)
+{
+	int i;
+	mdb_printf("\n");
+	mdb_printf("phy number and port mapping table\n");
+	for (i = 0; i < MPTSAS_MAX_PHYS; i++) {
+		if (m.m_phy_info[i].attached_devhdl) {
+			mdb_printf("phy %x --> port %x, phymask %x,"
+			"attached_devhdl %x\n", i, m.m_phy_info[i].port_num,
+			    m.m_phy_info[i].phy_mask,
+			    m.m_phy_info[i].attached_devhdl);
+		}
+	}
+	mdb_printf("\n");
+}
+static void *
+hash_traverse(mptsas_hash_table_t *hashtab, int pos, int alloc_size)
+{
+	mptsas_hash_node_t *this = NULL;
+	mptsas_hash_node_t h;
+	void *ret = NULL;
+
+	if (pos == MPTSAS_HASH_FIRST) {
+		hashtab->line = 0;
+		hashtab->cur = NULL;
+		this = hashtab->head[0];
+	} else {
+		if (hashtab->cur == NULL) {
+			return (NULL);
+		} else {
+			mdb_vread(&h, sizeof (h), (uintptr_t)hashtab->cur);
+			this = h.next;
+		}
+	}
+
+	while (this == NULL) {
+		hashtab->line++;
+		if (hashtab->line >= MPTSAS_HASH_ARRAY_SIZE) {
+			/* the traverse reaches the end */
+			hashtab->cur = NULL;
+			return (NULL);
+		} else {
+			this = hashtab->head[hashtab->line];
+		}
+	}
+	hashtab->cur = this;
+
+	if (mdb_vread(&h, sizeof (h), (uintptr_t)this) == -1) {
+		mdb_warn("couldn't read hashtab");
+		return (NULL);
+	}
+	ret = mdb_alloc(alloc_size, UM_SLEEP);
+	if (mdb_vread(ret, alloc_size, (uintptr_t)h.data) == -1) {
+		mdb_warn("couldn't read hashdata");
+		return (NULL);
+	}
+	return (ret);
+}
+void
+display_targets(struct mptsas_slots *s)
+{
+	mptsas_target_t *ptgt;
+	mptsas_smp_t *psmp;
+
+	mdb_printf("\n");
+	mdb_printf("The SCSI target information\n");
+	ptgt = (mptsas_target_t *)hash_traverse(&s->m_tgttbl,
+	    MPTSAS_HASH_FIRST, sizeof (mptsas_target_t));
+	while (ptgt != NULL) {
+		mdb_printf("\n");
+		mdb_printf("devhdl %x, sasaddress %"PRIx64", phymask %x,"
+		    "devinfo %x\n", ptgt->m_devhdl, ptgt->m_sas_wwn,
+		    ptgt->m_phymask, ptgt->m_deviceinfo);
+		mdb_printf("throttle %x, dr_flag %x, m_t_ncmds %x\n",
+		    ptgt->m_t_throttle, ptgt->m_dr_flag, ptgt->m_t_ncmds);
+
+		mdb_free(ptgt, sizeof (mptsas_target_t));
+		ptgt = (mptsas_target_t *)hash_traverse(
+		    &s->m_tgttbl, MPTSAS_HASH_NEXT, sizeof (mptsas_target_t));
+	}
+	mdb_printf("\n");
+	mdb_printf("The smp child information\n");
+	psmp = (mptsas_smp_t *)hash_traverse(&s->m_smptbl,
+	    MPTSAS_HASH_FIRST, sizeof (mptsas_smp_t));
+	while (psmp != NULL) {
+		mdb_printf("\n");
+		mdb_printf("devhdl %x, sasaddress %"PRIx64", phymask %x \n",
+		    psmp->m_devhdl, psmp->m_sasaddr, psmp->m_phymask);
+
+		mdb_free(psmp, sizeof (mptsas_smp_t));
+		psmp = (mptsas_smp_t *)hash_traverse(
+		    &s->m_smptbl, MPTSAS_HASH_NEXT, sizeof (mptsas_smp_t));
+	}
+	mdb_printf("\n");
+#if 0
+	mdb_printf("targ         wwn      ncmds throttle "
+	    "dr_flag  timeout  dups\n");
+	mdb_printf("-------------------------------"
+	    "--------------------------------\n");
+	for (i = 0; i < MPTSAS_MAX_TARGETS; i++) {
+		if (s->m_target[i].m_sas_wwn || s->m_target[i].m_deviceinfo) {
+			mdb_printf("%4d ", i);
+			if (s->m_target[i].m_sas_wwn)
+				mdb_printf("%"PRIx64" ",
+				    s->m_target[i].m_sas_wwn);
+			mdb_printf("%3d", s->m_target[i].m_t_ncmds);
+			switch (s->m_target[i].m_t_throttle) {
+				case QFULL_THROTTLE:
+					mdb_printf("   QFULL ");
+					break;
+				case DRAIN_THROTTLE:
+					mdb_printf("   DRAIN ");
+					break;
+				case HOLD_THROTTLE:
+					mdb_printf("    HOLD ");
+					break;
+				case MAX_THROTTLE:
+					mdb_printf("     MAX ");
+					break;
+				case CHOKE_THROTTLE:
+					mdb_printf("   CHOKE ");
+					break;
+				default:
+					mdb_printf("%8d ",
+					    s->m_target[i].m_t_throttle);
+			}
+			switch (s->m_target[i].m_dr_flag) {
+				case MPTSAS_DR_INACTIVE:
+					mdb_printf("  INACTIVE ");
+					break;
+				case MPTSAS_DR_PRE_OFFLINE_TIMEOUT:
+					mdb_printf("   TIMEOUT ");
+					break;
+				case MPTSAS_DR_PRE_OFFLINE_TIMEOUT_NO_CANCEL:
+					mdb_printf("TIMEOUT_NC ");
+					break;
+				case MPTSAS_DR_OFFLINE_IN_PROGRESS:
+					mdb_printf(" OFFLINING ");
+					break;
+				case MPTSAS_DR_ONLINE_IN_PROGRESS:
+					mdb_printf("  ONLINING ");
+					break;
+				default:
+					mdb_printf("   UNKNOWN ");
+					break;
+				}
+			mdb_printf("%3d/%-3d   %d/%d\n",
+			    s->m_target[i].m_dr_timeout, m.m_offline_delay,
+			    s->m_target[i].m_dr_online_dups,
+			    s->m_target[i].m_dr_offline_dups);
+
+			if (verbose) {
+				mdb_inc_indent(5);
+				if ((s->m_target[i].m_deviceinfo &
+				    MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) ==
+				    MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER)
+					mdb_printf("Fanout expander: ");
+				if ((s->m_target[i].m_deviceinfo &
+				    MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) ==
+				    MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER)
+					mdb_printf("Edge expander: ");
+				if ((s->m_target[i].m_deviceinfo &
+				    MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) ==
+				    MPI2_SAS_DEVICE_INFO_END_DEVICE)
+					mdb_printf("End device: ");
+				if ((s->m_target[i].m_deviceinfo &
+				    MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) ==
+				    MPI2_SAS_DEVICE_INFO_NO_DEVICE)
+					mdb_printf("No device ");
+
+				for (loop = 0, comma = 0;
+				    loop < (sizeof (devinfo_array) /
+				    sizeof (devinfo_array[0])); loop++) {
+					if (s->m_target[i].m_deviceinfo &
+					    devinfo_array[loop].value) {
+						mdb_printf("%s%s",
+						    (comma ? ", " : ""),
+						    devinfo_array[loop].text);
+						comma++;
+					}
+				}
+				mdb_printf("\n");
+
+				if (s->m_target[i].m_tgt_dip) {
+					*target_path = 0;
+					if (construct_path((uintptr_t)
+					    s->m_target[i].m_tgt_dip,
+					    target_path)
+					    == DCMD_OK)
+						mdb_printf("%s\n", target_path);
+				}
+				mdi_info(m, i);
+				mdb_dec_indent(5);
+			}
+		}
+	}
+#endif
+}
+
+int
+display_slotinfo()
+{
+#if 0
+	int	i, nslots;
+	struct	mptsas_cmd		c, *q, *slots;
+	int	header_output = 0;
+	int	rv = DCMD_OK;
+	int	slots_in_use = 0;
+	int	tcmds = 0;
+	int	mismatch = 0;
+	int	wq, dq;
+	int	ncmds = 0;
+	ulong_t	saved_indent;
+
+	nslots = s->m_n_slots;
+
+	slots = mdb_alloc(sizeof (mptsas_cmd_t) * nslots, UM_SLEEP);
+
+	for (i = 0; i < nslots; i++)
+		if (s->m_slot[i]) {
+			slots_in_use++;
+			if (mdb_vread(&slots[i], sizeof (mptsas_cmd_t),
+			    (uintptr_t)s->m_slot[i]) == -1) {
+				mdb_warn("couldn't read slot");
+				s->m_slot[i] = NULL;
+			}
+			if ((slots[i].cmd_flags & CFLAG_CMDIOC) == 0)
+				tcmds++;
+			if (i != slots[i].cmd_slot)
+				mismatch++;
+		}
+
+	for (q = m.m_waitq, wq = 0; q; q = c.cmd_linkp, wq++)
+		if (mdb_vread(&c, sizeof (mptsas_cmd_t), (uintptr_t)q) == -1) {
+			mdb_warn("couldn't follow m_waitq");
+			rv = DCMD_ERR;
+			goto exit;
+		}
+
+	for (q = m.m_doneq, dq = 0; q; q = c.cmd_linkp, dq++)
+		if (mdb_vread(&c, sizeof (mptsas_cmd_t), (uintptr_t)q) == -1) {
+			mdb_warn("couldn't follow m_doneq");
+			rv = DCMD_ERR;
+			goto exit;
+		}
+
+	for (i = 0; i < MPTSAS_MAX_TARGETS; i++)
+		ncmds += s->m_target[i].m_t_ncmds;
+
+	mdb_printf("\n");
+	mdb_printf("   mpt.  slot               mptsas_slots     slot");
+	mdb_printf("\n");
+	mdb_printf("m_ncmds total"
+	    " targ throttle m_t_ncmds targ_tot wq dq");
+	mdb_printf("\n");
+	mdb_printf("----------------------------------------------------");
+	mdb_printf("\n");
+
+	mdb_printf("%7d ", m.m_ncmds);
+	mdb_printf("%s", (m.m_ncmds == slots_in_use ? "  " : "!="));
+	mdb_printf("%3d               total %3d ", slots_in_use, ncmds);
+	mdb_printf("%s", (tcmds == ncmds ? "     " : "   !="));
+	mdb_printf("%3d %2d %2d\n", tcmds, wq, dq);
+
+	saved_indent = mdb_dec_indent(0);
+	mdb_dec_indent(saved_indent);
+
+	for (i = 0; i < s->m_n_slots; i++)
+		if (s->m_slot[i]) {
+			if (!header_output) {
+				mdb_printf("\n");
+				mdb_printf("mptsas_cmd          slot cmd_slot "
+				    "cmd_flags cmd_pkt_flags scsi_pkt      "
+				    "  targ,lun [ pkt_cdbp ...\n");
+				mdb_printf("-------------------------------"
+				    "--------------------------------------"
+				    "--------------------------------------"
+				    "------\n");
+				header_output = 1;
+			}
+			mdb_printf("%16p %4d %s %4d  %8x      %8x %16p ",
+			    s->m_slot[i], i,
+			    (i == slots[i].cmd_slot?"   ":"BAD"),
+			    slots[i].cmd_slot,
+			    slots[i].cmd_flags,
+			    slots[i].cmd_pkt_flags,
+			    slots[i].cmd_pkt);
+			(void) print_cdb(&slots[i]);
+		}
+
+	/* print the wait queue */
+
+	for (q = m.m_waitq; q; q = c.cmd_linkp) {
+		if (q == m.m_waitq)
+			mdb_printf("\n");
+		if (mdb_vread(&c, sizeof (mptsas_cmd_t), (uintptr_t)q)
+		    == -1) {
+			mdb_warn("couldn't follow m_waitq");
+			rv = DCMD_ERR;
+			goto exit;
+		}
+		mdb_printf("%16p wait n/a %4d  %8x      %8x %16p ",
+		    q, c.cmd_slot, c.cmd_flags, c.cmd_pkt_flags,
+		    c.cmd_pkt);
+		print_cdb(&c);
+	}
+
+	/* print the done queue */
+
+	for (q = m.m_doneq; q; q = c.cmd_linkp) {
+		if (q == m.m_doneq)
+			mdb_printf("\n");
+		if (mdb_vread(&c, sizeof (mptsas_cmd_t), (uintptr_t)q)
+		    == -1) {
+			mdb_warn("couldn't follow m_doneq");
+			rv = DCMD_ERR;
+			goto exit;
+		}
+		mdb_printf("%16p done  n/a %4d  %8x      %8x %16p ",
+		    q, c.cmd_slot, c.cmd_flags, c.cmd_pkt_flags,
+		    c.cmd_pkt);
+		print_cdb(&c);
+	}
+
+	mdb_inc_indent(saved_indent);
+
+	if (m.m_ncmds != slots_in_use)
+		mdb_printf("WARNING: mpt.m_ncmds does not match the number of "
+		    "slots in use\n");
+
+	if (tcmds != ncmds)
+		mdb_printf("WARNING: the total of m_target[].m_t_ncmds does "
+		    "not match the slots in use\n");
+
+	if (mismatch)
+		mdb_printf("WARNING: corruption in slot table, "
+		    "m_slot[].cmd_slot incorrect\n");
+
+	/* now check for corruptions */
+
+	for (q = m.m_waitq; q; q = c.cmd_linkp) {
+		for (i = 0; i < nslots; i++)
+			if (s->m_slot[i] == q)
+				mdb_printf("WARNING: m_waitq entry"
+				    "(mptsas_cmd_t) %p is in m_slot[%i]\n",
+				    q, i);
+
+		if (mdb_vread(&c, sizeof (mptsas_cmd_t), (uintptr_t)q) == -1) {
+			mdb_warn("couldn't follow m_waitq");
+			rv = DCMD_ERR;
+			goto exit;
+		}
+	}
+
+	for (q = m.m_doneq; q; q = c.cmd_linkp) {
+		for (i = 0; i < nslots; i++)
+			if (s->m_slot[i] == q)
+				mdb_printf("WARNING: m_doneq entry "
+				"(mptsas_cmd_t) %p is in m_slot[%i]\n", q, i);
+
+		if (mdb_vread(&c, sizeof (mptsas_cmd_t), (uintptr_t)q) == -1) {
+			mdb_warn("couldn't follow m_doneq");
+			rv = DCMD_ERR;
+			goto exit;
+		}
+		if ((c.cmd_flags & CFLAG_FINISHED) == 0)
+			mdb_printf("WARNING: m_doneq entry (mptsas_cmd_t) %p "
+			    "should have CFLAG_FINISHED set\n", q);
+		if (c.cmd_flags & CFLAG_IN_TRANSPORT)
+			mdb_printf("WARNING: m_doneq entry (mptsas_cmd_t) %p "
+			    "should not have CFLAG_IN_TRANSPORT set\n", q);
+		if (c.cmd_flags & CFLAG_CMDARQ)
+			mdb_printf("WARNING: m_doneq entry (mptsas_cmd_t) %p "
+			    "should not have CFLAG_CMDARQ set\n", q);
+		if (c.cmd_flags & CFLAG_COMPLETED)
+			mdb_printf("WARNING: m_doneq entry (mptsas_cmd_t) %p "
+			    "should not have CFLAG_COMPLETED set\n", q);
+	}
+
+exit:
+	mdb_free(slots, sizeof (mptsas_cmd_t) * nslots);
+	return (rv);
+#endif
+	mdb_printf("\n");
+	mdb_printf("The slot information is not implemented yet\n");
+	return (0);
+}
+
+void
+display_deviceinfo(struct mptsas m)
+{
+	char	device_path[PATH_MAX];
+
+	*device_path = 0;
+	if (construct_path((uintptr_t)m.m_dip, device_path) != DCMD_OK) {
+		strcpy(device_path, "couldn't determine device path");
+	}
+
+	mdb_printf("\n");
+	mdb_printf("Path in device tree %s\n", device_path);
+#if 0
+	mdb_printf("base_wwid          phys "
+	    "mptid prodid  devid        revid   ssid\n");
+	mdb_printf("-----------------------------"
+	    "----------------------------------\n");
+	mdb_printf("%"PRIx64"     %2d   %3d "
+	    "0x%04x 0x%04x ", m.un.m_base_wwid, m.m_num_phys, m.m_mptid,
+	    m.m_productid, m.m_devid);
+	switch (m.m_devid) {
+		case MPTSAS_909:
+			mdb_printf("(909)   ");
+			break;
+		case MPTSAS_929:
+			mdb_printf("(929)   ");
+			break;
+		case MPTSAS_919:
+			mdb_printf("(919)   ");
+			break;
+		case MPTSAS_1030:
+			mdb_printf("(1030)  ");
+			break;
+		case MPTSAS_1064:
+			mdb_printf("(1064)  ");
+			break;
+		case MPTSAS_1068:
+			mdb_printf("(1068)  ");
+			break;
+		case MPTSAS_1064E:
+			mdb_printf("(1064E) ");
+			break;
+		case MPTSAS_1068E:
+			mdb_printf("(1068E) ");
+			break;
+		default:
+			mdb_printf("(?????) ");
+			break;
+	}
+	mdb_printf("0x%02x 0x%04x\n", m.m_revid, m.m_ssid);
+	mdb_printf("%s\n", device_path);
+
+	for (i = 0; i < MAX_MPI2_PORTS; i++) {
+		if (i%4 == 0)
+			mdb_printf("\n");
+
+		mdb_printf("%d:", i);
+
+		switch (m.m_port_type[i]) {
+			case MPI2_PORTFACTS_PORTTYPE_INACTIVE:
+				mdb_printf("inactive     ",
+				    m.m_protocol_flags[i]);
+				break;
+			case MPI2_PORTFACTS_PORTTYPE_SCSI:
+				mdb_printf("SCSI (0x%1x)   ",
+				    m.m_protocol_flags[i]);
+				break;
+			case MPI2_PORTFACTS_PORTTYPE_FC:
+				mdb_printf("FC (0x%1x)     ",
+				    m.m_protocol_flags[i]);
+				break;
+			case MPI2_PORTFACTS_PORTTYPE_ISCSI:
+				mdb_printf("iSCSI (0x%1x)  ",
+				    m.m_protocol_flags[i]);
+				break;
+			case MPI2_PORTFACTS_PORTTYPE_SAS:
+				mdb_printf("SAS (0x%1x)    ",
+				    m.m_protocol_flags[i]);
+				break;
+			default:
+				mdb_printf("unknown      ");
+		}
+	}
+#endif
+	mdb_printf("\n");
+}
+
+static int
+mptsas_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
+{
+	struct mptsas		m;
+	struct	mptsas_slots	*s;
+
+	int			nslots;
+	int			slot_size = 0;
+	uint_t			verbose = FALSE;
+	uint_t			target_info = FALSE;
+	uint_t			slot_info = FALSE;
+	uint_t			device_info = FALSE;
+	uint_t			port_info = FALSE;
+	int			rv = DCMD_OK;
+	void			*mptsas_state;
+
+	if (!(flags & DCMD_ADDRSPEC)) {
+		mptsas_state = NULL;
+		if (mdb_readvar(&mptsas_state, "mptsas_state") == -1) {
+			mdb_warn("can't read mptsas_state");
+			return (DCMD_ERR);
+		}
+		if (mdb_pwalk_dcmd("genunix`softstate", "mpt_sas`mptsas", argc,
+		    argv, (uintptr_t)mptsas_state) == -1) {
+			mdb_warn("mdb_pwalk_dcmd failed");
+			return (DCMD_ERR);
+		}
+		return (DCMD_OK);
+	}
+
+	if (mdb_getopts(argc, argv,
+	    's', MDB_OPT_SETBITS, TRUE, &slot_info,
+	    'd', MDB_OPT_SETBITS, TRUE, &device_info,
+	    't', MDB_OPT_SETBITS, TRUE, &target_info,
+	    'p', MDB_OPT_SETBITS, TRUE, &port_info,
+	    'v', MDB_OPT_SETBITS, TRUE, &verbose,
+	    NULL) != argc)
+		return (DCMD_USAGE);
+
+
+	if (mdb_vread(&m, sizeof (m), addr) == -1) {
+		mdb_warn("couldn't read mpt struct at 0x%p", addr);
+		return (DCMD_ERR);
+	}
+
+	s = mdb_alloc(sizeof (mptsas_slots_t), UM_SLEEP);
+
+	if (mdb_vread(s, sizeof (mptsas_slots_t),
+	    (uintptr_t)m.m_active) == -1) {
+		mdb_warn("couldn't read small mptsas_slots_t at 0x%p",
+		    m.m_active);
+		mdb_free(s, sizeof (mptsas_slots_t));
+		return (DCMD_ERR);
+	}
+
+	nslots = s->m_n_slots;
+
+	mdb_free(s, sizeof (mptsas_slots_t));
+
+	slot_size = sizeof (mptsas_slots_t) +
+	    (sizeof (mptsas_cmd_t *) * (nslots-1));
+
+	s = mdb_alloc(slot_size, UM_SLEEP);
+
+	if (mdb_vread(s, slot_size, (uintptr_t)m.m_active) == -1) {
+		mdb_warn("couldn't read large mptsas_slots_t at 0x%p",
+		    m.m_active);
+		mdb_free(s, slot_size);
+		return (DCMD_ERR);
+	}
+
+	/* processing completed */
+
+	if (((flags & DCMD_ADDRSPEC) && !(flags & DCMD_LOOP)) ||
+	    (flags & DCMD_LOOPFIRST) || slot_info || device_info ||
+	    target_info) {
+		if ((flags & DCMD_LOOP) && !(flags & DCMD_LOOPFIRST))
+			mdb_printf("\n");
+		mdb_printf("        mptsas_t inst ncmds suspend  power");
+		mdb_printf("\n");
+		mdb_printf("========================================="
+		    "=======================================");
+		mdb_printf("\n");
+	}
+
+	mdb_printf("%16p %4d %5d ", addr, m.m_instance, m.m_ncmds);
+	mdb_printf("%7d", m.m_suspended);
+	switch (m.m_power_level) {
+		case PM_LEVEL_D0:
+			mdb_printf(" ON=D0 ");
+			break;
+		case PM_LEVEL_D1:
+			mdb_printf("    D1 ");
+			break;
+		case PM_LEVEL_D2:
+			mdb_printf("    D2 ");
+			break;
+		case PM_LEVEL_D3:
+			mdb_printf("OFF=D3 ");
+			break;
+		default:
+			mdb_printf("INVALD ");
+	}
+	mdb_printf("\n");
+
+	mdb_inc_indent(17);
+
+	if (target_info)
+		display_targets(s);
+
+	if (port_info)
+		display_ports(m);
+
+	if (device_info)
+		display_deviceinfo(m);
+
+	if (slot_info)
+		display_slotinfo();
+
+	mdb_dec_indent(17);
+
+	mdb_free(s, slot_size);
+
+	return (rv);
+}
+/*
+ * Only -t is implemented now, will add more later when the driver is stable
+ */
+void
+mptsas_help()
+{
+	mdb_printf("Prints summary information about each mpt_sas instance, "
+	    "including warning\nmessages when slot usage doesn't match "
+	    "summary information.\n"
+	    "Without the address of a \"struct mptsas\", prints every "
+	    "instance.\n\n"
+	    "Switches:\n"
+	    "  -t   includes information about targets\n"
+	    "  -p   includes information about port\n"
+	    "  -d   includes information about the hardware\n");
+}
+
+static const mdb_dcmd_t dcmds[] = {
+	{ "mptsas", "?[-tpd]", "print mpt_sas information", mptsas_dcmd,
+	    mptsas_help}, { NULL }
+};
+
+static const mdb_modinfo_t modinfo = {
+	MDB_API_VERSION, dcmds, NULL
+};
+
+const mdb_modinfo_t *
+_mdb_init(void)
+{
+	return (&modinfo);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/intel/amd64/mpt_sas/Makefile	Fri Jun 19 20:12:07 2009 +0800
@@ -0,0 +1,35 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+
+MODULE = mpt_sas.so
+MDBTGT = kvm
+
+MODSRCS = mpt_sas.c
+
+include ../../../../Makefile.cmd
+include ../../../../Makefile.cmd.64
+include ../../Makefile.amd64
+include ../../../Makefile.module
+
+CPPFLAGS += -I$(SRC)/uts/common
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/intel/ia32/mpt_sas/Makefile	Fri Jun 19 20:12:07 2009 +0800
@@ -0,0 +1,35 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+
+
+MODULE = mpt_sas.so
+MDBTGT = kvm
+
+MODSRCS = mpt_sas.c
+
+include ../../../../Makefile.cmd
+include ../../Makefile.ia32
+include ../../../Makefile.module
+
+CPPFLAGS += -I$(SRC)/uts/common
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/sparc/v9/mpt_sas/Makefile	Fri Jun 19 20:12:07 2009 +0800
@@ -0,0 +1,35 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+
+MODULE = mpt_sas.so
+MDBTGT = kvm
+
+MODSRCS = mpt_sas.c
+
+include ../../../../Makefile.cmd
+include ../../../../Makefile.cmd.64
+include ../../Makefile.sparcv9
+include ../../../Makefile.module
+
+CPPFLAGS += -I$(SRC)/uts/common
--- a/usr/src/cmd/stmsboot/stmsboot.sh	Fri Jun 19 18:13:27 2009 +0800
+++ b/usr/src/cmd/stmsboot/stmsboot.sh	Fri Jun 19 20:12:07 2009 +0800
@@ -39,7 +39,7 @@
 BOOTDEVICES=$SAVEDIR/boot-devices
 RECOVERFILE=$SAVEDIR/recover_instructions
 SVCCFG_RECOVERY=$SAVEDIR/svccfg_recover
-SUPPORTED_DRIVERS="fp|mpt"
+SUPPORTED_DRIVERS="fp|mpt|mpt_sas"
 USAGE=`gettext "Usage: stmsboot [-D $SUPPORTED_DRIVERS] -e | -d | -u | -L | -l controller_number"`
 TEXTDOMAIN=SUNW_OST_OSCMD
 export TEXTDOMAIN
@@ -290,7 +290,7 @@
 # Returns 0 on success, 1 on failure.
 #
 # Args: $cmd = {enable | disable}
-#	$d = {fp | mpt}
+#	$d = {fp | mpt | mpt_sas}
 #
 # the global variable $DRVLIST is used
 #
@@ -417,7 +417,7 @@
 # Emit a warning message to the user that by default we
 # operate on all multipath-capable controllers that are
 # attached to the system, and that if they want to operate
-# on only a specific controller type (fp|mpt|....) then 
+# on only a specific controller type (fp|mpt|mpt_sas|....) then 
 # they need to re-invoke stmsboot with "-D $driver" in
 # their argument list
 #
@@ -437,7 +437,7 @@
 	
 	echo ""
 	gettext "If you do NOT wish to operate on these controllers, please quit stmsboot\n"
-	gettext "and re-invoke with -D { fp | mpt } to specify which controllers you wish\n"
+	gettext "and re-invoke with -D { fp | mpt | mpt_sas} to specify which controllers you wish\n"
 	gettext "to modify your multipathing configuration for.\n"
 
 	echo ""
@@ -480,7 +480,7 @@
 fi
 
 if [ "x$DRV" = "x" ]; then
-	DRVLIST="fp mpt"
+	DRVLIST="fp mpt mpt_sas"
 else
 	DRVLIST=$DRV
 fi
--- a/usr/src/cmd/stmsboot/stmsboot_util.c	Fri Jun 19 18:13:27 2009 +0800
+++ b/usr/src/cmd/stmsboot/stmsboot_util.c	Fri Jun 19 20:12:07 2009 +0800
@@ -141,6 +141,8 @@
 			    devinfo_root));
 			print_mpx_capable(di_drv_first_node("mpt",
 			    devinfo_root));
+			print_mpx_capable(di_drv_first_node("mpt_sas",
+			    devinfo_root));
 		}
 		di_fini(devinfo_root);
 		return (0);
@@ -398,7 +400,8 @@
 			bcopy(optarg, drvlimit, strlen(optarg));
 			/* update this if adding support for a new driver */
 			if ((strncmp(drvlimit, "fp", 2) == NULL) &&
-			    (strncmp(drvlimit, "mpt", 3) == NULL)) {
+			    (strncmp(drvlimit, "mpt", 3) == NULL) &&
+			    (strncmp(drvlimit, "mpt_sas", 7) == NULL)) {
 				logmsg(MSG_ERROR,
 				    gettext("invalid parent driver (%s) "
 				    "specified"), drvlimit);
@@ -1218,6 +1221,25 @@
 	}
 }
 
+static void
+get_phci_driver_name(char *phci_path, char **driver_name)
+{
+	di_node_t phci_node = DI_NODE_NIL;
+	char *tmp = NULL;
+
+	phci_node = di_init(phci_path, DINFOCPYONE);
+	if (phci_node == DI_NODE_NIL) {
+		logmsg(MSG_ERROR,
+		    gettext("Unable to take phci snapshot "
+		    "(%s: %d)\n"), strerror(errno), errno);
+		return;
+	}
+	tmp = di_driver_name(phci_node);
+	if (tmp != NULL) {
+		(void) strncpy(*driver_name, tmp, 10);
+	}
+	di_fini(phci_node);
+}
 /*
  * We only call this routine if we have a scsi_vhci node and must
  * determine the actual physical path of its first online client
@@ -1268,18 +1290,39 @@
 	pi = (sv_path_info_t *)ioc.ret_buf;
 	while (npaths--) {
 		if (pi->ret_state == MDI_PATHINFO_STATE_ONLINE) {
-			char nodename[4];
+			char nodename[5];
+			char *phci_driver = NULL;
 
-			bzero(nodename, 4);
-			/* A hack, but nicer than a platform-specific ifdef */
+			bzero(nodename, 5);
+			phci_driver = malloc(10);
+			if (phci_driver == NULL) {
+				logmsg(MSG_INFO,
+				    "vhci_to_phci: Memory allocation failed\n");
+				goto failure;
+			}
+			bzero(phci_driver, 10);
+			get_phci_driver_name(pi->device.ret_phci,
+			    &phci_driver);
+			logmsg(MSG_INFO, "phci driver name: %s\n", phci_driver);
+			/*
+			 * A hack, but nicer than a platform-specific ifdef
+			 * fp on SPARC using "ssd" as nodename
+			 * mpt use "sd" when mpxio disabled, use "disk" when
+			 * mpxio is enabled
+			 * for alll other cases, "disk" should be used as the
+			 * nodename
+			 */
 			if (strstr(devpath, "ssd") != NULL) {
-				(void) snprintf(nodename, 4, "ssd");
+				(void) snprintf(nodename, 5, "ssd");
+			} else if (strncmp(phci_driver, "mpt", 10) == 0) {
+				(void) snprintf(nodename, 5, "sd");
 			} else {
-				(void) snprintf(nodename, 4, "sd");
+				(void) snprintf(nodename, 5, "disk");
 			}
 			(void) snprintf(physpath, MAXPATHLEN, "%s/%s@%s",
 			    pi->device.ret_phci, nodename, pi->ret_addr);
 			free(ioc.ret_buf);
+			free(phci_driver);
 			return;
 		}
 		pi++;
@@ -1294,7 +1337,7 @@
  * names substituted.
  *
  * Returns:
- * 	0	successful operation
+ *	0	successful operation
  *	-1	failed
  */
 static int
--- a/usr/src/pkgdefs/SUNWmdb/prototype_i386	Fri Jun 19 18:13:27 2009 +0800
+++ b/usr/src/pkgdefs/SUNWmdb/prototype_i386	Fri Jun 19 20:12:07 2009 +0800
@@ -75,6 +75,7 @@
 f none usr/lib/mdb/kvm/amd64/mdb_kb.so 555 root sys
 f none usr/lib/mdb/kvm/amd64/mdb_ks.so 555 root sys
 f none usr/lib/mdb/kvm/amd64/mpt.so 555 root sys
+f none usr/lib/mdb/kvm/amd64/mpt_sas.so 555 root sys
 f none usr/lib/mdb/kvm/amd64/mr_sas.so 555 root sys
 f none usr/lib/mdb/kvm/amd64/nca.so 555 root sys
 f none usr/lib/mdb/kvm/amd64/nfs.so 555 root sys
@@ -109,6 +110,7 @@
 f none usr/lib/mdb/kvm/mdb_kb.so 555 root sys
 f none usr/lib/mdb/kvm/mdb_ks.so 555 root sys
 f none usr/lib/mdb/kvm/mpt.so 555 root sys
+f none usr/lib/mdb/kvm/mpt_sas.so 555 root sys
 f none usr/lib/mdb/kvm/mr_sas.so 555 root sys
 f none usr/lib/mdb/kvm/nca.so 555 root sys
 f none usr/lib/mdb/kvm/nfs.so 555 root sys
--- a/usr/src/pkgdefs/SUNWmdb/prototype_sparc	Fri Jun 19 18:13:27 2009 +0800
+++ b/usr/src/pkgdefs/SUNWmdb/prototype_sparc	Fri Jun 19 20:12:07 2009 +0800
@@ -55,6 +55,7 @@
 f none usr/lib/mdb/kvm/sparcv9/md.so 555 root sys
 f none usr/lib/mdb/kvm/sparcv9/mdb_ks.so 555 root sys
 f none usr/lib/mdb/kvm/sparcv9/mpt.so 555 root sys
+f none usr/lib/mdb/kvm/sparcv9/mpt_sas.so 555 root sys
 f none usr/lib/mdb/kvm/sparcv9/mr_sas.so 555 root sys
 f none usr/lib/mdb/kvm/sparcv9/nca.so 555 root sys
 f none usr/lib/mdb/kvm/sparcv9/nfs.so 555 root sys
--- a/usr/src/pkgdefs/SUNWmdbr/prototype_i386	Fri Jun 19 18:13:27 2009 +0800
+++ b/usr/src/pkgdefs/SUNWmdbr/prototype_i386	Fri Jun 19 20:12:07 2009 +0800
@@ -43,6 +43,7 @@
 f none kernel/kmdb/amd64/md 555 root sys
 f none kernel/kmdb/amd64/mdb_ds 555 root sys
 f none kernel/kmdb/amd64/mpt 555 root sys
+f none kernel/kmdb/amd64/mpt_sas 555 root sys
 f none kernel/kmdb/amd64/mr_sas 555 root sys
 f none kernel/kmdb/amd64/nca 555 root sys
 f none kernel/kmdb/amd64/neti 555 root sys
@@ -76,6 +77,7 @@
 f none kernel/kmdb/md 555 root sys
 f none kernel/kmdb/mdb_ds 555 root sys
 f none kernel/kmdb/mpt 555 root sys
+f none kernel/kmdb/mpt_sas 555 root sys
 f none kernel/kmdb/mr_sas 555 root sys
 f none kernel/kmdb/nca 555 root sys
 f none kernel/kmdb/neti 555 root sys
--- a/usr/src/pkgdefs/SUNWmdbr/prototype_sparc	Fri Jun 19 18:13:27 2009 +0800
+++ b/usr/src/pkgdefs/SUNWmdbr/prototype_sparc	Fri Jun 19 20:12:07 2009 +0800
@@ -43,6 +43,7 @@
 f none kernel/kmdb/sparcv9/md 555 root sys
 f none kernel/kmdb/sparcv9/mdb_ds 555 root sys
 f none kernel/kmdb/sparcv9/mpt 555 root sys
+f none kernel/kmdb/sparcv9/mpt_sas 555 root sys
 f none kernel/kmdb/sparcv9/mr_sas 555 root sys
 f none kernel/kmdb/sparcv9/nca 555 root sys
 f none kernel/kmdb/sparcv9/neti 555 root sys
--- a/usr/src/pkgdefs/SUNWmptsas/Makefile	Fri Jun 19 18:13:27 2009 +0800
+++ b/usr/src/pkgdefs/SUNWmptsas/Makefile	Fri Jun 19 20:12:07 2009 +0800
@@ -18,13 +18,13 @@
 #
 # CDDL HEADER END
 #
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 
 include ../Makefile.com
 
-DATAFILES += depend
+DATAFILES += depend i.mptsasconf
 
 .KEEP_STATE:
 
--- a/usr/src/pkgdefs/SUNWmptsas/pkginfo.tmpl	Fri Jun 19 18:13:27 2009 +0800
+++ b/usr/src/pkgdefs/SUNWmptsas/pkginfo.tmpl	Fri Jun 19 20:12:07 2009 +0800
@@ -18,12 +18,14 @@
 #
 # CDDL HEADER END
 #
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+
+#
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 
 PKG=SUNWmptsas
-NAME=LSI MPT_SAS HBA Driver
+NAME=LSI MPT SAS 2.0 Controller HBA Driver
 ARCH="ISA"
 VERSION="ONVERS,REV=0.0.0"
 SUNW_PRODNAME="SunOS"
@@ -33,8 +35,8 @@
 MAXINST="1000"
 CATEGORY=system
 VENDOR="Sun Microsystems, Inc."
-DESC="LSI MPT_SAS HBA Driver"
-CLASSES="none"
+DESC="LSI MPT SAS 2.0 Controller HBA Driver"
+CLASSES="none mptsasconf"
 HOTLINE="Please contact your local service provider"
 EMAIL=""
 BASEDIR=/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/pkgdefs/SUNWmptsas/postinstall	Fri Jun 19 20:12:07 2009 +0800
@@ -0,0 +1,139 @@
+#!/sbin/sh
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+# Function: check_add_drv()
+#
+# This function will check if the module has an entry in etc/name_to_major
+# If not simply calls add_drv with the arguments given. If there is
+# such an entry in name_to_major file, it adds entries in driver_aliases
+# driver_classes and minor_perm if necessary.
+# The syntax of this function is the same as add_drv. 
+
+if [ "${BASEDIR:=/}" != "/" ]
+then
+        BASEDIR_OPT="-b $BASEDIR"
+fi
+
+check_add_drv()
+{
+	if [ "$BASEDIR" = "" ]
+	then
+		BASEDIR=/  
+	fi
+	alias=""
+	class=""
+	ADD_ALIAS=0
+	ADD_CLASS=0
+	ADD_MINOR=0
+	OPTIND=1
+	IS_NET_DRIVER=0
+
+	cmd="add_drv"
+
+	NO_CMD=
+
+	while getopts i:b:m:c:N  opt
+	do
+		case $opt in
+			N )	NO_CMD=1;;
+			i )	ADD_ALIAS=1	
+				alias=$OPTARG
+				cmd=$cmd" -i '$alias'"
+				;;
+			m )	ADD_MINOR=1
+				minor=$OPTARG
+				cmd=$cmd" -m '$minor'"
+				;;
+			c)	ADD_CLASS=1
+				class=$OPTARG
+				cmd=$cmd" -c $class"
+				;;
+			b)	BASEDIR=$OPTARG
+				cmd=$cmd" -b $BASEDIR"
+				;;
+			\?) 	echo "check_add_drv can not handle this option"
+				return
+				;;
+			esac
+	done 
+	shift `/usr/bin/expr $OPTIND - 1`
+	
+	drvname=$1
+
+	cmd=$cmd" "$drvname
+
+	drvname=`echo $drvname | /usr/bin/sed 's;.*/;;g'`
+
+	/usr/bin/grep "^$drvname[ 	]" $BASEDIR/etc/name_to_major >  /dev/null 2>&1
+
+	if [ "$NO_CMD" = "" -a $? -ne 0 ] 
+	then
+		eval $cmd
+	else	
+		# entry already in name_to_major, add alias, class, minorperm
+		# if necessary
+		if [ $ADD_ALIAS = 1 ]	
+		then
+			for i in $alias
+			do
+				/usr/bin/egrep "^$drvname[ 	]+$i" $BASEDIR/etc/driver_aliases>/dev/null 2>&1
+				if [ $? -ne 0 ]
+				then
+					echo "$drvname $i" >> $BASEDIR/etc/driver_aliases	
+				fi
+			done
+		fi
+
+		if [ $ADD_CLASS = 1 ]
+		then
+			/usr/bin/egrep "^$drvname[ 	]+$class( |	|$)" $BASEDIR/etc/driver_classes > /dev/null 2>&1
+			if [ $? -ne 0 ]
+			then 
+				echo "$drvname\t$class" >> $BASEDIR/etc/driver_classes
+			fi
+		fi
+
+		if [ $ADD_MINOR = 1 ]
+		then
+			/usr/bin/grep "^$drvname:" $BASEDIR/etc/minor_perm > /dev/null 2>&1
+			if [ $? -ne 0 ]
+			then 
+				minorentry="$drvname:$minor"
+				echo $minorentry >> $BASEDIR/etc/minor_perm
+			fi
+		fi
+
+	fi
+
+
+}
+
+# We should all use main PCI ID entries. The 4-tuple entries are used to patch 
+# specific cards, or they will be wrongly matched by other drivers.
+
+check_add_drv -i \
+	'"pci1000,72"
+	"pciex1000,72"' \
+	${BASEDIR_OPT} -c scsi-self-identifying mpt_sas
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/pkgdefs/SUNWmptsas/postremove	Fri Jun 19 20:12:07 2009 +0800
@@ -0,0 +1,49 @@
+#!/bin/sh
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+PATH="/usr/bin:/usr/sbin:${PATH}"
+export PATH
+
+BASEDIR=${BASEDIR:-/}
+
+# Select the correct rem_drv options to execute.
+# Only attempt to unload the driver on a running system
+if [ "$BASEDIR" = "/" ]; then
+	REM_DRV="rem_drv"
+else
+	REM_DRV="rem_drv -b ${BASEDIR}"
+fi
+
+EXIT=0
+
+# Make sure rem_drv has not been previously executed
+# before attempting to remove the driver
+if grep "\<mpt_sas\>" $BASEDIR/etc/name_to_major > /dev/null 2>&1
+then
+	$REM_DRV mpt_sas || EXIT=1
+fi
+exit $EXIT
--- a/usr/src/pkgdefs/SUNWmptsas/prototype_com	Fri Jun 19 18:13:27 2009 +0800
+++ b/usr/src/pkgdefs/SUNWmptsas/prototype_com	Fri Jun 19 20:12:07 2009 +0800
@@ -18,22 +18,35 @@
 #
 # CDDL HEADER END
 #
+
 #
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
+
+
+#
 # This required package information file contains a list of package contents.
 # The 'pkgmk' command uses this file to identify the contents of a package
 # and their location on the development machine when building the package.
 # Can be created via a text editor or through use of the 'pkgproto' command.
 
-#!search <pathname pathname ...>	# where to find pkg objects
-#!include <filename>			# include another 'prototype' file
-#!default <mode> <owner> <group>	# default used if not specified on entry
-#!<param>=<value>			# puts parameter in pkg environment
+#!search <pathname pathname ...>        # where to find pkg objects
+#!include <filename>                    # include another 'prototype' file
+#!default <mode> <owner> <group>        # default used if not specified on entry
+#!<param>=<value>                       # puts parameter in pkg environment
 
 #
 #
+i pkginfo
 i copyright
-i pkginfo
 i depend
+i postinstall
+i postremove
+i i.mptsasconf
+
+d none kernel   0755    root    sys
+d none kernel/drv       0755    root    sys
+e mptsasconf kernel/drv/mpt_sas.conf	0644	root	sys
+
+
--- a/usr/src/pkgdefs/SUNWmptsas/prototype_i386	Fri Jun 19 18:13:27 2009 +0800
+++ b/usr/src/pkgdefs/SUNWmptsas/prototype_i386	Fri Jun 19 20:12:07 2009 +0800
@@ -18,21 +18,31 @@
 #
 # CDDL HEADER END
 #
+
 #
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
+
+#
 # This required package information file contains a list of package contents.
 # The 'pkgmk' command uses this file to identify the contents of a package
 # and their location on the development machine when building the package.
 # Can be created via a text editor or through use of the 'pkgproto' command.
 
-#!search <pathname pathname ...>	# where to find pkg objects
-#!include <filename>			# include another 'prototype' file
-#!default <mode> <owner> <group>	# default used if not specified on entry
-#!<param>=<value>			# puts parameter in pkg environment
+#!search <pathname pathname ...>        # where to find pkg objects
+#!include <filename>                    # include another 'prototype' file
+#!default <mode> <owner> <group>        # default used if not specified on entry
+#!<param>=<value>                       # puts parameter in pkg environment
 
 #
 # Include ISA independent files (prototype_com)
 #
 !include prototype_com
+#
+#
+
+# LSI MPT SAS 2.0 Controller HBA driver 
+d none kernel/drv/amd64	0755	root	sys
+f none kernel/drv/mpt_sas	0755	root	sys
+f none kernel/drv/amd64/mpt_sas	0755	root	sys
--- a/usr/src/pkgdefs/SUNWmptsas/prototype_sparc	Fri Jun 19 18:13:27 2009 +0800
+++ b/usr/src/pkgdefs/SUNWmptsas/prototype_sparc	Fri Jun 19 20:12:07 2009 +0800
@@ -18,21 +18,30 @@
 #
 # CDDL HEADER END
 #
+
 #
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
+
+#
 # This required package information file contains a list of package contents.
 # The 'pkgmk' command uses this file to identify the contents of a package
 # and their location on the development machine when building the package.
 # Can be created via a text editor or through use of the 'pkgproto' command.
 
-#!search <pathname pathname ...>	# where to find pkg objects
-#!include <filename>			# include another 'prototype' file
-#!default <mode> <owner> <group>	# default used if not specified on entry
-#!<param>=<value>			# puts parameter in pkg environment
+#!search <pathname pathname ...>        # where to find pkg objects
+#!include <filename>                    # include another 'prototype' file
+#!default <mode> <owner> <group>        # default used if not specified on entry
+#!<param>=<value>                       # puts parameter in pkg environment
 
 #
 # Include ISA independent files (prototype_com)
 #
 !include prototype_com
+#
+#
+
+# LSI MPT SAS 2.0 Controller HBA driver 
+d none kernel/drv/sparcv9 0755 root sys
+f none kernel/drv/sparcv9/mpt_sas 0755 root sys
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/pkgdefs/common_files/i.mptsasconf	Fri Jun 19 20:12:07 2009 +0800
@@ -0,0 +1,150 @@
+#!/bin/sh
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+PATH=/usr/bin:/usr/sbin:$PATH; export PATH
+PREFIX=/tmp/mptsas.conf.$$
+
+add_comment_for_vhci_class()
+{
+	if grep "^# The mpt_sas driver, as a pHCI driver" $1 > /dev/null 2>&1; then
+		return
+	fi
+
+	cat >> $1 << EOF
+
+#
+# The mpt_sas driver, as a pHCI driver, must specify the vHCI class it
+# belongs to(scsi_vhci).
+#
+EOF
+}
+
+add_comment_for_mpxio_disable()
+{
+
+	if grep "^# Global mpxio-disable property:" $1 > /dev/null 2>&1; then
+		return
+	fi
+
+	cat >> $1 << EOF
+
+#
+# I/O multipathing feature (MPxIO) can be enabled or disabled using
+# mpxio-disable property. Setting mpxio-disable="no" will activate
+# I/O multipathing; setting mpxio-disable="yes" disables the feature.
+#
+# Global mpxio-disable property:
+#
+# To globally enable MPxIO on all LSI MPT SAS 2.0 controllers set:
+# mpxio-disable="no";
+#
+# To globally disable MPxIO on all LSI MPT SAS 2.0 controllers set:
+# mpxio-disable="yes";
+#
+# You can also enable or disable MPxIO on a per HBA basis. 
+# Per HBA settings override the global setting for the specified HBAs.
+# To disable MPxIO on a controller whose parent is /pci@7c0/pci@0/pci@9
+# and the unit-address is "0" set:
+# name="mpt_sas" parent="/pci@7c0/pci@0/pci@9" unit-address="0" mpxio-disable="yes";
+#
+EOF
+}
+
+add_comment_for_tape_property()
+{
+
+	if grep "^# The property tape" $1 > /dev/null 2>&1; then
+		return
+	fi
+
+	cat >> $1 << EOF
+
+#
+# The property tape is only used for X86
+#
+EOF
+}
+
+update_mptsasconf()
+{
+	NEWHDR1=$PREFIX.hdr1
+	NEWHDR2=$PREFIX.hdr2
+	TMPFILE=$PREFIX.tmp
+	
+	# replace old copyright with new one	
+	HEADER="^#.* Copyright.*Sun Microsystems.*$"
+	if grep "$HEADER" $1 > $NEWHDR1 2>/dev/null; then
+		# replace / by \/
+		sed "s/\\//\\\\\\//g" $NEWHDR1 > $NEWHDR2 2>/dev/null
+		if sed "s/$HEADER/`cat $NEWHDR2`/" $2 > $TMPFILE 2>/dev/null
+		then
+			cp $TMPFILE $2
+		fi
+	fi
+
+	if [ "$ARCH" = "i386" ]; then
+		grep 'tape="sctp"' $2 > /dev/null 2>&1
+		if [ $? != 0 ] ; then
+		        add_comment_for_tape_property $2
+			echo 'tape="sctp";' >> $2
+		fi
+	fi
+
+	add_comment_for_vhci_class $2
+
+	# check for property named ddi-vhci-class
+	grep '^ddi-vhci-class' $2 > /dev/null 2>&1
+	if [ $? != 0 ] ; then
+		echo 'ddi-vhci-class="scsi_vhci";' >> $2
+	fi
+
+	add_comment_for_mpxio_disable $2
+	# check for property named mpxio-disable
+
+	grep '^mpxio-disable' $2 > /dev/null 2>&1
+	if [ $? != 0 ] ; then
+		echo 'mpxio-disable="no";' >> $2
+	fi
+
+
+	rm -f $NEWHDR1 $NEWHDR2 $TMPFILE
+}
+
+if read src dest; then
+	if [ ! -f $dest ]; then
+		cp $src $dest
+		if [ "$ARCH" = "i386" ]; then
+			# add property tape for i386 platform
+		        add_comment_for_tape_property $dest
+			echo 'tape="sctp";' >> $dest
+		fi	
+	else
+		# upgrading solaris
+		update_mptsasconf $src $dest
+	fi
+
+fi
+
+exit 0
--- a/usr/src/tools/scripts/bfu.sh	Fri Jun 19 18:13:27 2009 +0800
+++ b/usr/src/tools/scripts/bfu.sh	Fri Jun 19 20:12:07 2009 +0800
@@ -220,6 +220,7 @@
 	kernel/drv/iscsi.conf
 	kernel/drv/md.conf
 	kernel/drv/mpt.conf
+	kernel/drv/mpt_sas.conf
 	kernel/drv/options.conf
 	kernel/drv/qlc.conf
 	kernel/drv/ra.conf
--- a/usr/src/uts/common/Makefile.files	Fri Jun 19 18:13:27 2009 +0800
+++ b/usr/src/uts/common/Makefile.files	Fri Jun 19 20:12:07 2009 +0800
@@ -1730,6 +1730,8 @@
 
 MXFE_OBJS += mxfe.o
 
+MPTSAS_OBJS += mptsas.o mptsas_impl.o mptsas_init.o mptsas_raid.o
+
 SFE_OBJS += sfe.o sfe_util.o
 
 BFE_OBJS += bfe.o
--- a/usr/src/uts/common/Makefile.rules	Fri Jun 19 18:13:27 2009 +0800
+++ b/usr/src/uts/common/Makefile.rules	Fri Jun 19 20:12:07 2009 +0800
@@ -820,6 +820,10 @@
 	$(COMPILE.c) -o $@ $<
 	$(CTFCONVERT_O)
 
+$(OBJS_DIR)/%.o:		$(UTSBASE)/common/io/scsi/adapters/mpt_sas/%.c
+	$(COMPILE.c) -o $@ $<
+	$(CTFCONVERT_O)
+
 $(OBJS_DIR)/%.o:		$(UTSBASE)/common/io/mxfe/%.c
 	$(COMPILE.c) -o $@ $<
 	$(CTFCONVERT_O)
@@ -1974,6 +1978,9 @@
 $(LINTS_DIR)/%.ln:		$(UTSBASE)/common/io/mms/dmd/%.c
 	@($(LHEAD) $(LINT.c) $< $(LTAIL))
 
+$(LINTS_DIR)/%.ln:		$(UTSBASE)/common/io/scsi/adapters/mpt_sas/%.c
+	@($(LHEAD) $(LINT.c) $< $(LTAIL))
+
 $(LINTS_DIR)/%.ln:		$(UTSBASE)/common/io/mxfe/%.c
 	@($(LHEAD) $(LINT.c) $< $(LTAIL))
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/io/scsi/adapters/mpt_sas/mpt_sas.conf	Fri Jun 19 20:12:07 2009 +0800
@@ -0,0 +1,51 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#
+
+#
+# The mpt_sas driver, as a pHCI driver, must specify the vHCI class it
+# belongs to(scsi_vhci).
+#
+ddi-vhci-class="scsi_vhci";
+#
+# I/O multipathing feature (MPxIO) can be enabled or disabled using
+# mpxio-disable property. Setting mpxio-disable="no" will activate
+# I/O multipathing; setting mpxio-disable="yes" disables the feature.
+#
+# Global mpxio-disable property:
+#
+# To globally enable MPxIO on all LSI MPT SAS 2.0 controllers set:
+# mpxio-disable="no";
+#
+# To globally disable MPxIO on all LSI MPT SAS 2.0 controllers set:
+# mpxio-disable="yes";
+#
+# You can also enable or disable MPxIO on a per HBA basis. 
+# Per HBA settings override the global setting for the specified HBAs.
+# To disable MPxIO on a controller whose parent is /pci@7c0/pci@0/pci@9
+# and the unit-address is "0" set:
+# name="mpt_sas" parent="/pci@7c0/pci@0/pci@9" unit-address="0" mpxio-disable="yes";
+#
+mpxio-disable="no";
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas.c	Fri Jun 19 20:12:07 2009 +0800
@@ -0,0 +1,13261 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Copyright (c) 2000 to 2009, LSI Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms of all code within
+ * this file that is exclusively owned by LSI, with or without
+ * modification, is permitted provided that, in addition to the CDDL 1.0
+ * License requirements, the following conditions are met:
+ *
+ *    Neither the name of the author nor the names of its contributors may be
+ *    used to endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ */
+
+/*
+ * mptsas - This is a driver based on LSI Logic's MPT2.0 interface.
+ *
+ */
+
+#if defined(lint) || defined(DEBUG)
+#define	MPTSAS_DEBUG
+#endif
+
+/*
+ * standard header files.
+ */
+#include <sys/note.h>
+#include <sys/scsi/scsi.h>
+#include <sys/pci.h>
+#include <sys/file.h>
+#include <sys/policy.h>
+#include <sys/sysevent.h>
+#include <sys/sysevent/eventdefs.h>
+#include <sys/sysevent/dr.h>
+#include <sys/sata/sata_defs.h>
+
+#pragma pack(1)
+#include <sys/scsi/adapters/mpt_sas/mpi/mpi2_type.h>
+#include <sys/scsi/adapters/mpt_sas/mpi/mpi2.h>
+#include <sys/scsi/adapters/mpt_sas/mpi/mpi2_cnfg.h>
+#include <sys/scsi/adapters/mpt_sas/mpi/mpi2_init.h>
+#include <sys/scsi/adapters/mpt_sas/mpi/mpi2_ioc.h>
+#include <sys/scsi/adapters/mpt_sas/mpi/mpi2_sas.h>
+#pragma pack()
+
+/*
+ * private header files.
+ *
+ */
+#include <sys/scsi/impl/scsi_reset_notify.h>
+#include <sys/scsi/adapters/mpt_sas/mptsas_var.h>
+#include <sys/scsi/adapters/mpt_sas/mptsas_ioctl.h>
+#include <sys/raidioctl.h>
+
+#include <sys/fs/dv_node.h>	/* devfs_clean */
+
+/*
+ * FMA header files
+ */
+#include <sys/ddifm.h>
+#include <sys/fm/protocol.h>
+#include <sys/fm/util.h>
+#include <sys/fm/io/ddi.h>
+
+/*
+ * autoconfiguration data and routines.
+ */
+static int mptsas_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
+static int mptsas_detach(dev_info_t *devi, ddi_detach_cmd_t cmd);
+static int mptsas_power(dev_info_t *dip, int component, int level);
+
+/*
+ * cb_ops function
+ */
+static int mptsas_ioctl(dev_t dev, int cmd, intptr_t data, int mode,
+	cred_t *credp, int *rval);
+#ifndef	__sparc
+static int mptsas_quiesce(dev_info_t *devi);
+#endif	/* __sparc */
+
+/*
+ * Resource initilaization for hardware
+ */
+static void mptsas_setup_cmd_reg(mptsas_t *mpt);
+static void mptsas_disable_bus_master(mptsas_t *mpt);
+static void mptsas_hba_fini(mptsas_t *mpt);
+static void mptsas_cfg_fini(mptsas_t *mptsas_blkp);
+static int mptsas_alloc_request_frames(mptsas_t *mpt);
+static int mptsas_alloc_reply_frames(mptsas_t *mpt);
+static int mptsas_alloc_free_queue(mptsas_t *mpt);
+static int mptsas_alloc_post_queue(mptsas_t *mpt);
+static int mptsas_alloc_extra_sgl_frame(mptsas_t *mpt, mptsas_cmd_t *cmd);
+static void mptsas_free_extra_sgl_frame(mptsas_t *mpt, mptsas_cmd_t *cmd);
+
+/*
+ * SCSA function prototypes
+ */
+static int mptsas_scsi_start(struct scsi_address *ap, struct scsi_pkt *pkt);
+static int mptsas_scsi_reset(struct scsi_address *ap, int level);
+static int mptsas_scsi_abort(struct scsi_address *ap, struct scsi_pkt *pkt);
+static int mptsas_scsi_getcap(struct scsi_address *ap, char *cap, int tgtonly);
+static int mptsas_scsi_setcap(struct scsi_address *ap, char *cap, int value,
+    int tgtonly);
+static void mptsas_scsi_dmafree(struct scsi_address *ap, struct scsi_pkt *pkt);
+static struct scsi_pkt *mptsas_scsi_init_pkt(struct scsi_address *ap,
+    struct scsi_pkt *pkt, struct buf *bp, int cmdlen, int statuslen,
+	int tgtlen, int flags, int (*callback)(), caddr_t arg);
+static void mptsas_scsi_sync_pkt(struct scsi_address *ap, struct scsi_pkt *pkt);
+static void mptsas_scsi_destroy_pkt(struct scsi_address *ap,
+    struct scsi_pkt *pkt);
+static int mptsas_scsi_tgt_init(dev_info_t *hba_dip, dev_info_t *tgt_dip,
+    scsi_hba_tran_t *hba_tran, struct scsi_device *sd);
+static void mptsas_scsi_tgt_free(dev_info_t *hba_dip, dev_info_t *tgt_dip,
+    scsi_hba_tran_t *hba_tran, struct scsi_device *sd);
+static int mptsas_scsi_reset_notify(struct scsi_address *ap, int flag,
+    void (*callback)(caddr_t), caddr_t arg);
+static int mptsas_get_name(struct scsi_device *sd, char *name, int len);
+static int mptsas_get_bus_addr(struct scsi_device *sd, char *name, int len);
+static int mptsas_scsi_quiesce(dev_info_t *dip);
+static int mptsas_scsi_unquiesce(dev_info_t *dip);
+static int mptsas_bus_config(dev_info_t *pdip, uint_t flags,
+    ddi_bus_config_op_t op, void *arg, dev_info_t **childp);
+
+/*
+ * SMP functions
+ */
+static int mptsas_smp_start(struct smp_pkt *smp_pkt);
+static int mptsas_getcap(struct sas_addr *ap, char *cap);
+static int mptsas_capchk(char *cap, int tgtonly, int *cidxp);
+
+/*
+ * internal function prototypes.
+ */
+static int mptsas_quiesce_bus(mptsas_t *mpt);
+static int mptsas_unquiesce_bus(mptsas_t *mpt);
+
+static int mptsas_alloc_handshake_msg(mptsas_t *mpt, size_t alloc_size);
+static void mptsas_free_handshake_msg(mptsas_t *mpt);
+
+static void mptsas_ncmds_checkdrain(void *arg);
+
+static int mptsas_prepare_pkt(mptsas_cmd_t *cmd);
+static int mptsas_accept_pkt(mptsas_t *mpt, mptsas_cmd_t *sp);
+static int mptsas_accept_txwq_and_pkt(mptsas_t *mpt, mptsas_cmd_t *sp);
+static void mptsas_accept_tx_waitq(mptsas_t *mpt);
+
+static int mptsas_do_detach(dev_info_t *dev);
+static int mptsas_do_scsi_reset(mptsas_t *mpt, uint16_t devhdl);
+static int mptsas_do_scsi_abort(mptsas_t *mpt, int target, int lun,
+    struct scsi_pkt *pkt);
+
+static void mptsas_handle_qfull(mptsas_t *mpt, mptsas_cmd_t *cmd);
+static void mptsas_handle_event(void *args);
+static int mptsas_handle_event_sync(void *args);
+static void mptsas_handle_dr(void *args);
+static void mptsas_handle_topo_change(mptsas_topo_change_list_t *topo_node,
+    dev_info_t *pdip);
+
+static void mptsas_restart_cmd(void *);
+
+static void mptsas_flush_hba(mptsas_t *mpt);
+static void mptsas_flush_target(mptsas_t *mpt, ushort_t target, int lun,
+	uint8_t tasktype);
+static void mptsas_set_pkt_reason(mptsas_t *mpt, mptsas_cmd_t *cmd,
+    uchar_t reason, uint_t stat);
+
+static uint_t mptsas_intr(caddr_t arg1, caddr_t arg2);
+static void mptsas_process_intr(mptsas_t *mpt,
+    pMpi2ReplyDescriptorsUnion_t reply_desc_union);
+static void mptsas_handle_scsi_io_success(mptsas_t *mpt,
+    pMpi2ReplyDescriptorsUnion_t reply_desc);
+static void mptsas_handle_address_reply(mptsas_t *mpt,
+    pMpi2ReplyDescriptorsUnion_t reply_desc);
+static int mptsas_wait_intr(mptsas_t *mpt, int polltime);
+static void mptsas_sge_setup(mptsas_t *mpt, mptsas_cmd_t *cmd,
+    uint32_t *control, pMpi2SCSIIORequest_t frame, ddi_acc_handle_t acc_hdl);
+
+static void mptsas_watch(void *arg);
+static void mptsas_watchsubr(mptsas_t *mpt);
+static void mptsas_cmd_timeout(mptsas_t *mpt, uint16_t devhdl);
+
+static void mptsas_start_passthru(mptsas_t *mpt, mptsas_cmd_t *cmd);
+static int mptsas_do_passthru(mptsas_t *mpt, uint8_t *request, uint8_t *reply,
+    uint8_t *data, uint32_t request_size, uint32_t reply_size,
+    uint32_t data_size, uint32_t direction, uint8_t *dataout,
+    uint32_t dataout_size, short timeout, int mode);
+static int mptsas_free_devhdl(mptsas_t *mpt, uint16_t devhdl);
+
+static int mptsas_pkt_alloc_extern(mptsas_t *mpt, mptsas_cmd_t *cmd,
+    int cmdlen, int tgtlen, int statuslen, int kf);
+static void mptsas_pkt_destroy_extern(mptsas_t *mpt, mptsas_cmd_t *cmd);
+
+static int mptsas_kmem_cache_constructor(void *buf, void *cdrarg, int kmflags);
+static void mptsas_kmem_cache_destructor(void *buf, void *cdrarg);
+
+static int mptsas_cache_frames_constructor(void *buf, void *cdrarg,
+    int kmflags);
+static void mptsas_cache_frames_destructor(void *buf, void *cdrarg);
+
+static void mptsas_check_scsi_io_error(mptsas_t *mpt, pMpi2SCSIIOReply_t reply,
+    mptsas_cmd_t *cmd);
+static void mptsas_check_task_mgt(mptsas_t *mpt,
+    pMpi2SCSIManagementReply_t reply, mptsas_cmd_t *cmd);
+static int mptsas_send_scsi_cmd(mptsas_t *mpt, struct scsi_address *ap,
+    mptsas_target_t *ptgt, uchar_t *cdb, int cdblen, struct buf *data_bp,
+    int *resid);
+
+static int mptsas_alloc_active_slots(mptsas_t *mpt, int flag);
+static int mptsas_start_cmd(mptsas_t *mpt, mptsas_cmd_t *cmd);
+
+static void mptsas_restart_hba(mptsas_t *mpt);
+static void mptsas_restart_waitq(mptsas_t *mpt);
+
+static void mptsas_deliver_doneq_thread(mptsas_t *mpt);
+static void mptsas_doneq_add(mptsas_t *mpt, mptsas_cmd_t *cmd);
+static void mptsas_doneq_mv(mptsas_t *mpt, uint64_t t);
+
+static mptsas_cmd_t *mptsas_doneq_thread_rm(mptsas_t *mpt, uint64_t t);
+static void mptsas_doneq_empty(mptsas_t *mpt);
+static void mptsas_doneq_thread(mptsas_doneq_thread_arg_t *arg);
+
+static mptsas_cmd_t *mptsas_waitq_rm(mptsas_t *mpt);
+static void mptsas_waitq_delete(mptsas_t *mpt, mptsas_cmd_t *cmd);
+static mptsas_cmd_t *mptsas_tx_waitq_rm(mptsas_t *mpt);
+static void mptsas_tx_waitq_delete(mptsas_t *mpt, mptsas_cmd_t *cmd);
+
+
+static void mptsas_start_watch_reset_delay();
+static void mptsas_setup_bus_reset_delay(mptsas_t *mpt);
+static void mptsas_watch_reset_delay(void *arg);
+static int mptsas_watch_reset_delay_subr(mptsas_t *mpt);
+
+/*
+ * helper functions
+ */
+static void mptsas_dump_cmd(mptsas_t *mpt, mptsas_cmd_t *cmd);
+
+static dev_info_t *mptsas_find_child(dev_info_t *pdip, char *name);
+static dev_info_t *mptsas_find_child_phy(dev_info_t *pdip, uint8_t phy);
+static dev_info_t *mptsas_find_child_addr(dev_info_t *pdip, uint64_t sasaddr,
+    int lun);
+static mdi_pathinfo_t *mptsas_find_path_addr(dev_info_t *pdip, uint64_t sasaddr,
+    int lun);
+static mdi_pathinfo_t *mptsas_find_path_phy(dev_info_t *pdip, uint8_t phy);
+static dev_info_t *mptsas_find_smp_child(dev_info_t *pdip, char *str_wwn);
+
+static int mptsas_parse_address(char *name, uint64_t *wwid, uint8_t *phy,
+    int *lun);
+static int mptsas_parse_smp_name(char *name, uint64_t *wwn);
+
+static mptsas_target_t *mptsas_phy_to_tgt(dev_info_t *pdip, uint8_t phy);
+static mptsas_target_t *mptsas_wwid_to_ptgt(mptsas_t *mpt, int port,
+    uint64_t wwid);
+static mptsas_smp_t *mptsas_wwid_to_psmp(mptsas_t *mpt, int port,
+    uint64_t wwid);
+
+static int mptsas_inquiry(mptsas_t *mpt, mptsas_target_t *ptgt, int lun,
+    uchar_t page, unsigned char *buf, int len, int *rlen, uchar_t evpd);
+
+static int mptsas_get_target_device_info(mptsas_t *mpt, uint32_t page_address,
+    uint16_t *handle, mptsas_target_t **pptgt);
+static void mptsas_update_phymask(mptsas_t *mpt);
+
+/*
+ * Enumeration / DR functions
+ */
+static void mptsas_config_all(dev_info_t *pdip);
+static int mptsas_config_one_addr(dev_info_t *pdip, uint64_t sasaddr, int lun,
+    dev_info_t **lundip);
+static int mptsas_config_one_phy(dev_info_t *pdip, uint8_t phy, int lun,
+    dev_info_t **lundip);
+
+static int mptsas_config_target(dev_info_t *pdip, mptsas_target_t *ptgt);
+static int mptsas_offline_target(dev_info_t *pdip, char *name);
+
+static int mptsas_config_raid(dev_info_t *pdip, uint16_t target,
+    dev_info_t **dip);
+
+static int mptsas_config_luns(dev_info_t *pdip, mptsas_target_t *ptgt);
+static int mptsas_probe_lun(dev_info_t *pdip, int lun,
+    dev_info_t **dip, mptsas_target_t *ptgt);
+
+static int mptsas_create_lun(dev_info_t *pdip, struct scsi_inquiry *sd_inq,
+    dev_info_t **dip, mptsas_target_t *ptgt, int lun);
+
+static int mptsas_create_phys_lun(dev_info_t *pdip, struct scsi_inquiry *sd,
+    char *guid, dev_info_t **dip, mptsas_target_t *ptgt, int lun);
+static int mptsas_create_virt_lun(dev_info_t *pdip, struct scsi_inquiry *sd,
+    char *guid, dev_info_t **dip, mdi_pathinfo_t **pip, mptsas_target_t *ptgt,
+    int lun);
+
+static void mptsas_offline_missed_luns(dev_info_t *pdip,
+    uint16_t *repluns, int lun_cnt, mptsas_target_t *ptgt);
+static int mptsas_offline_lun(dev_info_t *pdip, dev_info_t *rdip,
+    mdi_pathinfo_t *rpip, uint_t flags);
+
+static int mptsas_config_smp(dev_info_t *pdip, uint64_t sas_wwn,
+    dev_info_t **smp_dip);
+static int mptsas_offline_smp(dev_info_t *pdip, mptsas_smp_t *smp_node,
+    uint_t flags);
+
+static int mptsas_event_query(mptsas_t *mpt, mptsas_event_query_t *data,
+    int mode, int *rval);
+static int mptsas_event_enable(mptsas_t *mpt, mptsas_event_enable_t *data,
+    int mode, int *rval);
+static int mptsas_event_report(mptsas_t *mpt, mptsas_event_report_t *data,
+    int mode, int *rval);
+static void mptsas_record_event(void *args);
+
+static void mptsas_hash_init(mptsas_hash_table_t *hashtab);
+static void mptsas_hash_uninit(mptsas_hash_table_t *hashtab, size_t datalen);
+static void mptsas_hash_add(mptsas_hash_table_t *hashtab, void *data);
+static void * mptsas_hash_rem(mptsas_hash_table_t *hashtab, uint64_t key1,
+    uint8_t key2);
+static void * mptsas_hash_search(mptsas_hash_table_t *hashtab, uint64_t key1,
+    uint8_t key2);
+static void * mptsas_hash_traverse(mptsas_hash_table_t *hashtab, int pos);
+
+mptsas_target_t *mptsas_tgt_alloc(mptsas_hash_table_t *, uint16_t, uint64_t,
+    uint32_t, uint8_t, uint8_t);
+static mptsas_smp_t *mptsas_smp_alloc(mptsas_hash_table_t *hashtab,
+    mptsas_smp_t *data);
+static void mptsas_smp_free(mptsas_hash_table_t *hashtab, uint64_t wwid,
+    uint8_t physport);
+static void mptsas_tgt_free(mptsas_hash_table_t *, uint64_t, uint8_t);
+static void * mptsas_search_by_devhdl(mptsas_hash_table_t *, uint16_t);
+static int mptsas_online_smp(dev_info_t *pdip, mptsas_smp_t *smp_node,
+    dev_info_t **smp_dip);
+
+/*
+ * Power management functions
+ */
+static void mptsas_idle_pm(void *arg);
+static int mptsas_init_pm(mptsas_t *mpt);
+
+/*
+ * MPT MSI tunable:
+ *
+ * By default MSI is enabled on all supported platforms.
+ */
+boolean_t mptsas_enable_msi = B_TRUE;
+
+static int mptsas_add_intrs(mptsas_t *, int);
+static void mptsas_rem_intrs(mptsas_t *);
+
+/*
+ * FMA Prototypes
+ */
+static void mptsas_fm_init(mptsas_t *mpt);
+static void mptsas_fm_fini(mptsas_t *mpt);
+static int mptsas_fm_error_cb(dev_info_t *, ddi_fm_error_t *, const void *);
+
+extern pri_t minclsyspri, maxclsyspri;
+
+/*
+ * This device is created by the SCSI pseudo nexus driver (SCSI vHCI).  It is
+ * under this device that the paths to a physical device are created when
+ * MPxIO is used.
+ */
+extern dev_info_t	*scsi_vhci_dip;
+
+/*
+ * Tunable timeout value for Inquiry VPD page 0x83
+ * By default the value is 30 seconds.
+ */
+int mptsas_inq83_retry_timeout = 30;
+
+/*
+ * This is used to allocate memory for message frame storage, not for
+ * data I/O DMA. All message frames must be stored in the first 4G of
+ * physical memory.
+ */
+ddi_dma_attr_t mptsas_dma_attrs = {
+	DMA_ATTR_V0,	/* attribute layout version		*/
+	0x0ull,		/* address low - should be 0 (longlong)	*/
+	0xffffffffull,	/* address high - 32-bit max range	*/
+	0x00ffffffull,	/* count max - max DMA object size	*/
+	4,		/* allocation alignment requirements	*/
+	0x78,		/* burstsizes - binary encoded values	*/
+	1,		/* minxfer - gran. of DMA engine	*/
+	0x00ffffffull,	/* maxxfer - gran. of DMA engine	*/
+	0xffffffffull,	/* max segment size (DMA boundary)	*/
+	MPTSAS_MAX_DMA_SEGS, /* scatter/gather list length	*/
+	512,		/* granularity - device transfer size	*/
+	0		/* flags, set to 0			*/
+};
+
+/*
+ * This is used for data I/O DMA memory allocation. (full 64-bit DMA
+ * physical addresses are supported.)
+ */
+ddi_dma_attr_t mptsas_dma_attrs64 = {
+	DMA_ATTR_V0,	/* attribute layout version		*/
+	0x0ull,		/* address low - should be 0 (longlong)	*/
+	0xffffffffffffffffull,	/* address high - 64-bit max	*/
+	0x00ffffffull,	/* count max - max DMA object size	*/
+	4,		/* allocation alignment requirements	*/
+	0x78,		/* burstsizes - binary encoded values	*/
+	1,		/* minxfer - gran. of DMA engine	*/
+	0x00ffffffull,	/* maxxfer - gran. of DMA engine	*/
+	0xffffffffull,	/* max segment size (DMA boundary)	*/
+	MPTSAS_MAX_DMA_SEGS, /* scatter/gather list length	*/
+	512,		/* granularity - device transfer size	*/
+	DDI_DMA_RELAXED_ORDERING	/* flags, enable relaxed ordering */
+};
+
+ddi_device_acc_attr_t mptsas_dev_attr = {
+	DDI_DEVICE_ATTR_V0,
+	DDI_STRUCTURE_LE_ACC,
+	DDI_STRICTORDER_ACC
+};
+
+static struct cb_ops mptsas_cb_ops = {
+	scsi_hba_open,		/* open */
+	scsi_hba_close,		/* close */
+	nodev,			/* strategy */
+	nodev,			/* print */
+	nodev,			/* dump */
+	nodev,			/* read */
+	nodev,			/* write */
+	mptsas_ioctl,		/* ioctl */
+	nodev,			/* devmap */
+	nodev,			/* mmap */
+	nodev,			/* segmap */
+	nochpoll,		/* chpoll */
+	ddi_prop_op,		/* cb_prop_op */
+	NULL,			/* streamtab */
+	D_MP,			/* cb_flag */
+	CB_REV,			/* rev */
+	nodev,			/* aread */
+	nodev			/* awrite */
+};
+
+static struct dev_ops mptsas_ops = {
+	DEVO_REV,		/* devo_rev, */
+	0,			/* refcnt  */
+	ddi_no_info,		/* info */
+	nulldev,		/* identify */
+	nulldev,		/* probe */
+	mptsas_attach,		/* attach */
+	mptsas_detach,		/* detach */
+	nodev,			/* reset */
+	&mptsas_cb_ops,		/* driver operations */
+	NULL,			/* bus operations */
+	mptsas_power,		/* power management */
+#ifdef	__sparc
+	ddi_quiesce_not_needed
+#else
+	mptsas_quiesce		/* quiesce */
+#endif	/* __sparc */
+};
+
+
+#define	MPTSAS_MOD_STRING "MPTSAS HBA Driver 00.00.00.16"
+#define	CDATE "MPTSAS was compiled on "__DATE__
+/* LINTED E_STATIC_UNUSED */
+static char *MPTWASCOMPILEDON = CDATE;
+
+static struct modldrv modldrv = {
+	&mod_driverops,	/* Type of module. This one is a driver */
+	MPTSAS_MOD_STRING, /* Name of the module. */
+	&mptsas_ops,	/* driver ops */
+};
+
+static struct modlinkage modlinkage = {
+	MODREV_1, &modldrv, NULL
+};
+#define	TARGET_PROP	"target"
+#define	LUN_PROP	"lun"
+#define	SAS_PROP	"sas-mpt"
+#define	MDI_GUID	"wwn"
+#define	NDI_GUID	"guid"
+#define	MPTSAS_DEV_GONE	"mptsas_dev_gone"
+
+/*
+ * Local static data
+ */
+#if defined(MPTSAS_DEBUG)
+uint32_t mptsas_debug_flags = 0;
+#endif	/* defined(MPTSAS_DEBUG) */
+uint32_t mptsas_debug_resets = 0;
+
+static kmutex_t		mptsas_global_mutex;
+static void		*mptsas_state;		/* soft	state ptr */
+static krwlock_t	mptsas_global_rwlock;
+
+static kmutex_t		mptsas_log_mutex;
+static char		mptsas_log_buf[256];
+_NOTE(MUTEX_PROTECTS_DATA(mptsas_log_mutex, mptsas_log_buf))
+
+static mptsas_t *mptsas_head, *mptsas_tail;
+static clock_t mptsas_scsi_watchdog_tick;
+static clock_t mptsas_tick;
+static timeout_id_t mptsas_reset_watch;
+static timeout_id_t mptsas_timeout_id;
+static int mptsas_timeouts_enabled = 0;
+
+/*
+ * warlock directives
+ */
+_NOTE(SCHEME_PROTECTS_DATA("unique per pkt", scsi_pkt \
+	mptsas_cmd NcrTableIndirect buf scsi_cdb scsi_status))
+_NOTE(SCHEME_PROTECTS_DATA("unique per pkt", smp_pkt))
+_NOTE(SCHEME_PROTECTS_DATA("stable data", scsi_device scsi_address))
+_NOTE(SCHEME_PROTECTS_DATA("No Mutex Needed", mptsas_tgt_private))
+_NOTE(SCHEME_PROTECTS_DATA("No Mutex Needed", scsi_hba_tran::tran_tgt_private))
+
+#ifdef MPTSAS_DEBUG
+void debug_enter(char *);
+#endif
+
+/*
+ * Notes:
+ *	- scsi_hba_init(9F) initializes SCSI HBA modules
+ *	- must call scsi_hba_fini(9F) if modload() fails
+ */
+int
+_init(void)
+{
+	int status;
+	/* CONSTCOND */
+	ASSERT(NO_COMPETING_THREADS);
+
+	NDBG0(("_init"));
+
+	status = ddi_soft_state_init(&mptsas_state, MPTSAS_SIZE,
+	    MPTSAS_INITIAL_SOFT_SPACE);
+	if (status != 0) {
+		return (status);
+	}
+
+	if ((status = scsi_hba_init(&modlinkage)) != 0) {
+		ddi_soft_state_fini(&mptsas_state);
+		return (status);
+	}
+
+	mutex_init(&mptsas_global_mutex, NULL, MUTEX_DRIVER, NULL);
+	rw_init(&mptsas_global_rwlock, NULL, RW_DRIVER, NULL);
+	mutex_init(&mptsas_log_mutex, NULL, MUTEX_DRIVER, NULL);
+
+	if ((status = mod_install(&modlinkage)) != 0) {
+		mutex_destroy(&mptsas_log_mutex);
+		rw_destroy(&mptsas_global_rwlock);
+		mutex_destroy(&mptsas_global_mutex);
+		ddi_soft_state_fini(&mptsas_state);
+		scsi_hba_fini(&modlinkage);
+	}
+
+	return (status);
+}
+
+/*
+ * Notes:
+ *	- scsi_hba_fini(9F) uninitializes SCSI HBA modules
+ */
+int
+_fini(void)
+{
+	int	status;
+	/* CONSTCOND */
+	ASSERT(NO_COMPETING_THREADS);
+
+	NDBG0(("_fini"));
+
+	if ((status = mod_remove(&modlinkage)) == 0) {
+		ddi_soft_state_fini(&mptsas_state);
+		scsi_hba_fini(&modlinkage);
+		mutex_destroy(&mptsas_global_mutex);
+		rw_destroy(&mptsas_global_rwlock);
+		mutex_destroy(&mptsas_log_mutex);
+	}
+	return (status);
+}
+
+/*
+ * The loadable-module _info(9E) entry point
+ */
+int
+_info(struct modinfo *modinfop)
+{
+	/* CONSTCOND */
+	ASSERT(NO_COMPETING_THREADS);
+	NDBG0(("mptsas _info"));
+
+	return (mod_info(&modlinkage, modinfop));
+}
+
+
+static int
+mptsas_iport_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
+{
+	dev_info_t		*pdip;
+	mptsas_t		*mpt;
+	scsi_hba_tran_t		*hba_tran;
+	char			*iport = NULL;
+	char			phymask[8];
+	uint8_t			phy_mask = 0;
+	int			physport = -1;
+	int			dynamic_port = 0;
+	uint32_t		page_address;
+	char			initiator_wwnstr[MPTSAS_WWN_STRLEN];
+	int			rval = DDI_FAILURE;
+	int			i = 0;
+	uint64_t		wwid = 0;
+	uint8_t			portwidth = 0;
+
+	/* CONSTCOND */
+	ASSERT(NO_COMPETING_THREADS);
+
+	switch (cmd) {
+	case DDI_ATTACH:
+		break;
+
+	case DDI_RESUME:
+		/*
+		 * If this a scsi-iport node, nothing to do here.
+		 */
+		return (DDI_SUCCESS);
+
+	default:
+		return (DDI_FAILURE);
+	}
+
+	pdip = ddi_get_parent(dip);
+
+	if ((hba_tran = ndi_flavorv_get(pdip, SCSA_FLAVOR_SCSI_DEVICE)) ==
+	    NULL) {
+		cmn_err(CE_WARN, "Failed attach iport becasue fail to "
+		    "get tran vector for the HBA node");
+		return (DDI_FAILURE);
+	}
+
+	mpt = TRAN2MPT(hba_tran);
+	ASSERT(mpt != NULL);
+	if (mpt == NULL)
+		return (DDI_FAILURE);
+
+	if ((hba_tran = ndi_flavorv_get(dip, SCSA_FLAVOR_SCSI_DEVICE)) ==
+	    NULL) {
+		mptsas_log(mpt, CE_WARN, "Failed attach iport becasue fail to "
+		    "get tran vector for the iport node");
+		return (DDI_FAILURE);
+	}
+
+	/*
+	 * Overwrite parent's tran_hba_private to iport's tran vector
+	 */
+	hba_tran->tran_hba_private = mpt;
+
+	ddi_report_dev(dip);
+
+	/*
+	 * Get SAS address for initiator port according dev_handle
+	 */
+	iport = ddi_get_name_addr(dip);
+	if (iport && strncmp(iport, "v0", 2) == 0) {
+		return (DDI_SUCCESS);
+	}
+
+	mutex_enter(&mpt->m_mutex);
+	for (i = 0; i < MPTSAS_MAX_PHYS; i++) {
+		bzero(phymask, sizeof (phymask));
+		(void) sprintf(phymask, "%x", mpt->m_phy_info[i].phy_mask);
+		if (strcmp(phymask, iport) == 0) {
+			break;
+		}
+	}
+
+	if (i == MPTSAS_MAX_PHYS) {
+		mptsas_log(mpt, CE_WARN, "Failed attach port %s becasue port"
+		    "seems not exist", iport);
+		mutex_exit(&mpt->m_mutex);
+		return (DDI_FAILURE);
+	}
+
+	phy_mask = mpt->m_phy_info[i].phy_mask;
+	physport = mpt->m_phy_info[i].port_num;
+
+	if (mpt->m_phy_info[i].port_flags & AUTO_PORT_CONFIGURATION)
+		dynamic_port = 1;
+	else
+		dynamic_port = 0;
+
+	page_address = (MPI2_SASPORT_PGAD_FORM_PORT_NUM |
+	    (MPI2_SASPORT_PGAD_PORTNUMBER_MASK & physport));
+
+	rval = mptsas_get_sas_port_page0(mpt, page_address, &wwid, &portwidth);
+	if (rval != DDI_SUCCESS) {
+		mptsas_log(mpt, CE_WARN, "Failed attach port %s becasue get"
+		    "SAS address of initiator failed!", iport);
+		mutex_exit(&mpt->m_mutex);
+		return (DDI_FAILURE);
+	}
+	mutex_exit(&mpt->m_mutex);
+
+	bzero(initiator_wwnstr, sizeof (initiator_wwnstr));
+	(void) sprintf(initiator_wwnstr, "%016"PRIx64,
+	    wwid);
+
+	if (ddi_prop_update_string(DDI_DEV_T_NONE, dip,
+	    "initiator-port", initiator_wwnstr) !=
+	    DDI_PROP_SUCCESS) {
+		(void) ddi_prop_remove(DDI_DEV_T_NONE, dip, "initiator-port");
+		return (DDI_FAILURE);
+	}
+
+	if (ddi_prop_update_int(DDI_DEV_T_NONE, dip,
+	    "phymask", phy_mask) !=
+	    DDI_PROP_SUCCESS) {
+		(void) ddi_prop_remove(DDI_DEV_T_NONE, dip, "phymask");
+		return (DDI_FAILURE);
+	}
+
+	if (ddi_prop_update_int(DDI_DEV_T_NONE, dip,
+	    "dynamic-port", dynamic_port) !=
+	    DDI_PROP_SUCCESS) {
+		(void) ddi_prop_remove(DDI_DEV_T_NONE, dip, "dynamic-port");
+		return (DDI_FAILURE);
+	}
+	/*
+	 * register sas hba iport with mdi (MPxIO/vhci)
+	 */
+	if (mdi_phci_register(MDI_HCI_CLASS_SCSI,
+	    dip, 0) == MDI_SUCCESS) {
+		mpt->m_mpxio_enable = TRUE;
+	}
+	return (DDI_SUCCESS);
+}
+
+/*
+ * Notes:
+ *	Set up all device state and allocate data structures,
+ *	mutexes, condition variables, etc. for device operation.
+ *	Add interrupts needed.
+ *	Return DDI_SUCCESS if device is ready, else return DDI_FAILURE.
+ */
+static int
+mptsas_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
+{
+	mptsas_t		*mpt = NULL;
+	int			instance, i, j;
+	int			doneq_thread_num;
+	char			buf[64];
+	char			intr_added = 0;
+	char			map_setup = 0;
+	char			config_setup = 0;
+	char			hba_attach_setup = 0;
+	char			sas_attach_setup = 0;
+	char			mutex_init_done = 0;
+	char			event_taskq_create = 0;
+	char			dr_taskq_create = 0;
+	char			doneq_thread_create = 0;
+	scsi_hba_tran_t		*hba_tran;
+	int			intr_types;
+	uint_t			mem_bar = MEM_SPACE;
+	uint8_t			mask = 0x0;
+	int			tran_flags = 0;
+	int			rval = DDI_FAILURE;
+
+	/* CONSTCOND */
+	ASSERT(NO_COMPETING_THREADS);
+
+	if (scsi_hba_iport_unit_address(dip)) {
+		return (mptsas_iport_attach(dip, cmd));
+	}
+
+	switch (cmd) {
+	case DDI_ATTACH:
+		break;
+
+	case DDI_RESUME:
+		if ((hba_tran = ddi_get_driver_private(dip)) == NULL)
+			return (DDI_FAILURE);
+
+		mpt = TRAN2MPT(hba_tran);
+
+		if (!mpt) {
+			return (DDI_FAILURE);
+		}
+
+		/*
+		 * Reset hardware and softc to "no outstanding commands"
+		 * Note	that a check condition can result on first command
+		 * to a	target.
+		 */
+		mutex_enter(&mpt->m_mutex);
+
+		/*
+		 * raise power.
+		 */
+		if (mpt->m_options & MPTSAS_OPT_PM) {
+			mutex_exit(&mpt->m_mutex);
+			(void) pm_busy_component(dip, 0);
+			if (mpt->m_power_level != PM_LEVEL_D0) {
+				rval = pm_raise_power(dip, 0, PM_LEVEL_D0);
+			} else {
+				rval = pm_power_has_changed(dip, 0,
+				    PM_LEVEL_D0);
+			}
+			if (rval == DDI_SUCCESS) {
+				mutex_enter(&mpt->m_mutex);
+			} else {
+				/*
+				 * The pm_raise_power() call above failed,
+				 * and that can only occur if we were unable
+				 * to reset the hardware.  This is probably
+				 * due to unhealty hardware, and because
+				 * important filesystems(such as the root
+				 * filesystem) could be on the attached disks,
+				 * it would not be a good idea to continue,
+				 * as we won't be entirely certain we are
+				 * writing correct data.  So we panic() here
+				 * to not only prevent possible data corruption,
+				 * but to give developers or end users a hope
+				 * of identifying and correcting any problems.
+				 */
+				fm_panic("mptsas could not reset hardware "
+				    "during resume");
+			}
+		}
+
+		mpt->m_suspended = 0;
+
+		/*
+		 * Reinitialize ioc
+		 */
+		if (mptsas_init_chip(mpt, FALSE) == DDI_FAILURE) {
+			mutex_exit(&mpt->m_mutex);
+			if (mpt->m_options & MPTSAS_OPT_PM) {
+				(void) pm_idle_component(dip, 0);
+			}
+			fm_panic("mptsas init chip fail during resume");
+		}
+		/*
+		 * mptsas_update_driver_data needs interrupts so enable them
+		 * first.
+		 */
+		MPTSAS_ENABLE_INTR(mpt);
+		mptsas_update_driver_data(mpt);
+
+		/* start requests, if possible */
+		mptsas_restart_hba(mpt);
+
+		mutex_exit(&mpt->m_mutex);
+
+		/*
+		 * Restart watch thread
+		 */
+		mutex_enter(&mptsas_global_mutex);
+		if (mptsas_timeout_id == 0) {
+			mptsas_timeout_id = timeout(mptsas_watch, NULL,
+			    mptsas_tick);
+			mptsas_timeouts_enabled = 1;
+		}
+		mutex_exit(&mptsas_global_mutex);
+
+		/* report idle status to pm framework */
+		if (mpt->m_options & MPTSAS_OPT_PM) {
+			(void) pm_idle_component(dip, 0);
+		}
+
+		return (DDI_SUCCESS);
+
+	default:
+		return (DDI_FAILURE);
+
+	}
+
+	instance = ddi_get_instance(dip);
+
+	/*
+	 * Allocate softc information.
+	 */
+	if (ddi_soft_state_zalloc(mptsas_state, instance) != DDI_SUCCESS) {
+		mptsas_log(NULL, CE_WARN,
+		    "mptsas%d: cannot allocate soft state", instance);
+		goto fail;
+	}
+
+	mpt = ddi_get_soft_state(mptsas_state, instance);
+
+	if (mpt == NULL) {
+		mptsas_log(NULL, CE_WARN,
+		    "mptsas%d: cannot get soft state", instance);
+		goto fail;
+	}
+
+	/* Allocate a transport structure */
+	hba_tran = mpt->m_tran = scsi_hba_tran_alloc(dip, SCSI_HBA_CANSLEEP);
+	ASSERT(mpt->m_tran != NULL);
+
+	/* Indicate that we are 'sizeof (scsi_*(9S))' clean. */
+	scsi_size_clean(dip);
+
+	mpt->m_dip = dip;
+	mpt->m_instance = instance;
+
+	/* Make a per-instance copy of the structures */
+	mpt->m_io_dma_attr = mptsas_dma_attrs64;
+	mpt->m_msg_dma_attr = mptsas_dma_attrs;
+	mpt->m_dev_acc_attr = mptsas_dev_attr;
+
+	/*
+	 * Initialize FMA
+	 */
+	mpt->m_fm_capabilities = ddi_getprop(DDI_DEV_T_ANY, mpt->m_dip,
+	    DDI_PROP_CANSLEEP | DDI_PROP_DONTPASS, "fm-capable",
+	    DDI_FM_EREPORT_CAPABLE | DDI_FM_ACCCHK_CAPABLE |
+	    DDI_FM_DMACHK_CAPABLE | DDI_FM_ERRCB_CAPABLE);
+
+	mptsas_fm_init(mpt);
+
+	if (pci_config_setup(mpt->m_dip,
+	    &mpt->m_config_handle) != DDI_SUCCESS) {
+		mptsas_log(mpt, CE_WARN, "cannot map configuration space.");
+		goto fail;
+	}
+	config_setup++;
+
+	if (mptsas_alloc_handshake_msg(mpt,
+	    sizeof (Mpi2SCSITaskManagementRequest_t)) == DDI_FAILURE) {
+		mptsas_log(mpt, CE_WARN, "cannot initialize handshake msg.");
+		goto fail;
+	}
+
+	/*
+	 * This is a workaround for a XMITS ASIC bug which does not
+	 * drive the CBE upper bits.
+	 */
+	if (pci_config_get16(mpt->m_config_handle, PCI_CONF_STAT) &
+	    PCI_STAT_PERROR) {
+		pci_config_put16(mpt->m_config_handle, PCI_CONF_STAT,
+		    PCI_STAT_PERROR);
+	}
+
+	/*
+	 * Setup configuration space
+	 */
+	if (mptsas_config_space_init(mpt) == FALSE) {
+		mptsas_log(mpt, CE_WARN, "mptsas_config_space_init failed");
+		goto fail;
+	}
+
+	if (ddi_regs_map_setup(dip, mem_bar, (caddr_t *)&mpt->m_reg,
+	    0, 0, &mpt->m_dev_acc_attr, &mpt->m_datap) != DDI_SUCCESS) {
+		mptsas_log(mpt, CE_WARN, "map setup failed");
+		goto fail;
+	}
+	map_setup++;
+
+	/*
+	 * A taskq is created for dealing with the event handler
+	 */
+	if ((mpt->m_event_taskq = ddi_taskq_create(dip, "mptsas_event_taskq",
+	    1, TASKQ_DEFAULTPRI, 0)) == NULL) {
+		mptsas_log(mpt, CE_NOTE, "ddi_taskq_create failed");
+		goto fail;
+	}
+	event_taskq_create++;
+
+	/*
+	 * A taskq is created for dealing with dr events
+	 */
+	if ((mpt->m_dr_taskq = ddi_taskq_create(dip,
+	    "mptsas_dr_taskq",
+	    1, TASKQ_DEFAULTPRI, 0)) == NULL) {
+		mptsas_log(mpt, CE_NOTE, "ddi_taskq_create for discovery "
+		    "failed");
+		goto fail;
+	}
+	dr_taskq_create++;
+
+	mpt->m_doneq_thread_threshold = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
+	    0, "mptsas_doneq_thread_threshold_prop", 10);
+	mpt->m_doneq_length_threshold = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
+	    0, "mptsas_doneq_length_threshold_prop", 8);
+	mpt->m_doneq_thread_n = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
+	    0, "mptsas_doneq_thread_n_prop", 8);
+
+	if (mpt->m_doneq_thread_n) {
+		cv_init(&mpt->m_doneq_thread_cv, NULL, CV_DRIVER, NULL);
+		mutex_init(&mpt->m_doneq_mutex, NULL, MUTEX_DRIVER, NULL);
+
+		mutex_enter(&mpt->m_doneq_mutex);
+		mpt->m_doneq_thread_id =
+		    kmem_zalloc(sizeof (mptsas_doneq_thread_list_t)
+		    * mpt->m_doneq_thread_n, KM_SLEEP);
+
+		for (j = 0; j < mpt->m_doneq_thread_n; j++) {
+			cv_init(&mpt->m_doneq_thread_id[j].cv, NULL,
+			    CV_DRIVER, NULL);
+			mutex_init(&mpt->m_doneq_thread_id[j].mutex, NULL,
+			    MUTEX_DRIVER, NULL);
+			mutex_enter(&mpt->m_doneq_thread_id[j].mutex);
+			mpt->m_doneq_thread_id[j].flag |=
+			    MPTSAS_DONEQ_THREAD_ACTIVE;
+			mpt->m_doneq_thread_id[j].arg.mpt = mpt;
+			mpt->m_doneq_thread_id[j].arg.t = j;
+			mpt->m_doneq_thread_id[j].threadp =
+			    thread_create(NULL, 0, mptsas_doneq_thread,
+			    &mpt->m_doneq_thread_id[j].arg,
+			    0, &p0, TS_RUN, minclsyspri);
+			mpt->m_doneq_thread_id[j].donetail =
+			    &mpt->m_doneq_thread_id[j].doneq;
+			mutex_exit(&mpt->m_doneq_thread_id[j].mutex);
+		}
+		mutex_exit(&mpt->m_doneq_mutex);
+		doneq_thread_create++;
+	}
+
+	/* Get supported interrupt types */
+	if (ddi_intr_get_supported_types(dip, &intr_types) != DDI_SUCCESS) {
+		mptsas_log(mpt, CE_WARN, "ddi_intr_get_supported_types "
+		    "failed\n");
+		goto fail;
+	}
+
+	NDBG6(("ddi_intr_get_supported_types() returned: 0x%x", intr_types));
+
+	if (mptsas_enable_msi && (intr_types & DDI_INTR_TYPE_MSI)) {
+		/*
+		 * Try MSI, but fall back to FIXED
+		 */
+		if (mptsas_add_intrs(mpt, DDI_INTR_TYPE_MSI) == DDI_SUCCESS) {
+			NDBG0(("Using MSI interrupt type"));
+			mpt->m_intr_type = DDI_INTR_TYPE_MSI;
+			goto intr_done;
+		}
+	}
+
+	if (intr_types & DDI_INTR_TYPE_FIXED) {
+
+		if (mptsas_add_intrs(mpt, DDI_INTR_TYPE_FIXED) == DDI_SUCCESS) {
+			NDBG0(("Using FIXED interrupt type"));
+			mpt->m_intr_type = DDI_INTR_TYPE_FIXED;
+
+			goto intr_done;
+		}
+
+		NDBG0(("FIXED interrupt registration failed"));
+	}
+
+	goto fail;
+
+intr_done:
+	intr_added++;
+
+	/* Initialize mutex used in interrupt handler */
+	mutex_init(&mpt->m_mutex, NULL, MUTEX_DRIVER,
+	    DDI_INTR_PRI(mpt->m_intr_pri));
+	mutex_init(&mpt->m_tx_waitq_mutex, NULL, MUTEX_DRIVER,
+	    DDI_INTR_PRI(mpt->m_intr_pri));
+	cv_init(&mpt->m_cv, NULL, CV_DRIVER, NULL);
+	cv_init(&mpt->m_passthru_cv, NULL, CV_DRIVER, NULL);
+	cv_init(&mpt->m_fw_cv, NULL, CV_DRIVER, NULL);
+	cv_init(&mpt->m_config_cv, NULL, CV_DRIVER, NULL);
+	mutex_init_done++;
+
+	/*
+	 * Disable hardware interrupt since we're not ready to
+	 * handle it yet.
+	 */
+	MPTSAS_DISABLE_INTR(mpt);
+
+	/*
+	 * Enable interrupts
+	 */
+	if (mpt->m_intr_cap & DDI_INTR_FLAG_BLOCK) {
+		/* Call ddi_intr_block_enable() for MSI interrupts */
+		(void) ddi_intr_block_enable(mpt->m_htable, mpt->m_intr_cnt);
+	} else {
+		/* Call ddi_intr_enable for MSI or FIXED interrupts */
+		for (i = 0; i < mpt->m_intr_cnt; i++) {
+			(void) ddi_intr_enable(mpt->m_htable[i]);
+		}
+	}
+
+	mutex_enter(&mpt->m_mutex);
+	/*
+	 * Initialize power management component
+	 */
+	if (mpt->m_options & MPTSAS_OPT_PM) {
+		if (mptsas_init_pm(mpt)) {
+			mutex_exit(&mpt->m_mutex);
+			mptsas_log(mpt, CE_WARN, "mptsas pm initialization "
+			    "failed");
+			goto fail;
+		}
+	}
+
+	/*
+	 * Initialize chip
+	 */
+	if (mptsas_init_chip(mpt, TRUE) == DDI_FAILURE) {
+		mutex_exit(&mpt->m_mutex);
+		mptsas_log(mpt, CE_WARN, "mptsas chip initialization failed");
+		goto fail;
+	}
+	mutex_exit(&mpt->m_mutex);
+
+	/*
+	 * initialize SCSI HBA transport structure
+	 */
+	hba_tran->tran_hba_private	= mpt;
+	hba_tran->tran_tgt_private	= NULL;
+
+	hba_tran->tran_tgt_init		= mptsas_scsi_tgt_init;
+	hba_tran->tran_tgt_free		= mptsas_scsi_tgt_free;
+
+	hba_tran->tran_start		= mptsas_scsi_start;
+	hba_tran->tran_reset		= mptsas_scsi_reset;
+	hba_tran->tran_abort		= mptsas_scsi_abort;
+	hba_tran->tran_getcap		= mptsas_scsi_getcap;
+	hba_tran->tran_setcap		= mptsas_scsi_setcap;
+	hba_tran->tran_init_pkt		= mptsas_scsi_init_pkt;
+	hba_tran->tran_destroy_pkt	= mptsas_scsi_destroy_pkt;
+
+	hba_tran->tran_dmafree		= mptsas_scsi_dmafree;
+	hba_tran->tran_sync_pkt		= mptsas_scsi_sync_pkt;
+	hba_tran->tran_reset_notify	= mptsas_scsi_reset_notify;
+
+	hba_tran->tran_get_bus_addr	= mptsas_get_bus_addr;
+	hba_tran->tran_get_name		= mptsas_get_name;
+
+	hba_tran->tran_quiesce		= mptsas_scsi_quiesce;
+	hba_tran->tran_unquiesce	= mptsas_scsi_unquiesce;
+	hba_tran->tran_bus_reset	= NULL;
+
+	hba_tran->tran_add_eventcall	= NULL;
+	hba_tran->tran_get_eventcookie	= NULL;
+	hba_tran->tran_post_event	= NULL;
+	hba_tran->tran_remove_eventcall	= NULL;
+
+	hba_tran->tran_bus_config	= mptsas_bus_config;
+
+	hba_tran->tran_interconnect_type = INTERCONNECT_SAS;
+
+	if (mptsas_alloc_active_slots(mpt, KM_SLEEP)) {
+		goto fail;
+	}
+
+	/*
+	 * Register the iport for multiple port HBA
+	 */
+	/*
+	 * initial value of mask is 0
+	 */
+	mutex_enter(&mpt->m_mutex);
+	for (i = 0; i < mpt->m_num_phys; i++) {
+		uint8_t	phy_mask = 0x00;
+		char phy_mask_name[8];
+		uint8_t current_port;
+
+		if (mpt->m_phy_info[i].attached_devhdl == 0)
+			continue;
+
+		bzero(phy_mask_name, sizeof (phy_mask_name));
+
+		current_port = mpt->m_phy_info[i].port_num;
+
+		if ((mask & (1 << i)) != 0)
+			continue;
+
+		for (j = 0; j < mpt->m_num_phys; j++) {
+			if (mpt->m_phy_info[j].attached_devhdl &&
+			    (mpt->m_phy_info[j].port_num == current_port)) {
+				phy_mask |= (1 << j);
+			}
+		}
+		mask = mask | phy_mask;
+
+		for (j = 0; j < mpt->m_num_phys; j++) {
+			if ((phy_mask >> j) & 0x01) {
+				mpt->m_phy_info[j].phy_mask = phy_mask;
+			}
+		}
+
+		(void) sprintf(phy_mask_name, "%x", phy_mask);
+
+		mutex_exit(&mpt->m_mutex);
+		/*
+		 * register a iport
+		 */
+		(void) scsi_hba_iport_register(dip, phy_mask_name);
+		mutex_enter(&mpt->m_mutex);
+	}
+	mutex_exit(&mpt->m_mutex);
+	/*
+	 * register a virtual port for RAID volume always
+	 */
+	(void) scsi_hba_iport_register(dip, "v0");
+	/*
+	 * All children of the HBA are iports. We need tran was cloned.
+	 * So we pass the flags to SCSA. SCSI_HBA_TRAN_CLONE will be
+	 * inherited to iport's tran vector.
+	 */
+	tran_flags = (SCSI_HBA_HBA | SCSI_HBA_TRAN_CLONE);
+
+	if (scsi_hba_attach_setup(dip, &mpt->m_msg_dma_attr,
+	    hba_tran, tran_flags) != DDI_SUCCESS) {
+		mptsas_log(mpt, CE_WARN, "hba attach setup failed");
+		goto fail;
+	}
+	hba_attach_setup++;
+
+	mpt->m_smptran = sas_hba_tran_alloc(dip, SCSI_HBA_CANSLEEP);
+	ASSERT(mpt->m_smptran != NULL);
+	mpt->m_smptran->tran_hba_private = mpt;
+	mpt->m_smptran->tran_smp_start = mptsas_smp_start;
+	mpt->m_smptran->tran_sas_getcap = mptsas_getcap;
+	if (sas_hba_attach_setup(dip, mpt->m_smptran) != DDI_SUCCESS) {
+		mptsas_log(mpt, CE_WARN, "smp attach setup failed");
+		goto fail;
+	}
+	sas_attach_setup++;
+	/*
+	 * Initialize smp hash table
+	 */
+	mptsas_hash_init(&mpt->m_active->m_smptbl);
+	mpt->m_smp_devhdl = 0xFFFF;
+
+	/*
+	 * create kmem cache for packets
+	 */
+	(void) sprintf(buf, "mptsas%d_cache", instance);
+	mpt->m_kmem_cache = kmem_cache_create(buf,
+	    sizeof (struct mptsas_cmd) + scsi_pkt_size(), 8,
+	    mptsas_kmem_cache_constructor, mptsas_kmem_cache_destructor,
+	    NULL, (void *)mpt, NULL, 0);
+
+	if (mpt->m_kmem_cache == NULL) {
+		mptsas_log(mpt, CE_WARN, "creating kmem cache failed");
+		goto fail;
+	}
+
+	/*
+	 * create kmem cache for extra SGL frames if SGL cannot
+	 * be accomodated into main request frame.
+	 */
+	(void) sprintf(buf, "mptsas%d_cache_frames", instance);
+	mpt->m_cache_frames = kmem_cache_create(buf,
+	    sizeof (mptsas_cache_frames_t), 8,
+	    mptsas_cache_frames_constructor, mptsas_cache_frames_destructor,
+	    NULL, (void *)mpt, NULL, 0);
+
+	if (mpt->m_cache_frames == NULL) {
+		mptsas_log(mpt, CE_WARN, "creating cache for frames failed");
+		goto fail;
+	}
+
+	mpt->m_scsi_reset_delay	= ddi_prop_get_int(DDI_DEV_T_ANY,
+	    dip, 0, "scsi-reset-delay",	SCSI_DEFAULT_RESET_DELAY);
+	if (mpt->m_scsi_reset_delay == 0) {
+		mptsas_log(mpt, CE_NOTE,
+		    "scsi_reset_delay of 0 is not recommended,"
+		    " resetting to SCSI_DEFAULT_RESET_DELAY\n");
+		mpt->m_scsi_reset_delay = SCSI_DEFAULT_RESET_DELAY;
+	}
+
+	/*
+	 * Initialize the wait and done FIFO queue
+	 */
+	mpt->m_donetail = &mpt->m_doneq;
+	mpt->m_waitqtail = &mpt->m_waitq;
+
+	mpt->m_tx_waitqtail = &mpt->m_tx_waitq;
+	mpt->m_tx_draining = 0;
+
+	/*
+	 * ioc cmd queue initialize
+	 */
+	mpt->m_ioc_event_cmdtail = &mpt->m_ioc_event_cmdq;
+
+	mpt->m_dev_handle = 0xFFFF;
+
+	MPTSAS_ENABLE_INTR(mpt);
+
+	/*
+	 * enable event notification
+	 */
+	mutex_enter(&mpt->m_mutex);
+	if (mptsas_ioc_enable_event_notification(mpt)) {
+		mutex_exit(&mpt->m_mutex);
+		goto fail;
+	}
+	mutex_exit(&mpt->m_mutex);
+
+
+	/* Check all dma handles allocated in attach */
+	if ((mptsas_check_dma_handle(mpt->m_dma_req_frame_hdl)
+	    != DDI_SUCCESS) ||
+	    (mptsas_check_dma_handle(mpt->m_dma_reply_frame_hdl)
+	    != DDI_SUCCESS) ||
+	    (mptsas_check_dma_handle(mpt->m_dma_free_queue_hdl)
+	    != DDI_SUCCESS) ||
+	    (mptsas_check_dma_handle(mpt->m_dma_post_queue_hdl)
+	    != DDI_SUCCESS) ||
+	    (mptsas_check_dma_handle(mpt->m_hshk_dma_hdl)
+	    != DDI_SUCCESS)) {
+		goto fail;
+	}
+
+	/* Check all acc handles allocated in attach */
+	if ((mptsas_check_acc_handle(mpt->m_datap) != DDI_SUCCESS) ||
+	    (mptsas_check_acc_handle(mpt->m_acc_req_frame_hdl)
+	    != DDI_SUCCESS) ||
+	    (mptsas_check_acc_handle(mpt->m_acc_reply_frame_hdl)
+	    != DDI_SUCCESS) ||
+	    (mptsas_check_acc_handle(mpt->m_acc_free_queue_hdl)
+	    != DDI_SUCCESS) ||
+	    (mptsas_check_acc_handle(mpt->m_acc_post_queue_hdl)
+	    != DDI_SUCCESS) ||
+	    (mptsas_check_acc_handle(mpt->m_hshk_acc_hdl)
+	    != DDI_SUCCESS) ||
+	    (mptsas_check_acc_handle(mpt->m_config_handle)
+	    != DDI_SUCCESS)) {
+		goto fail;
+	}
+
+	/*
+	 * After this point, we are not going to fail the attach.
+	 */
+	/*
+	 * used for mptsas_watch
+	 */
+	rw_enter(&mptsas_global_rwlock, RW_WRITER);
+	if (mptsas_head == NULL) {
+		mptsas_head = mpt;
+	} else {
+		mptsas_tail->m_next = mpt;
+	}
+	mptsas_tail = mpt;
+	rw_exit(&mptsas_global_rwlock);
+
+	mutex_enter(&mptsas_global_mutex);
+	if (mptsas_timeouts_enabled == 0) {
+		mptsas_scsi_watchdog_tick = ddi_prop_get_int(DDI_DEV_T_ANY,
+		    dip, 0, "scsi-watchdog-tick", DEFAULT_WD_TICK);
+
+		mptsas_tick = mptsas_scsi_watchdog_tick *
+		    drv_usectohz((clock_t)1000000);
+
+		mptsas_timeout_id = timeout(mptsas_watch, NULL, mptsas_tick);
+		mptsas_timeouts_enabled = 1;
+	}
+	mutex_exit(&mptsas_global_mutex);
+
+	/* Print message of HBA present */
+	ddi_report_dev(dip);
+
+	/* report idle status to pm framework */
+	if (mpt->m_options & MPTSAS_OPT_PM) {
+		(void) pm_idle_component(dip, 0);
+	}
+
+	return (DDI_SUCCESS);
+
+fail:
+	mptsas_log(mpt, CE_WARN, "attach failed");
+	mptsas_fm_ereport(mpt, DDI_FM_DEVICE_NO_RESPONSE);
+	ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_LOST);
+	if (mpt) {
+		mutex_enter(&mptsas_global_mutex);
+
+		if (mptsas_timeout_id && (mptsas_head == NULL)) {
+			timeout_id_t tid = mptsas_timeout_id;
+			mptsas_timeouts_enabled = 0;
+			mptsas_timeout_id = 0;
+			mutex_exit(&mptsas_global_mutex);
+			(void) untimeout(tid);
+			mutex_enter(&mptsas_global_mutex);
+		}
+		mutex_exit(&mptsas_global_mutex);
+		/* deallocate in reverse order */
+		if (mpt->m_cache_frames) {
+			kmem_cache_destroy(mpt->m_cache_frames);
+		}
+		if (mpt->m_kmem_cache) {
+			kmem_cache_destroy(mpt->m_kmem_cache);
+		}
+		if (hba_attach_setup) {
+			(void) scsi_hba_detach(dip);
+		}
+		if (sas_attach_setup) {
+			(void) sas_hba_detach(dip);
+		}
+		if (intr_added) {
+			mptsas_rem_intrs(mpt);
+		}
+		if (doneq_thread_create) {
+			mutex_enter(&mpt->m_doneq_mutex);
+			doneq_thread_num = mpt->m_doneq_thread_n;
+			for (j = 0; j < mpt->m_doneq_thread_n; j++) {
+				mutex_enter(&mpt->m_doneq_thread_id[j].mutex);
+				mpt->m_doneq_thread_id[j].flag &=
+				    (~MPTSAS_DONEQ_THREAD_ACTIVE);
+				cv_signal(&mpt->m_doneq_thread_id[j].cv);
+				mutex_exit(&mpt->m_doneq_thread_id[j].mutex);
+			}
+			while (mpt->m_doneq_thread_n) {
+				cv_wait(&mpt->m_doneq_thread_cv,
+				    &mpt->m_doneq_mutex);
+			}
+			for (j = 0; j < doneq_thread_num; j++) {
+				cv_destroy(&mpt->m_doneq_thread_id[j].cv);
+				mutex_destroy(&mpt->m_doneq_thread_id[j].mutex);
+			}
+			kmem_free(mpt->m_doneq_thread_id,
+			    sizeof (mptsas_doneq_thread_list_t)
+			    * doneq_thread_num);
+			mutex_exit(&mpt->m_doneq_mutex);
+			cv_destroy(&mpt->m_doneq_thread_cv);
+			mutex_destroy(&mpt->m_doneq_mutex);
+		}
+		if (event_taskq_create) {
+			ddi_taskq_destroy(mpt->m_event_taskq);
+		}
+		if (dr_taskq_create) {
+			ddi_taskq_destroy(mpt->m_dr_taskq);
+		}
+		if (mutex_init_done) {
+			mutex_destroy(&mpt->m_tx_waitq_mutex);
+			mutex_destroy(&mpt->m_mutex);
+			cv_destroy(&mpt->m_cv);
+			cv_destroy(&mpt->m_passthru_cv);
+			cv_destroy(&mpt->m_fw_cv);
+			cv_destroy(&mpt->m_config_cv);
+		}
+		mptsas_free_handshake_msg(mpt);
+		mptsas_hba_fini(mpt);
+		if (map_setup) {
+			mptsas_cfg_fini(mpt);
+		}
+		if (config_setup) {
+			pci_config_teardown(&mpt->m_config_handle);
+		}
+		if (mpt->m_tran) {
+			scsi_hba_tran_free(mpt->m_tran);
+			mpt->m_tran = NULL;
+		}
+		if (mpt->m_smptran) {
+			sas_hba_tran_free(mpt->m_smptran);
+			mpt->m_smptran = NULL;
+		}
+		mptsas_fm_fini(mpt);
+		ddi_soft_state_free(mptsas_state, instance);
+		ddi_prop_remove_all(dip);
+	}
+	return (DDI_FAILURE);
+}
+
+static int
+mptsas_suspend(dev_info_t *devi)
+{
+	mptsas_t	*mpt, *g;
+	scsi_hba_tran_t	*tran;
+
+	if (scsi_hba_iport_unit_address(devi)) {
+		return (DDI_SUCCESS);
+	}
+
+	if ((tran = ddi_get_driver_private(devi)) == NULL)
+		return (DDI_SUCCESS);
+
+	mpt = TRAN2MPT(tran);
+	if (!mpt) {
+		return (DDI_SUCCESS);
+	}
+
+	mutex_enter(&mpt->m_mutex);
+
+	if (mpt->m_suspended++) {
+		mutex_exit(&mpt->m_mutex);
+		return (DDI_SUCCESS);
+	}
+
+	/*
+	 * Cancel timeout threads for this mpt
+	 */
+	if (mpt->m_quiesce_timeid) {
+		timeout_id_t tid = mpt->m_quiesce_timeid;
+		mpt->m_quiesce_timeid = 0;
+		mutex_exit(&mpt->m_mutex);
+		(void) untimeout(tid);
+		mutex_enter(&mpt->m_mutex);
+	}
+
+	if (mpt->m_restart_cmd_timeid) {
+		timeout_id_t tid = mpt->m_restart_cmd_timeid;
+		mpt->m_restart_cmd_timeid = 0;
+		mutex_exit(&mpt->m_mutex);
+		(void) untimeout(tid);
+		mutex_enter(&mpt->m_mutex);
+	}
+
+	if (mpt->m_pm_timeid != 0) {
+		timeout_id_t tid = mpt->m_pm_timeid;
+		mpt->m_pm_timeid = 0;
+		mutex_exit(&mpt->m_mutex);
+		(void) untimeout(tid);
+		/*
+		 * Report idle status for last ioctl since
+		 * calls to pm_busy_component(9F) are stacked.
+		 */
+		(void) pm_idle_component(mpt->m_dip, 0);
+		mutex_enter(&mpt->m_mutex);
+	}
+	mutex_exit(&mpt->m_mutex);
+
+	/*
+	 * Cancel watch threads if all mpts suspended
+	 */
+	rw_enter(&mptsas_global_rwlock, RW_WRITER);
+	for (g = mptsas_head; g != NULL; g = g->m_next) {
+		if (!g->m_suspended)
+			break;
+	}
+	rw_exit(&mptsas_global_rwlock);
+
+	mutex_enter(&mptsas_global_mutex);
+	if (g == NULL) {
+		timeout_id_t tid;
+
+		mptsas_timeouts_enabled = 0;
+		if (mptsas_timeout_id) {
+			tid = mptsas_timeout_id;
+			mptsas_timeout_id = 0;
+			mutex_exit(&mptsas_global_mutex);
+			(void) untimeout(tid);
+			mutex_enter(&mptsas_global_mutex);
+		}
+		if (mptsas_reset_watch) {
+			tid = mptsas_reset_watch;
+			mptsas_reset_watch = 0;
+			mutex_exit(&mptsas_global_mutex);
+			(void) untimeout(tid);
+			mutex_enter(&mptsas_global_mutex);
+		}
+	}
+	mutex_exit(&mptsas_global_mutex);
+
+	mutex_enter(&mpt->m_mutex);
+
+	/*
+	 * If this mpt is not in full power(PM_LEVEL_D0), just return.
+	 */
+	if ((mpt->m_options & MPTSAS_OPT_PM) &&
+	    (mpt->m_power_level != PM_LEVEL_D0)) {
+		mutex_exit(&mpt->m_mutex);
+		return (DDI_SUCCESS);
+	}
+
+	/* Disable HBA interrupts in hardware */
+	MPTSAS_DISABLE_INTR(mpt);
+
+	mutex_exit(&mpt->m_mutex);
+
+	/* drain the taskq */
+	ddi_taskq_wait(mpt->m_event_taskq);
+	ddi_taskq_wait(mpt->m_dr_taskq);
+
+	return (DDI_SUCCESS);
+}
+
+/*
+ * quiesce(9E) entry point.
+ *
+ * This function is called when the system is single-threaded at high
+ * PIL with preemption disabled. Therefore, this function must not be
+ * blocked.
+ *
+ * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure.
+ * DDI_FAILURE indicates an error condition and should almost never happen.
+ */
+#ifndef	__sparc
+static int
+mptsas_quiesce(dev_info_t *devi)
+{
+	mptsas_t	*mpt;
+	scsi_hba_tran_t *tran;
+
+	if ((tran = ddi_get_driver_private(devi)) == NULL)
+		return (DDI_SUCCESS);
+
+	if ((mpt = TRAN2MPT(tran)) == NULL)
+		return (DDI_SUCCESS);
+
+	/* Disable HBA interrupts in hardware */
+	MPTSAS_DISABLE_INTR(mpt);
+
+	return (DDI_SUCCESS);
+}
+#endif	/* __sparc */
+
+/*
+ * detach(9E).	Remove all device allocations and system resources;
+ * disable device interrupts.
+ * Return DDI_SUCCESS if done; DDI_FAILURE if there's a problem.
+ */
+static int
+mptsas_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
+{
+	/* CONSTCOND */
+	ASSERT(NO_COMPETING_THREADS);
+	NDBG0(("mptsas_detach: dip=0x%p cmd=0x%p", (void *)devi, (void *)cmd));
+
+	switch (cmd) {
+	case DDI_DETACH:
+		return (mptsas_do_detach(devi));
+
+	case DDI_SUSPEND:
+		return (mptsas_suspend(devi));
+
+	default:
+		return (DDI_FAILURE);
+	}
+	/* NOTREACHED */
+}
+
+static int
+mptsas_do_detach(dev_info_t *dip)
+{
+	mptsas_t	*mpt, *m;
+	scsi_hba_tran_t	*tran;
+	mptsas_slots_t	*active;
+	int		circ = 0;
+	int		circ1 = 0;
+	mdi_pathinfo_t	*pip = NULL;
+	int		i;
+	int		doneq_thread_num = 0;
+
+	NDBG0(("mptsas_do_detach: dip=0x%p", (void *)dip));
+
+	if ((tran = ndi_flavorv_get(dip, SCSA_FLAVOR_SCSI_DEVICE)) == NULL)
+		return (DDI_FAILURE);
+
+	mpt = TRAN2MPT(tran);
+	if (!mpt) {
+		return (DDI_FAILURE);
+	}
+	/*
+	 * Still have pathinfo child, should not detach mpt driver
+	 */
+	if (scsi_hba_iport_unit_address(dip)) {
+		if (mpt->m_mpxio_enable) {
+			/*
+			 * MPxIO enabled for the iport
+			 */
+			ndi_devi_enter(scsi_vhci_dip, &circ1);
+			ndi_devi_enter(dip, &circ);
+			while (pip = mdi_get_next_client_path(dip, NULL)) {
+				if (mdi_pi_free(pip, 0) == MDI_SUCCESS) {
+					continue;
+				}
+				ndi_devi_exit(dip, circ);
+				ndi_devi_exit(scsi_vhci_dip, circ1);
+				NDBG12(("detach failed because of "
+				    "outstanding path info"));
+				return (DDI_FAILURE);
+			}
+			ndi_devi_exit(dip, circ);
+			ndi_devi_exit(scsi_vhci_dip, circ1);
+			(void) mdi_phci_unregister(dip, 0);
+		}
+
+		ddi_prop_remove_all(dip);
+
+		return (DDI_SUCCESS);
+	}
+
+	/* Make sure power level is D0 before accessing registers */
+	if (mpt->m_options & MPTSAS_OPT_PM) {
+		(void) pm_busy_component(dip, 0);
+		if (mpt->m_power_level != PM_LEVEL_D0) {
+			if (pm_raise_power(dip, 0, PM_LEVEL_D0) !=
+			    DDI_SUCCESS) {
+				mptsas_log(mpt, CE_WARN,
+				    "mptsas%d: Raise power request failed.",
+				    mpt->m_instance);
+				(void) pm_idle_component(dip, 0);
+				return (DDI_FAILURE);
+			}
+		}
+	}
+
+	mutex_enter(&mpt->m_mutex);
+	MPTSAS_DISABLE_INTR(mpt);
+	mutex_exit(&mpt->m_mutex);
+	mptsas_rem_intrs(mpt);
+	ddi_taskq_destroy(mpt->m_event_taskq);
+	ddi_taskq_destroy(mpt->m_dr_taskq);
+
+	if (mpt->m_doneq_thread_n) {
+		mutex_enter(&mpt->m_doneq_mutex);
+		doneq_thread_num = mpt->m_doneq_thread_n;
+		for (i = 0; i < mpt->m_doneq_thread_n; i++) {
+			mutex_enter(&mpt->m_doneq_thread_id[i].mutex);
+			mpt->m_doneq_thread_id[i].flag &=
+			    (~MPTSAS_DONEQ_THREAD_ACTIVE);
+			cv_signal(&mpt->m_doneq_thread_id[i].cv);
+			mutex_exit(&mpt->m_doneq_thread_id[i].mutex);
+		}
+		while (mpt->m_doneq_thread_n) {
+			cv_wait(&mpt->m_doneq_thread_cv,
+			    &mpt->m_doneq_mutex);
+		}
+		for (i = 0;  i < doneq_thread_num; i++) {
+			cv_destroy(&mpt->m_doneq_thread_id[i].cv);
+			mutex_destroy(&mpt->m_doneq_thread_id[i].mutex);
+		}
+		kmem_free(mpt->m_doneq_thread_id,
+		    sizeof (mptsas_doneq_thread_list_t)
+		    * doneq_thread_num);
+		mutex_exit(&mpt->m_doneq_mutex);
+		cv_destroy(&mpt->m_doneq_thread_cv);
+		mutex_destroy(&mpt->m_doneq_mutex);
+	}
+
+	scsi_hba_reset_notify_tear_down(mpt->m_reset_notify_listf);
+
+	/*
+	 * Remove device instance from the global linked list
+	 */
+	rw_enter(&mptsas_global_rwlock, RW_WRITER);
+	if (mptsas_head == mpt) {
+		m = mptsas_head = mpt->m_next;
+	} else {
+		for (m = mptsas_head; m != NULL; m = m->m_next) {
+			if (m->m_next == mpt) {
+				m->m_next = mpt->m_next;
+				break;
+			}
+		}
+		if (m == NULL) {
+			mptsas_log(mpt, CE_PANIC, "Not in softc list!");
+		}
+	}
+
+	if (mptsas_tail == mpt) {
+		mptsas_tail = m;
+	}
+	rw_exit(&mptsas_global_rwlock);
+
+	/*
+	 * Cancel timeout threads for this mpt
+	 */
+	mutex_enter(&mpt->m_mutex);
+	if (mpt->m_quiesce_timeid) {
+		timeout_id_t tid = mpt->m_quiesce_timeid;
+		mpt->m_quiesce_timeid = 0;
+		mutex_exit(&mpt->m_mutex);
+		(void) untimeout(tid);
+		mutex_enter(&mpt->m_mutex);
+	}
+
+	if (mpt->m_restart_cmd_timeid) {
+		timeout_id_t tid = mpt->m_restart_cmd_timeid;
+		mpt->m_restart_cmd_timeid = 0;
+		mutex_exit(&mpt->m_mutex);
+		(void) untimeout(tid);
+		mutex_enter(&mpt->m_mutex);
+	}
+
+	if (mpt->m_pm_timeid != 0) {
+		timeout_id_t tid = mpt->m_pm_timeid;
+		mpt->m_pm_timeid = 0;
+		mutex_exit(&mpt->m_mutex);
+		(void) untimeout(tid);
+		/*
+		 * Report idle status for last ioctl since
+		 * calls to pm_busy_component(9F) are stacked.
+		 */
+		(void) pm_idle_component(mpt->m_dip, 0);
+		mutex_enter(&mpt->m_mutex);
+	}
+	mutex_exit(&mpt->m_mutex);
+
+	/*
+	 * last mpt? ... if active, CANCEL watch threads.
+	 */
+	mutex_enter(&mptsas_global_mutex);
+	if (mptsas_head == NULL) {
+		timeout_id_t tid;
+		/*
+		 * Clear mptsas_timeouts_enable so that the watch thread
+		 * gets restarted on DDI_ATTACH
+		 */
+		mptsas_timeouts_enabled = 0;
+		if (mptsas_timeout_id) {
+			tid = mptsas_timeout_id;
+			mptsas_timeout_id = 0;
+			mutex_exit(&mptsas_global_mutex);
+			(void) untimeout(tid);
+			mutex_enter(&mptsas_global_mutex);
+		}
+		if (mptsas_reset_watch) {
+			tid = mptsas_reset_watch;
+			mptsas_reset_watch = 0;
+			mutex_exit(&mptsas_global_mutex);
+			(void) untimeout(tid);
+			mutex_enter(&mptsas_global_mutex);
+		}
+	}
+	mutex_exit(&mptsas_global_mutex);
+
+	/*
+	 * Delete nt_active.
+	 */
+	active = mpt->m_active;
+	mutex_enter(&mpt->m_mutex);
+	mptsas_hash_uninit(&active->m_smptbl, sizeof (mptsas_smp_t));
+	mutex_exit(&mpt->m_mutex);
+
+	if (active) {
+		kmem_free(active, active->m_size);
+		mpt->m_active = NULL;
+	}
+
+	/* deallocate everything that was allocated in mptsas_attach */
+	mptsas_fm_fini(mpt);
+	kmem_cache_destroy(mpt->m_cache_frames);
+	kmem_cache_destroy(mpt->m_kmem_cache);
+
+	(void) scsi_hba_detach(dip);
+	(void) sas_hba_detach(dip);
+	mptsas_free_handshake_msg(mpt);
+	mptsas_hba_fini(mpt);
+	mptsas_cfg_fini(mpt);
+
+	/* Lower the power informing PM Framework */
+	if (mpt->m_options & MPTSAS_OPT_PM) {
+		if (pm_lower_power(dip, 0, PM_LEVEL_D3) != DDI_SUCCESS)
+			mptsas_log(mpt, CE_WARN,
+			    "!mptsas%d: Lower power request failed "
+			    "during detach, ignoring.",
+			    mpt->m_instance);
+	}
+
+	mutex_destroy(&mpt->m_tx_waitq_mutex);
+	mutex_destroy(&mpt->m_mutex);
+	cv_destroy(&mpt->m_cv);
+	cv_destroy(&mpt->m_passthru_cv);
+	cv_destroy(&mpt->m_fw_cv);
+	cv_destroy(&mpt->m_config_cv);
+
+	pci_config_teardown(&mpt->m_config_handle);
+	if (mpt->m_tran) {
+		scsi_hba_tran_free(mpt->m_tran);
+		mpt->m_tran = NULL;
+	}
+
+	if (mpt->m_smptran) {
+		sas_hba_tran_free(mpt->m_smptran);
+		mpt->m_smptran = NULL;
+	}
+
+	ddi_soft_state_free(mptsas_state, ddi_get_instance(dip));
+	ddi_prop_remove_all(dip);
+
+	return (DDI_SUCCESS);
+}
+
+static int
+mptsas_alloc_handshake_msg(mptsas_t *mpt, size_t alloc_size)
+{
+	ddi_dma_attr_t		task_dma_attrs;
+	ddi_dma_cookie_t	tmp_dma_cookie;
+	size_t			alloc_len;
+	uint_t			ncookie;
+
+	/* allocate Task Management ddi_dma resources */
+	task_dma_attrs = mpt->m_msg_dma_attr;
+	task_dma_attrs.dma_attr_sgllen = 1;
+	task_dma_attrs.dma_attr_granular = (uint32_t)(alloc_size);
+
+	if (ddi_dma_alloc_handle(mpt->m_dip, &task_dma_attrs,
+	    DDI_DMA_SLEEP, NULL, &mpt->m_hshk_dma_hdl) != DDI_SUCCESS) {
+		mpt->m_hshk_dma_hdl = NULL;
+		return (DDI_FAILURE);
+	}
+
+	if (ddi_dma_mem_alloc(mpt->m_hshk_dma_hdl, alloc_size,
+	    &mpt->m_dev_acc_attr, DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL,
+	    &mpt->m_hshk_memp, &alloc_len, &mpt->m_hshk_acc_hdl)
+	    != DDI_SUCCESS) {
+		ddi_dma_free_handle(&mpt->m_hshk_dma_hdl);
+		mpt->m_hshk_dma_hdl = NULL;
+		return (DDI_FAILURE);
+	}
+
+	if (ddi_dma_addr_bind_handle(mpt->m_hshk_dma_hdl, NULL,
+	    mpt->m_hshk_memp, alloc_len, (DDI_DMA_RDWR | DDI_DMA_CONSISTENT),
+	    DDI_DMA_SLEEP, NULL, &tmp_dma_cookie, &ncookie)
+	    != DDI_DMA_MAPPED) {
+		(void) ddi_dma_mem_free(&mpt->m_hshk_acc_hdl);
+		ddi_dma_free_handle(&mpt->m_hshk_dma_hdl);
+		mpt->m_hshk_dma_hdl = NULL;
+		return (DDI_FAILURE);
+	}
+	mpt->m_hshk_dma_size = alloc_size;
+	return (DDI_SUCCESS);
+}
+
+static void
+mptsas_free_handshake_msg(mptsas_t *mpt)
+{
+	if (mpt->m_hshk_dma_hdl != NULL) {
+		(void) ddi_dma_unbind_handle(mpt->m_hshk_dma_hdl);
+		(void) ddi_dma_mem_free(&mpt->m_hshk_acc_hdl);
+		ddi_dma_free_handle(&mpt->m_hshk_dma_hdl);
+		mpt->m_hshk_dma_hdl = NULL;
+		mpt->m_hshk_dma_size = 0;
+	}
+}
+
+static int
+mptsas_power(dev_info_t *dip, int component, int level)
+{
+#ifndef __lock_lint
+	_NOTE(ARGUNUSED(component))
+#endif
+	mptsas_t	*mpt;
+	int		rval = DDI_SUCCESS;
+	int		polls = 0;
+	uint32_t	ioc_status;
+
+	if (scsi_hba_iport_unit_address(dip) != 0)
+		return (DDI_SUCCESS);
+
+	mpt = ddi_get_soft_state(mptsas_state, ddi_get_instance(dip));
+	if (mpt == NULL) {
+		return (DDI_FAILURE);
+	}
+
+	mutex_enter(&mpt->m_mutex);
+
+	/*
+	 * If the device is busy, don't lower its power level
+	 */
+	if (mpt->m_busy && (mpt->m_power_level > level)) {
+		mutex_exit(&mpt->m_mutex);
+		return (DDI_FAILURE);
+	}
+
+	switch (level) {
+	case PM_LEVEL_D0:
+		NDBG11(("mptsas%d: turning power ON.", mpt->m_instance));
+		MPTSAS_POWER_ON(mpt);
+		/*
+		 * Wait up to 30 seconds for IOC to come out of reset.
+		 */
+		while (((ioc_status = ddi_get32(mpt->m_datap,
+		    &mpt->m_reg->Doorbell)) &
+		    MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_RESET) {
+			if (polls++ > 3000) {
+				break;
+			}
+			delay(drv_usectohz(10000));
+		}
+		/*
+		 * If IOC is not in operational state, try to hard reset it.
+		 */
+		if ((ioc_status & MPI2_IOC_STATE_MASK) !=
+		    MPI2_IOC_STATE_OPERATIONAL) {
+			if (mptsas_restart_ioc(mpt) == DDI_FAILURE) {
+				mptsas_log(mpt, CE_WARN,
+				    "mptsas_power: hard reset failed");
+				mutex_exit(&mpt->m_mutex);
+				return (DDI_FAILURE);
+			}
+		}
+		mpt->m_power_level = PM_LEVEL_D0;
+		break;
+	case PM_LEVEL_D3:
+		NDBG11(("mptsas%d: turning power OFF.", mpt->m_instance));
+		MPTSAS_POWER_OFF(mpt);
+		break;
+	default:
+		mptsas_log(mpt, CE_WARN, "mptsas%d: unknown power level <%x>.",
+		    mpt->m_instance, level);
+		rval = DDI_FAILURE;
+		break;
+	}
+	mutex_exit(&mpt->m_mutex);
+	return (rval);
+}
+
+/*
+ * Initialize configuration space and figure out which
+ * chip and revison of the chip the mpt driver is using.
+ */
+int
+mptsas_config_space_init(mptsas_t *mpt)
+{
+	ushort_t	caps_ptr, cap, cap_count;
+
+	NDBG0(("mptsas_config_space_init"));
+
+	mptsas_setup_cmd_reg(mpt);
+
+	/*
+	 * Get the chip device id:
+	 */
+	mpt->m_devid = pci_config_get16(mpt->m_config_handle, PCI_CONF_DEVID);
+
+	/*
+	 * Save the revision.
+	 */
+	mpt->m_revid = pci_config_get8(mpt->m_config_handle, PCI_CONF_REVID);
+
+	/*
+	 * Save the SubSystem Vendor and Device IDs
+	 */
+	mpt->m_svid = pci_config_get16(mpt->m_config_handle, PCI_CONF_SUBVENID);
+	mpt->m_ssid = pci_config_get16(mpt->m_config_handle, PCI_CONF_SUBSYSID);
+
+	/*
+	 * Set the latency timer to 0x40 as specified by the upa -> pci
+	 * bridge chip design team.  This may be done by the sparc pci
+	 * bus nexus driver, but the driver should make sure the latency
+	 * timer is correct for performance reasons.
+	 */
+	pci_config_put8(mpt->m_config_handle, PCI_CONF_LATENCY_TIMER,
+	    MPTSAS_LATENCY_TIMER);
+
+	/*
+	 * Check if capabilities list is supported and if so,
+	 * get initial capabilities pointer and clear bits 0,1.
+	 */
+	if (pci_config_get16(mpt->m_config_handle, PCI_CONF_STAT)
+	    & PCI_STAT_CAP) {
+		caps_ptr = P2ALIGN(pci_config_get8(mpt->m_config_handle,
+		    PCI_CONF_CAP_PTR), 4);
+	} else {
+		caps_ptr = PCI_CAP_NEXT_PTR_NULL;
+	}
+
+	/*
+	 * Walk capabilities if supported.
+	 */
+	for (cap_count = 0; caps_ptr != PCI_CAP_NEXT_PTR_NULL; ) {
+
+		/*
+		 * Check that we haven't exceeded the maximum number of
+		 * capabilities and that the pointer is in a valid range.
+		 */
+		if (++cap_count > 48) {
+			mptsas_log(mpt, CE_WARN,
+			    "too many device capabilities.\n");
+			return (FALSE);
+		}
+		if (caps_ptr < 64) {
+			mptsas_log(mpt, CE_WARN,
+			    "capabilities pointer 0x%x out of range.\n",
+			    caps_ptr);
+			return (FALSE);
+		}
+
+		/*
+		 * Get next capability and check that it is valid.
+		 * For now, we only support power management.
+		 */
+		cap = pci_config_get8(mpt->m_config_handle, caps_ptr);
+		switch (cap) {
+			case PCI_CAP_ID_PM:
+				mptsas_log(mpt, CE_NOTE,
+				    "?mptsas%d supports power management.\n",
+				    mpt->m_instance);
+				mpt->m_options |= MPTSAS_OPT_PM;
+
+				/* Save PMCSR offset */
+				mpt->m_pmcsr_offset = caps_ptr + PCI_PMCSR;
+				break;
+
+			/*
+			 * 0x5 is Message signaled interrupts and 0x7
+			 * is pci-x capable.  Both are unsupported for now
+			 * but supported by the 1030 chip so we don't
+			 * need to keep printing out the notice.
+			 * 0x10 is PCI-E support (1064E/1068E)
+			 * 0x11 is MSIX supported by the 1064/1068
+			 */
+			case 0x5:
+			case 0x7:
+			case 0x10:
+			case 0x11:
+				break;
+			default:
+				mptsas_log(mpt, CE_NOTE,
+				    "?mptsas%d unrecognized capability "
+				    "0x%x.\n", mpt->m_instance, cap);
+			break;
+		}
+
+		/*
+		 * Get next capabilities pointer and clear bits 0,1.
+		 */
+		caps_ptr = P2ALIGN(pci_config_get8(mpt->m_config_handle,
+		    (caps_ptr + PCI_CAP_NEXT_PTR)), 4);
+	}
+
+	return (TRUE);
+}
+
+static void
+mptsas_setup_cmd_reg(mptsas_t *mpt)
+{
+	ushort_t	cmdreg;
+
+	/*
+	 * Set the command register to the needed values.
+	 */
+	cmdreg = pci_config_get16(mpt->m_config_handle, PCI_CONF_COMM);
+	cmdreg |= (PCI_COMM_ME | PCI_COMM_SERR_ENABLE |
+	    PCI_COMM_PARITY_DETECT | PCI_COMM_MAE);
+	cmdreg &= ~PCI_COMM_IO;
+	pci_config_put16(mpt->m_config_handle, PCI_CONF_COMM, cmdreg);
+}
+
+static void
+mptsas_disable_bus_master(mptsas_t *mpt)
+{
+	ushort_t	cmdreg;
+
+	/*
+	 * Clear the master enable bit in the PCI command register.
+	 * This prevents any bus mastering activity like DMA.
+	 */
+	cmdreg = pci_config_get16(mpt->m_config_handle, PCI_CONF_COMM);
+	cmdreg &= ~PCI_COMM_ME;
+	pci_config_put16(mpt->m_config_handle, PCI_CONF_COMM, cmdreg);
+}
+
+int
+mptsas_passthru_dma_alloc(mptsas_t *mpt, mptsas_dma_alloc_state_t *dma_statep)
+{
+	ddi_dma_attr_t	attrs;
+	uint_t		ncookie;
+	size_t		alloc_len;
+
+	attrs = mpt->m_msg_dma_attr;
+	attrs.dma_attr_sgllen = 1;
+
+	ASSERT(dma_statep != NULL);
+
+	if (ddi_dma_alloc_handle(mpt->m_dip, &attrs,
+	    DDI_DMA_SLEEP, NULL, &dma_statep->handle) != DDI_SUCCESS) {
+		mptsas_log(mpt, CE_WARN,
+		    "unable to allocate dma handle.");
+		return (DDI_FAILURE);
+	}
+
+	if (ddi_dma_mem_alloc(dma_statep->handle, dma_statep->size,
+	    &mpt->m_dev_acc_attr, DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL,
+	    &dma_statep->memp, &alloc_len, &dma_statep->accessp) !=
+	    DDI_SUCCESS) {
+		ddi_dma_free_handle(&dma_statep->handle);
+		dma_statep->handle = NULL;
+		mptsas_log(mpt, CE_WARN,
+		    "unable to allocate memory for dma xfer.");
+		return (DDI_FAILURE);
+	}
+
+	if (ddi_dma_addr_bind_handle(dma_statep->handle, NULL, dma_statep->memp,
+	    alloc_len, DDI_DMA_RDWR | DDI_DMA_CONSISTENT, DDI_DMA_SLEEP,
+	    NULL, &dma_statep->cookie, &ncookie) != DDI_DMA_MAPPED) {
+		ddi_dma_mem_free(&dma_statep->accessp);
+		dma_statep->accessp = NULL;
+		ddi_dma_free_handle(&dma_statep->handle);
+		dma_statep->handle = NULL;
+		mptsas_log(mpt, CE_WARN, "unable to bind DMA resources.");
+		return (DDI_FAILURE);
+	}
+	return (DDI_SUCCESS);
+}
+
+void
+mptsas_passthru_dma_free(mptsas_dma_alloc_state_t *dma_statep)
+{
+	ASSERT(dma_statep != NULL);
+	if (dma_statep->handle != NULL) {
+		(void) ddi_dma_unbind_handle(dma_statep->handle);
+		(void) ddi_dma_mem_free(&dma_statep->accessp);
+		ddi_dma_free_handle(&dma_statep->handle);
+	}
+}
+
+int
+mptsas_do_dma(mptsas_t *mpt, uint32_t size, int var, int (*callback)())
+{
+	ddi_dma_attr_t		attrs;
+	ddi_dma_handle_t	dma_handle;
+	caddr_t			memp;
+	uint_t			ncookie;
+	ddi_dma_cookie_t	cookie;
+	ddi_acc_handle_t	accessp;
+	size_t			alloc_len;
+	int			rval;
+
+	ASSERT(mutex_owned(&mpt->m_mutex));
+
+	attrs = mpt->m_msg_dma_attr;
+	attrs.dma_attr_sgllen = 1;
+	attrs.dma_attr_granular = size;
+
+	if (ddi_dma_alloc_handle(mpt->m_dip, &attrs,
+	    DDI_DMA_SLEEP, NULL, &dma_handle) != DDI_SUCCESS) {
+		mptsas_log(mpt, CE_WARN,
+		    "unable to allocate dma handle.");
+		return (DDI_FAILURE);
+	}
+
+	if (ddi_dma_mem_alloc(dma_handle, size,
+	    &mpt->m_dev_acc_attr, DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL,
+	    &memp, &alloc_len, &accessp) != DDI_SUCCESS) {
+		ddi_dma_free_handle(&dma_handle);
+		mptsas_log(mpt, CE_WARN,
+		    "unable to allocate request structure.");
+		return (DDI_FAILURE);
+	}
+
+	if (ddi_dma_addr_bind_handle(dma_handle, NULL, memp,
+	    alloc_len, DDI_DMA_RDWR | DDI_DMA_CONSISTENT, DDI_DMA_SLEEP,
+	    NULL, &cookie, &ncookie) != DDI_DMA_MAPPED) {
+		(void) ddi_dma_mem_free(&accessp);
+		ddi_dma_free_handle(&dma_handle);
+		mptsas_log(mpt, CE_WARN, "unable to bind DMA resources.");
+		return (DDI_FAILURE);
+	}
+
+	rval = (*callback) (mpt, memp, var, accessp);
+
+	if ((mptsas_check_dma_handle(dma_handle) != DDI_SUCCESS) ||
+	    (mptsas_check_acc_handle(accessp) != DDI_SUCCESS)) {
+		ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
+		rval = DDI_FAILURE;
+	}
+
+	if (dma_handle != NULL) {
+		(void) ddi_dma_unbind_handle(dma_handle);
+		(void) ddi_dma_mem_free(&accessp);
+		ddi_dma_free_handle(&dma_handle);
+	}
+
+	return (rval);
+
+}
+
+static int
+mptsas_alloc_request_frames(mptsas_t *mpt)
+{
+	ddi_dma_attr_t		frame_dma_attrs;
+	caddr_t			memp;
+	uint_t			ncookie;
+	ddi_dma_cookie_t	cookie;
+	size_t			alloc_len;
+	size_t			mem_size;
+
+	/*
+	 * The size of the request frame pool is:
+	 *   Number of Request Frames * Request Frame Size
+	 */
+	mem_size = mpt->m_max_requests * mpt->m_req_frame_size;
+
+	/*
+	 * set the DMA attributes.  System Request Message Frames must be
+	 * aligned on a 16-byte boundry.
+	 */
+	frame_dma_attrs = mpt->m_msg_dma_attr;
+	frame_dma_attrs.dma_attr_align = 16;
+	frame_dma_attrs.dma_attr_sgllen = 1;
+
+	/*
+	 * allocate the request frame pool.
+	 */
+	if (ddi_dma_alloc_handle(mpt->m_dip, &frame_dma_attrs,
+	    DDI_DMA_SLEEP, NULL, &mpt->m_dma_req_frame_hdl) != DDI_SUCCESS) {
+		mptsas_log(mpt, CE_WARN,
+		    "Unable to allocate dma handle.");
+		return (DDI_FAILURE);
+	}
+
+	if (ddi_dma_mem_alloc(mpt->m_dma_req_frame_hdl,
+	    mem_size, &mpt->m_dev_acc_attr, DDI_DMA_CONSISTENT, DDI_DMA_SLEEP,
+	    NULL, (caddr_t *)&memp, &alloc_len, &mpt->m_acc_req_frame_hdl)
+	    != DDI_SUCCESS) {
+		ddi_dma_free_handle(&mpt->m_dma_req_frame_hdl);
+		mpt->m_dma_req_frame_hdl = NULL;
+		mptsas_log(mpt, CE_WARN,
+		    "Unable to allocate request frames.");
+		return (DDI_FAILURE);
+	}
+
+	if (ddi_dma_addr_bind_handle(mpt->m_dma_req_frame_hdl, NULL,
+	    memp, alloc_len, DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
+	    DDI_DMA_SLEEP, NULL, &cookie, &ncookie) != DDI_DMA_MAPPED) {
+		(void) ddi_dma_mem_free(&mpt->m_acc_req_frame_hdl);
+		ddi_dma_free_handle(&mpt->m_dma_req_frame_hdl);
+		mpt->m_dma_req_frame_hdl = NULL;
+		mptsas_log(mpt, CE_WARN, "Unable to bind DMA resources.");
+		return (DDI_FAILURE);
+	}
+
+	/*
+	 * Store the request frame memory address.  This chip uses this
+	 * address to dma to and from the driver's frame.  The second
+	 * address is the address mpt uses to fill in the frame.
+	 */
+	mpt->m_req_frame_dma_addr = cookie.dmac_laddress;
+	mpt->m_req_frame = memp;
+
+	/*
+	 * Clear the request frame pool.
+	 */
+	bzero(mpt->m_req_frame, alloc_len);
+
+	return (DDI_SUCCESS);
+}
+
+static int
+mptsas_alloc_reply_frames(mptsas_t *mpt)
+{
+	ddi_dma_attr_t		frame_dma_attrs;
+	caddr_t			memp;
+	uint_t			ncookie;
+	ddi_dma_cookie_t	cookie;
+	size_t			alloc_len;
+	size_t			mem_size;
+
+	/*
+	 * The size of the reply frame pool is:
+	 *   Number of Reply Frames * Reply Frame Size
+	 */
+	mem_size = mpt->m_max_replies * mpt->m_reply_frame_size;
+
+	/*
+	 * set the DMA attributes.   System Reply Message Frames must be
+	 * aligned on a 4-byte boundry.  This is the default.
+	 */
+	frame_dma_attrs = mpt->m_msg_dma_attr;
+	frame_dma_attrs.dma_attr_sgllen = 1;
+
+	/*
+	 * allocate the reply frame pool
+	 */
+	if (ddi_dma_alloc_handle(mpt->m_dip, &frame_dma_attrs,
+	    DDI_DMA_SLEEP, NULL, &mpt->m_dma_reply_frame_hdl) != DDI_SUCCESS) {
+		mptsas_log(mpt, CE_WARN,
+		    "Unable to allocate dma handle.");
+		return (DDI_FAILURE);
+	}
+
+	if (ddi_dma_mem_alloc(mpt->m_dma_reply_frame_hdl,
+	    mem_size, &mpt->m_dev_acc_attr, DDI_DMA_CONSISTENT, DDI_DMA_SLEEP,
+	    NULL, (caddr_t *)&memp, &alloc_len, &mpt->m_acc_reply_frame_hdl)
+	    != DDI_SUCCESS) {
+		ddi_dma_free_handle(&mpt->m_dma_reply_frame_hdl);
+		mpt->m_dma_reply_frame_hdl = NULL;
+		mptsas_log(mpt, CE_WARN,
+		    "Unable to allocate reply frames.");
+		return (DDI_FAILURE);
+	}
+
+	if (ddi_dma_addr_bind_handle(mpt->m_dma_reply_frame_hdl, NULL,
+	    memp, alloc_len, DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
+	    DDI_DMA_SLEEP, NULL, &cookie, &ncookie) != DDI_DMA_MAPPED) {
+		(void) ddi_dma_mem_free(&mpt->m_acc_reply_frame_hdl);
+		ddi_dma_free_handle(&mpt->m_dma_reply_frame_hdl);
+		mpt->m_dma_reply_frame_hdl = NULL;
+		mptsas_log(mpt, CE_WARN, "Unable to bind DMA resources.");
+		return (DDI_FAILURE);
+	}
+
+	/*
+	 * Store the reply frame memory address.  This chip uses this
+	 * address to dma to and from the driver's frame.  The second
+	 * address is the address mpt uses to process the frame.
+	 */
+	mpt->m_reply_frame_dma_addr = cookie.dmac_laddress;
+	mpt->m_reply_frame = memp;
+
+	/*
+	 * Clear the reply frame pool.
+	 */
+	bzero(mpt->m_reply_frame, alloc_len);
+
+	return (DDI_SUCCESS);
+}
+
+static int
+mptsas_alloc_free_queue(mptsas_t *mpt)
+{
+	ddi_dma_attr_t		frame_dma_attrs;
+	caddr_t			memp;
+	uint_t			ncookie;
+	ddi_dma_cookie_t	cookie;
+	size_t			alloc_len;
+	size_t			mem_size;
+
+	/*
+	 * The reply free queue size is:
+	 *   Reply Free Queue Depth * 4
+	 * The "4" is the size of one 32 bit address (low part of 64-bit
+	 *   address)
+	 */
+	mem_size = mpt->m_free_queue_depth * 4;
+
+	/*
+	 * set the DMA attributes  The Reply Free Queue must be aligned on a
+	 * 16-byte boundry.
+	 */
+	frame_dma_attrs = mpt->m_msg_dma_attr;
+	frame_dma_attrs.dma_attr_align = 16;
+	frame_dma_attrs.dma_attr_sgllen = 1;
+
+	/*
+	 * allocate the reply free queue
+	 */
+	if (ddi_dma_alloc_handle(mpt->m_dip, &frame_dma_attrs,
+	    DDI_DMA_SLEEP, NULL, &mpt->m_dma_free_queue_hdl) != DDI_SUCCESS) {
+		mptsas_log(mpt, CE_WARN,
+		    "Unable to allocate dma handle.");
+		return (DDI_FAILURE);
+	}
+
+	if (ddi_dma_mem_alloc(mpt->m_dma_free_queue_hdl,
+	    mem_size, &mpt->m_dev_acc_attr, DDI_DMA_CONSISTENT, DDI_DMA_SLEEP,
+	    NULL, (caddr_t *)&memp, &alloc_len, &mpt->m_acc_free_queue_hdl)
+	    != DDI_SUCCESS) {
+		ddi_dma_free_handle(&mpt->m_dma_free_queue_hdl);
+		mpt->m_dma_free_queue_hdl = NULL;
+		mptsas_log(mpt, CE_WARN,
+		    "Unable to allocate free queue.");
+		return (DDI_FAILURE);
+	}
+
+	if (ddi_dma_addr_bind_handle(mpt->m_dma_free_queue_hdl, NULL,
+	    memp, alloc_len, DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
+	    DDI_DMA_SLEEP, NULL, &cookie, &ncookie) != DDI_DMA_MAPPED) {
+		(void) ddi_dma_mem_free(&mpt->m_acc_free_queue_hdl);
+		ddi_dma_free_handle(&mpt->m_dma_free_queue_hdl);
+		mpt->m_dma_free_queue_hdl = NULL;
+		mptsas_log(mpt, CE_WARN, "Unable to bind DMA resources.");
+		return (DDI_FAILURE);
+	}
+
+	/*
+	 * Store the reply free queue memory address.  This chip uses this
+	 * address to read from the reply free queue.  The second address
+	 * is the address mpt uses to manage the queue.
+	 */
+	mpt->m_free_queue_dma_addr = cookie.dmac_laddress;
+	mpt->m_free_queue = memp;
+
+	/*
+	 * Clear the reply free queue memory.
+	 */
+	bzero(mpt->m_free_queue, alloc_len);
+
+	return (DDI_SUCCESS);
+}
+
+static int
+mptsas_alloc_post_queue(mptsas_t *mpt)
+{
+	ddi_dma_attr_t		frame_dma_attrs;
+	caddr_t			memp;
+	uint_t			ncookie;
+	ddi_dma_cookie_t	cookie;
+	size_t			alloc_len;
+	size_t			mem_size;
+
+	/*
+	 * The reply descriptor post queue size is:
+	 *   Reply Descriptor Post Queue Depth * 8
+	 * The "8" is the size of each descriptor (8 bytes or 64 bits).
+	 */
+	mem_size = mpt->m_post_queue_depth * 8;
+
+	/*
+	 * set the DMA attributes.  The Reply Descriptor Post Queue must be
+	 * aligned on a 16-byte boundry.
+	 */
+	frame_dma_attrs = mpt->m_msg_dma_attr;
+	frame_dma_attrs.dma_attr_align = 16;
+	frame_dma_attrs.dma_attr_sgllen = 1;
+
+	/*
+	 * allocate the reply post queue
+	 */
+	if (ddi_dma_alloc_handle(mpt->m_dip, &frame_dma_attrs,
+	    DDI_DMA_SLEEP, NULL, &mpt->m_dma_post_queue_hdl) != DDI_SUCCESS) {
+		mptsas_log(mpt, CE_WARN,
+		    "Unable to allocate dma handle.");
+		return (DDI_FAILURE);
+	}
+
+	if (ddi_dma_mem_alloc(mpt->m_dma_post_queue_hdl,
+	    mem_size, &mpt->m_dev_acc_attr, DDI_DMA_CONSISTENT, DDI_DMA_SLEEP,
+	    NULL, (caddr_t *)&memp, &alloc_len, &mpt->m_acc_post_queue_hdl)
+	    != DDI_SUCCESS) {
+		ddi_dma_free_handle(&mpt->m_dma_post_queue_hdl);
+		mpt->m_dma_post_queue_hdl = NULL;
+		mptsas_log(mpt, CE_WARN,
+		    "Unable to allocate post queue.");
+		return (DDI_FAILURE);
+	}
+
+	if (ddi_dma_addr_bind_handle(mpt->m_dma_post_queue_hdl, NULL,
+	    memp, alloc_len, DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
+	    DDI_DMA_SLEEP, NULL, &cookie, &ncookie) != DDI_DMA_MAPPED) {
+		(void) ddi_dma_mem_free(&mpt->m_acc_post_queue_hdl);
+		ddi_dma_free_handle(&mpt->m_dma_post_queue_hdl);
+		mpt->m_dma_post_queue_hdl = NULL;
+		mptsas_log(mpt, CE_WARN, "Unable to bind DMA resources.");
+		return (DDI_FAILURE);
+	}
+
+	/*
+	 * Store the reply descriptor post queue memory address.  This chip
+	 * uses this address to write to the reply descriptor post queue.  The
+	 * second address is the address mpt uses to manage the queue.
+	 */
+	mpt->m_post_queue_dma_addr = cookie.dmac_laddress;
+	mpt->m_post_queue = memp;
+
+	/*
+	 * Clear the reply post queue memory.
+	 */
+	bzero(mpt->m_post_queue, alloc_len);
+
+	return (DDI_SUCCESS);
+}
+
+static int
+mptsas_alloc_extra_sgl_frame(mptsas_t *mpt, mptsas_cmd_t *cmd)
+{
+	mptsas_cache_frames_t	*frames = NULL;
+	if (cmd->cmd_extra_frames == NULL) {
+		frames = kmem_cache_alloc(mpt->m_cache_frames, KM_NOSLEEP);
+		if (frames == NULL) {
+			return (DDI_FAILURE);
+		}
+		cmd->cmd_extra_frames = frames;
+	}
+	return (DDI_SUCCESS);
+}
+
+static void
+mptsas_free_extra_sgl_frame(mptsas_t *mpt, mptsas_cmd_t *cmd)
+{
+	if (cmd->cmd_extra_frames) {
+		kmem_cache_free(mpt->m_cache_frames,
+		    (void *)cmd->cmd_extra_frames);
+		cmd->cmd_extra_frames = NULL;
+	}
+}
+
+static void
+mptsas_cfg_fini(mptsas_t *mpt)
+{
+	NDBG0(("mptsas_cfg_fini"));
+	ddi_regs_map_free(&mpt->m_datap);
+}
+
+static void
+mptsas_hba_fini(mptsas_t *mpt)
+{
+	NDBG0(("mptsas_hba_fini"));
+
+	/*
+	 * Disable any bus mastering ability (i.e: DMA) prior to freeing any
+	 * allocated DMA resources.
+	 */
+	if (mpt->m_config_handle != NULL)
+		mptsas_disable_bus_master(mpt);
+
+	/*
+	 * Free up any allocated memory
+	 */
+	if (mpt->m_dma_req_frame_hdl != NULL) {
+		(void) ddi_dma_unbind_handle(mpt->m_dma_req_frame_hdl);
+		ddi_dma_mem_free(&mpt->m_acc_req_frame_hdl);
+		ddi_dma_free_handle(&mpt->m_dma_req_frame_hdl);
+		mpt->m_dma_req_frame_hdl = NULL;
+	}
+
+	if (mpt->m_dma_reply_frame_hdl != NULL) {
+		(void) ddi_dma_unbind_handle(mpt->m_dma_reply_frame_hdl);
+		ddi_dma_mem_free(&mpt->m_acc_reply_frame_hdl);
+		ddi_dma_free_handle(&mpt->m_dma_reply_frame_hdl);
+		mpt->m_dma_reply_frame_hdl = NULL;
+	}
+
+	if (mpt->m_dma_free_queue_hdl != NULL) {
+		(void) ddi_dma_unbind_handle(mpt->m_dma_free_queue_hdl);
+		ddi_dma_mem_free(&mpt->m_acc_free_queue_hdl);
+		ddi_dma_free_handle(&mpt->m_dma_free_queue_hdl);
+		mpt->m_dma_free_queue_hdl = NULL;
+	}
+
+	if (mpt->m_dma_post_queue_hdl != NULL) {
+		(void) ddi_dma_unbind_handle(mpt->m_dma_post_queue_hdl);
+		ddi_dma_mem_free(&mpt->m_acc_post_queue_hdl);
+		ddi_dma_free_handle(&mpt->m_dma_post_queue_hdl);
+		mpt->m_dma_post_queue_hdl = NULL;
+	}
+
+	if (mpt->m_replyh_args != NULL) {
+		kmem_free(mpt->m_replyh_args, sizeof (m_replyh_arg_t)
+		    * mpt->m_max_replies);
+	}
+}
+
+static int
+mptsas_name_child(dev_info_t *lun_dip, char *name, int len)
+{
+	int		lun = 0;
+	char		*sas_wwn = NULL;
+	int		phynum = -1;
+	int		reallen = 0;
+
+	/* Get the target num */
+	lun = ddi_prop_get_int(DDI_DEV_T_ANY, lun_dip, DDI_PROP_DONTPASS,
+	    LUN_PROP, 0);
+
+	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, lun_dip, DDI_PROP_DONTPASS,
+	    "target-port", &sas_wwn) == DDI_PROP_SUCCESS) {
+		/*
+		 * Stick in the address of the form "wWWN,LUN"
+		 */
+		reallen = snprintf(name, len, "w%016s,%x", sas_wwn, lun);
+		ddi_prop_free(sas_wwn);
+	} else if ((phynum = ddi_prop_get_int(DDI_DEV_T_ANY, lun_dip,
+	    DDI_PROP_DONTPASS, "sata-phy", -1)) != -1) {
+		/*
+		 * Stick in the address of form "pPHY,LUN"
+		 */
+		reallen = snprintf(name, len, "p%x,%x", phynum, lun);
+	} else {
+		return (DDI_FAILURE);
+	}
+
+	ASSERT(reallen < len);
+	if (reallen >= len) {
+		mptsas_log(0, CE_WARN, "!mptsas_get_name: name parameter "
+		    "length too small, it needs to be %d bytes", reallen + 1);
+	}
+	return (DDI_SUCCESS);
+}
+
+/*
+ * tran_tgt_init(9E) - target device instance initialization
+ */
+static int
+mptsas_scsi_tgt_init(dev_info_t *hba_dip, dev_info_t *tgt_dip,
+    scsi_hba_tran_t *hba_tran, struct scsi_device *sd)
+{
+#ifndef __lock_lint
+	_NOTE(ARGUNUSED(hba_tran))
+#endif
+
+	/*
+	 * At this point, the scsi_device structure already exists
+	 * and has been initialized.
+	 *
+	 * Use this function to allocate target-private data structures,
+	 * if needed by this HBA.  Add revised flow-control and queue
+	 * properties for child here, if desired and if you can tell they
+	 * support tagged queueing by now.
+	 */
+	mptsas_t		*mpt;
+	int			lun = sd->sd_address.a_lun;
+	mdi_pathinfo_t		*pip = NULL;
+	mptsas_tgt_private_t	*tgt_private = NULL;
+	mptsas_target_t		*ptgt = NULL;
+	char			*psas_wwn = NULL;
+	int			phymask = 0;
+	uint64_t		sas_wwn = 0;
+	mpt = SDEV2MPT(sd);
+
+	ASSERT(scsi_hba_iport_unit_address(hba_dip) != 0);
+
+	NDBG0(("mptsas_scsi_tgt_init: hbadip=0x%p tgtdip=0x%p lun=%d",
+	    (void *)hba_dip, (void *)tgt_dip, lun));
+
+	if (ndi_dev_is_persistent_node(tgt_dip) == 0) {
+		(void) ndi_merge_node(tgt_dip, mptsas_name_child);
+		ddi_set_name_addr(tgt_dip, NULL);
+		return (DDI_FAILURE);
+	}
+	/*
+	 * phymask is 0 means the virtual port for RAID
+	 */
+	phymask = ddi_prop_get_int(DDI_DEV_T_ANY, hba_dip, 0,
+	    "phymask", 0);
+	if (mdi_component_is_client(tgt_dip, NULL) == MDI_SUCCESS) {
+		if ((pip = (void *)(sd->sd_private)) == NULL) {
+			/*
+			 * Very bad news if this occurs. Somehow scsi_vhci has
+			 * lost the pathinfo node for this target.
+			 */
+			return (DDI_NOT_WELL_FORMED);
+		}
+
+		if (mdi_prop_lookup_int(pip, LUN_PROP, &lun) !=
+		    DDI_PROP_SUCCESS) {
+			mptsas_log(mpt, CE_WARN, "Get lun property failed\n");
+			return (DDI_FAILURE);
+		}
+
+		if (mdi_prop_lookup_string(pip, "target-port", &psas_wwn) ==
+		    MDI_SUCCESS) {
+			if (scsi_wwnstr_to_wwn(psas_wwn, &sas_wwn)) {
+				sas_wwn = 0;
+			}
+			(void) mdi_prop_free(psas_wwn);
+		}
+	} else {
+		lun = ddi_prop_get_int(DDI_DEV_T_ANY, tgt_dip,
+		    DDI_PROP_DONTPASS, LUN_PROP, 0);
+		if (ddi_prop_lookup_string(DDI_DEV_T_ANY, tgt_dip,
+		    DDI_PROP_DONTPASS, "target-port", &psas_wwn) ==
+		    DDI_PROP_SUCCESS) {
+			if (scsi_wwnstr_to_wwn(psas_wwn, &sas_wwn)) {
+				sas_wwn = 0;
+			}
+			ddi_prop_free(psas_wwn);
+		} else {
+			sas_wwn = 0;
+		}
+	}
+	ASSERT((sas_wwn != 0) || (phymask != 0));
+	mutex_enter(&mpt->m_mutex);
+	ptgt = mptsas_hash_search(&mpt->m_active->m_tgttbl, sas_wwn, phymask);
+	mutex_exit(&mpt->m_mutex);
+	if (ptgt == NULL) {
+		mptsas_log(mpt, CE_WARN, "!tgt_init: target doesn't exist or "
+		    "gone already! phymask:%x, saswwn %"PRIx64, phymask,
+		    sas_wwn);
+		return (DDI_FAILURE);
+	}
+	if (hba_tran->tran_tgt_private == NULL) {
+		tgt_private = kmem_zalloc(sizeof (mptsas_tgt_private_t),
+		    KM_SLEEP);
+		tgt_private->t_lun = lun;
+		tgt_private->t_private = ptgt;
+		hba_tran->tran_tgt_private = tgt_private;
+	}
+
+	if (mdi_component_is_client(tgt_dip, NULL) == MDI_SUCCESS) {
+		return (DDI_SUCCESS);
+	}
+	mutex_enter(&mpt->m_mutex);
+
+	if (ptgt->m_deviceinfo &
+	    (MPI2_SAS_DEVICE_INFO_SATA_DEVICE |
+	    MPI2_SAS_DEVICE_INFO_ATAPI_DEVICE)) {
+		uchar_t *inq89 = NULL;
+		int inq89_len = 0x238;
+		int reallen = 0;
+		int rval = 0;
+		struct sata_id *sid = NULL;
+		char model[SATA_ID_MODEL_LEN + 1];
+		char fw[SATA_ID_FW_LEN + 1];
+		char *vid, *pid;
+		int i;
+
+		mutex_exit(&mpt->m_mutex);
+		/*
+		 * According SCSI/ATA Translation -2 (SAT-2) revision 01a
+		 * chapter 12.4.2 VPD page 89h includes 512 bytes ATA IDENTIFY
+		 * DEVICE data or ATA IDENTIFY PACKET DEVICE data.
+		 */
+		inq89 = kmem_zalloc(inq89_len, KM_SLEEP);
+		rval = mptsas_inquiry(mpt, ptgt, 0, 0x89,
+		    inq89, inq89_len, &reallen, 1);
+
+		if (rval != 0) {
+			if (inq89 != NULL) {
+				kmem_free(inq89, inq89_len);
+			}
+
+			mptsas_log(mpt, CE_WARN, "!mptsas request inquiry page "
+			    "0x89 for SATA target:%x failed!", ptgt->m_devhdl);
+			return (DDI_SUCCESS);
+		}
+		sid = (void *)(&inq89[60]);
+
+		swab(sid->ai_model, model, SATA_ID_MODEL_LEN);
+		swab(sid->ai_fw, fw, SATA_ID_FW_LEN);
+
+		model[SATA_ID_MODEL_LEN] = 0;
+		fw[SATA_ID_FW_LEN] = 0;
+
+		/*
+		 * split model into into vid/pid
+		 */
+		for (i = 0, pid = model; i < SATA_ID_MODEL_LEN; i++, pid++)
+			if ((*pid == ' ') || (*pid == '\t'))
+				break;
+		if (i < SATA_ID_MODEL_LEN) {
+			vid = model;
+			/*
+			 * terminate vid, establish pid
+			 */
+			*pid++ = 0;
+		} else {
+			/*
+			 * vid will stay "ATA     ", the rule is same
+			 * as sata framework implementation.
+			 */
+			vid = NULL;
+			/*
+			 * model is all pid
+			 */
+			pid = model;
+		}
+
+		/*
+		 * override SCSA "inquiry-*" properties
+		 */
+		if (vid)
+			(void) scsi_hba_prop_update_inqstring(sd,
+			    INQUIRY_VENDOR_ID, vid, strlen(vid));
+		if (pid)
+			(void) scsi_hba_prop_update_inqstring(sd,
+			    INQUIRY_PRODUCT_ID, pid, strlen(pid));
+		(void) scsi_hba_prop_update_inqstring(sd,
+		    INQUIRY_REVISION_ID, fw, strlen(fw));
+
+		if (inq89 != NULL) {
+			kmem_free(inq89, inq89_len);
+		}
+	} else {
+		mutex_exit(&mpt->m_mutex);
+	}
+
+	return (DDI_SUCCESS);
+}
+/*
+ * tran_tgt_free(9E) - target device instance deallocation
+ */
+static void
+mptsas_scsi_tgt_free(dev_info_t *hba_dip, dev_info_t *tgt_dip,
+    scsi_hba_tran_t *hba_tran, struct scsi_device *sd)
+{
+#ifndef __lock_lint
+	_NOTE(ARGUNUSED(hba_dip, tgt_dip, hba_tran, sd))
+#endif
+
+	mptsas_tgt_private_t	*tgt_private = hba_tran->tran_tgt_private;
+
+	if (tgt_private != NULL) {
+		kmem_free(tgt_private, sizeof (mptsas_tgt_private_t));
+		hba_tran->tran_tgt_private = NULL;
+	}
+}
+
+/*
+ * scsi_pkt handling
+ *
+ * Visible to the external world via the transport structure.
+ */
+
+/*
+ * Notes:
+ *	- transport the command to the addressed SCSI target/lun device
+ *	- normal operation is to schedule the command to be transported,
+ *	  and return TRAN_ACCEPT if this is successful.
+ *	- if NO_INTR, tran_start must poll device for command completion
+ */
+static int
+mptsas_scsi_start(struct scsi_address *ap, struct scsi_pkt *pkt)
+{
+#ifndef __lock_lint
+	_NOTE(ARGUNUSED(ap))
+#endif
+	mptsas_t	*mpt = PKT2MPT(pkt);
+	mptsas_cmd_t	*cmd = PKT2CMD(pkt);
+	int		rval;
+	mptsas_target_t	*ptgt = cmd->cmd_tgt_addr;
+
+	NDBG1(("mptsas_scsi_start: pkt=0x%p", (void *)pkt));
+	ASSERT(ptgt);
+	if (ptgt == NULL)
+		return (TRAN_FATAL_ERROR);
+
+	/*
+	 * prepare the pkt before taking mutex.
+	 */
+	rval = mptsas_prepare_pkt(cmd);
+	if (rval != TRAN_ACCEPT) {
+		return (rval);
+	}
+
+	/*
+	 * Send the command to target/lun, however your HBA requires it.
+	 * If busy, return TRAN_BUSY; if there's some other formatting error
+	 * in the packet, return TRAN_BADPKT; otherwise, fall through to the
+	 * return of TRAN_ACCEPT.
+	 *
+	 * Remember that access to shared resources, including the mptsas_t
+	 * data structure and the HBA hardware registers, must be protected
+	 * with mutexes, here and everywhere.
+	 *
+	 * Also remember that at interrupt time, you'll get an argument
+	 * to the interrupt handler which is a pointer to your mptsas_t
+	 * structure; you'll have to remember which commands are outstanding
+	 * and which scsi_pkt is the currently-running command so the
+	 * interrupt handler can refer to the pkt to set completion
+	 * status, call the target driver back through pkt_comp, etc.
+	 *
+	 * If the instance lock is held by other thread, don't spin to wait
+	 * for it. Instead, queue the cmd and next time when the instance lock
+	 * is not held, accept all the queued cmd. A extra tx_waitq is
+	 * introduced to protect the queue.
+	 *
+	 * The polled cmd will not be queud and accepted as usual.
+	 *
+	 * Under the tx_waitq mutex, record whether a thread is draining
+	 * the tx_waitq.  An IO requesting thread that finds the instance
+	 * mutex contended appends to the tx_waitq and while holding the
+	 * tx_wait mutex, if the draining flag is not set, sets it and then
+	 * proceeds to spin for the instance mutex. This scheme ensures that
+	 * the last cmd in a burst be processed.
+	 *
+	 * we enable this feature only when the helper threads are enabled,
+	 * at which we think the loads are heavy.
+	 *
+	 * per instance mutex m_tx_waitq_mutex is introduced to protect the
+	 * m_tx_waitqtail, m_tx_waitq, m_tx_draining.
+	 */
+
+	if (mpt->m_doneq_thread_n) {
+		if (mutex_tryenter(&mpt->m_mutex) != 0) {
+			rval = mptsas_accept_txwq_and_pkt(mpt, cmd);
+			mutex_exit(&mpt->m_mutex);
+		} else if (cmd->cmd_pkt_flags & FLAG_NOINTR) {
+			mutex_enter(&mpt->m_mutex);
+			rval = mptsas_accept_txwq_and_pkt(mpt, cmd);
+			mutex_exit(&mpt->m_mutex);
+		} else {
+			mutex_enter(&mpt->m_tx_waitq_mutex);
+			/*
+			 * ptgt->m_dr_flag is protected by m_mutex or
+			 * m_tx_waitq_mutex. In this case, m_tx_waitq_mutex
+			 * is acquired.
+			 */
+			if (ptgt->m_dr_flag == MPTSAS_DR_INTRANSITION) {
+				if (cmd->cmd_pkt_flags & FLAG_NOQUEUE) {
+					/*
+					 * The command should be allowed to
+					 * retry by returning TRAN_BUSY to
+					 * to stall the I/O's which come from
+					 * scsi_vhci since the device/path is
+					 * in unstable state now.
+					 */
+					mutex_exit(&mpt->m_tx_waitq_mutex);
+					return (TRAN_BUSY);
+				} else {
+					/*
+					 * The device is offline, just fail the
+					 * command by returning
+					 * TRAN_FATAL_ERROR.
+					 */
+					mutex_exit(&mpt->m_tx_waitq_mutex);
+					return (TRAN_FATAL_ERROR);
+				}
+			}
+			if (mpt->m_tx_draining) {
+				cmd->cmd_flags |= CFLAG_TXQ;
+				*mpt->m_tx_waitqtail = cmd;
+				mpt->m_tx_waitqtail = &cmd->cmd_linkp;
+				mutex_exit(&mpt->m_tx_waitq_mutex);
+			} else { /* drain the queue */
+				mpt->m_tx_draining = 1;
+				mutex_exit(&mpt->m_tx_waitq_mutex);
+				mutex_enter(&mpt->m_mutex);
+				rval = mptsas_accept_txwq_and_pkt(mpt, cmd);
+				mutex_exit(&mpt->m_mutex);
+			}
+		}
+	} else {
+		mutex_enter(&mpt->m_mutex);
+		/*
+		 * ptgt->m_dr_flag is protected by m_mutex or m_tx_waitq_mutex
+		 * in this case, m_mutex is acquired.
+		 */
+		if (ptgt->m_dr_flag == MPTSAS_DR_INTRANSITION) {
+			if (cmd->cmd_pkt_flags & FLAG_NOQUEUE) {
+				/*
+				 * commands should be allowed to retry by
+				 * returning TRAN_BUSY to stall the I/O's
+				 * which come from scsi_vhci since the device/
+				 * path is in unstable state now.
+				 */
+				mutex_exit(&mpt->m_mutex);
+				return (TRAN_BUSY);
+			} else {
+				/*
+				 * The device is offline, just fail the
+				 * command by returning TRAN_FATAL_ERROR.
+				 */
+				mutex_exit(&mpt->m_mutex);
+				return (TRAN_FATAL_ERROR);
+			}
+		}
+		rval = mptsas_accept_pkt(mpt, cmd);
+		mutex_exit(&mpt->m_mutex);
+	}
+
+	return (rval);
+}
+
+/*
+ * Accept all the queued cmds(if any) before accept the current one.
+ */
+static int
+mptsas_accept_txwq_and_pkt(mptsas_t *mpt, mptsas_cmd_t *cmd)
+{
+	int rval;
+	mptsas_target_t	*ptgt = cmd->cmd_tgt_addr;
+
+	ASSERT(mutex_owned(&mpt->m_mutex));
+	/*
+	 * The call to mptsas_accept_tx_waitq() must always be performed
+	 * because that is where mpt->m_tx_draining is cleared.
+	 */
+	mutex_enter(&mpt->m_tx_waitq_mutex);
+	mptsas_accept_tx_waitq(mpt);
+	mutex_exit(&mpt->m_tx_waitq_mutex);
+	/*
+	 * ptgt->m_dr_flag is protected by m_mutex or m_tx_waitq_mutex
+	 * in this case, m_mutex is acquired.
+	 */
+	if (ptgt->m_dr_flag == MPTSAS_DR_INTRANSITION) {
+		if (cmd->cmd_pkt_flags & FLAG_NOQUEUE) {
+			/*
+			 * The command should be allowed to retry by returning
+			 * TRAN_BUSY to stall the I/O's which come from
+			 * scsi_vhci since the device/path is in unstable state
+			 * now.
+			 */
+			return (TRAN_BUSY);
+		} else {
+			/*
+			 * The device is offline, just fail the command by
+			 * return TRAN_FATAL_ERROR.
+			 */
+			return (TRAN_FATAL_ERROR);
+		}
+	}
+	rval = mptsas_accept_pkt(mpt, cmd);
+
+	return (rval);
+}
+
+static int
+mptsas_accept_pkt(mptsas_t *mpt, mptsas_cmd_t *cmd)
+{
+	int		rval = TRAN_ACCEPT;
+	mptsas_target_t	*ptgt = cmd->cmd_tgt_addr;
+
+	NDBG1(("mptsas_accept_pkt: cmd=0x%p", (void *)cmd));
+
+	ASSERT(mutex_owned(&mpt->m_mutex));
+
+	if ((cmd->cmd_flags & CFLAG_PREPARED) == 0) {
+		rval = mptsas_prepare_pkt(cmd);
+		if (rval != TRAN_ACCEPT) {
+			cmd->cmd_flags &= ~CFLAG_TRANFLAG;
+			return (rval);
+		}
+	}
+
+	/*
+	 * reset the throttle if we were draining
+	 */
+	if ((ptgt->m_t_ncmds == 0) &&
+	    (ptgt->m_t_throttle == DRAIN_THROTTLE)) {
+		NDBG23(("reset throttle"));
+		ASSERT(ptgt->m_reset_delay == 0);
+		mptsas_set_throttle(mpt, ptgt, MAX_THROTTLE);
+	}
+
+	/*
+	 * If device handle has already been invalidated, just
+	 * fail the command. In theory, command from scsi_vhci
+	 * client is impossible send down command with invalid
+	 * devhdl since devhdl is set after path offline, target
+	 * driver is not suppose to select a offlined path.
+	 */
+	if (ptgt->m_devhdl == MPTSAS_INVALID_DEVHDL) {
+		NDBG20(("rejecting command, it might because invalid devhdl "
+		    "request."));
+		mptsas_set_pkt_reason(mpt, cmd, CMD_DEV_GONE, STAT_TERMINATED);
+		if (cmd->cmd_flags & CFLAG_TXQ) {
+			mptsas_doneq_add(mpt, cmd);
+			mptsas_doneq_empty(mpt);
+			return (rval);
+		} else {
+			return (TRAN_FATAL_ERROR);
+		}
+	}
+	/*
+	 * The first case is the normal case.  mpt gets a command from the
+	 * target driver and starts it.
+	 * Since SMID 0 is reserved and the TM slot is reserved, the actual max
+	 * commands is m_max_requests - 2.
+	 */
+	if ((mpt->m_ncmds <= (mpt->m_max_requests - 2)) &&
+	    (ptgt->m_t_throttle > HOLD_THROTTLE) &&
+	    (ptgt->m_t_ncmds < ptgt->m_t_throttle) &&
+	    (ptgt->m_reset_delay == 0) &&
+	    (ptgt->m_t_nwait == 0) &&
+	    ((cmd->cmd_pkt_flags & FLAG_NOINTR) == 0)) {
+		if (mptsas_save_cmd(mpt, cmd) == TRUE) {
+			(void) mptsas_start_cmd(mpt, cmd);
+		} else {
+			mptsas_waitq_add(mpt, cmd);
+		}
+	} else {
+		/*
+		 * Add this pkt to the work queue
+		 */
+		mptsas_waitq_add(mpt, cmd);
+
+		if (cmd->cmd_pkt_flags & FLAG_NOINTR) {
+			(void) mptsas_poll(mpt, cmd, MPTSAS_POLL_TIME);
+
+			/*
+			 * Only flush the doneq if this is not a TM
+			 * cmd.  For TM cmds the flushing of the
+			 * doneq will be done in those routines.
+			 */
+			if ((cmd->cmd_flags & CFLAG_TM_CMD) == 0) {
+				mptsas_doneq_empty(mpt);
+			}
+		}
+	}
+	return (rval);
+}
+
+int
+mptsas_save_cmd(mptsas_t *mpt, mptsas_cmd_t *cmd)
+{
+	mptsas_slots_t	*slots;
+	int		slot;
+	mptsas_target_t	*ptgt = cmd->cmd_tgt_addr;
+
+	ASSERT(mutex_owned(&mpt->m_mutex));
+	slots = mpt->m_active;
+
+	/*
+	 * Account for reserved TM request slot and reserved SMID of 0.
+	 */
+	ASSERT(slots->m_n_slots == (mpt->m_max_requests - 2));
+
+	/*
+	 * m_tags is equivalent to the SMID when sending requests.  Since the
+	 * SMID cannot be 0, start out at one if rolling over past the size
+	 * of the request queue depth.  Also, don't use the last SMID, which is
+	 * reserved for TM requests.
+	 */
+	slot = (slots->m_tags)++;
+	if (slots->m_tags > slots->m_n_slots) {
+		slots->m_tags = 1;
+	}
+
+alloc_tag:
+	/* Validate tag, should never fail. */
+	if (slots->m_slot[slot] == NULL) {
+		/*
+		 * Make sure SMID is not using reserved value of 0
+		 * and the TM request slot.
+		 */
+		ASSERT((slot > 0) && (slot <= slots->m_n_slots));
+		cmd->cmd_slot = slot;
+		slots->m_slot[slot] = cmd;
+		mpt->m_ncmds++;
+
+		/*
+		 * only increment per target ncmds if this is not a
+		 * command that has no target associated with it (i.e. a
+		 * event acknoledgment)
+		 */
+		if ((cmd->cmd_flags & CFLAG_CMDIOC) == 0) {
+			ptgt->m_t_ncmds++;
+		}
+		cmd->cmd_active_timeout = cmd->cmd_pkt->pkt_time;
+
+		return (TRUE);
+	} else {
+		int i;
+
+		/*
+		 * If slot in use, scan until a free one is found. Don't use 0
+		 * or final slot, which is reserved for TM requests.
+		 */
+		for (i = 0; i < slots->m_n_slots; i++) {
+			slot = slots->m_tags;
+			if (++(slots->m_tags) > slots->m_n_slots) {
+				slots->m_tags = 1;
+			}
+			if (slots->m_slot[slot] == NULL) {
+				NDBG22(("found free slot %d", slot));
+				goto alloc_tag;
+			}
+		}
+	}
+	return (FALSE);
+}
+
+/*
+ * prepare the pkt:
+ * the pkt may have been resubmitted or just reused so
+ * initialize some fields and do some checks.
+ */
+static int
+mptsas_prepare_pkt(mptsas_cmd_t *cmd)
+{
+	struct scsi_pkt	*pkt = CMD2PKT(cmd);
+
+	NDBG1(("mptsas_prepare_pkt: cmd=0x%p", (void *)cmd));
+
+	/*
+	 * Reinitialize some fields that need it; the packet may
+	 * have been resubmitted
+	 */
+	pkt->pkt_reason = CMD_CMPLT;
+	pkt->pkt_state = 0;
+	pkt->pkt_statistics = 0;
+	pkt->pkt_resid = 0;
+	cmd->cmd_age = 0;
+	cmd->cmd_pkt_flags = pkt->pkt_flags;
+
+	/*
+	 * zero status byte.
+	 */
+	*(pkt->pkt_scbp) = 0;
+
+	if (cmd->cmd_flags & CFLAG_DMAVALID) {
+		pkt->pkt_resid = cmd->cmd_dmacount;
+
+		/*
+		 * consistent packets need to be sync'ed first
+		 * (only for data going out)
+		 */
+		if ((cmd->cmd_flags & CFLAG_CMDIOPB) &&
+		    (cmd->cmd_flags & CFLAG_DMASEND)) {
+			(void) ddi_dma_sync(cmd->cmd_dmahandle, 0, 0,
+			    DDI_DMA_SYNC_FORDEV);
+		}
+	}
+
+	cmd->cmd_flags =
+	    (cmd->cmd_flags & ~(CFLAG_TRANFLAG)) |
+	    CFLAG_PREPARED | CFLAG_IN_TRANSPORT;
+
+	return (TRAN_ACCEPT);
+}
+
+/*
+ * tran_init_pkt(9E) - allocate scsi_pkt(9S) for command
+ *
+ * One of three possibilities:
+ *	- allocate scsi_pkt
+ *	- allocate scsi_pkt and DMA resources
+ *	- allocate DMA resources to an already-allocated pkt
+ */
+static struct scsi_pkt *
+mptsas_scsi_init_pkt(struct scsi_address *ap, struct scsi_pkt *pkt,
+    struct buf *bp, int cmdlen, int statuslen, int tgtlen, int flags,
+    int (*callback)(), caddr_t arg)
+{
+	mptsas_cmd_t		*cmd, *new_cmd;
+	mptsas_t		*mpt = ADDR2MPT(ap);
+	int			failure = 1;
+	uint_t			oldcookiec;
+	mptsas_target_t		*ptgt = NULL;
+	int			rval;
+	mptsas_tgt_private_t	*tgt_private;
+	int			kf;
+
+	kf = (callback == SLEEP_FUNC)? KM_SLEEP: KM_NOSLEEP;
+
+	tgt_private = (mptsas_tgt_private_t *)ap->a_hba_tran->
+	    tran_tgt_private;
+	ASSERT(tgt_private != NULL);
+	if (tgt_private == NULL) {
+		return (NULL);
+	}
+	ptgt = tgt_private->t_private;
+	ASSERT(ptgt != NULL);
+	if (ptgt == NULL)
+		return (NULL);
+	ap->a_target = ptgt->m_devhdl;
+	ap->a_lun = tgt_private->t_lun;
+
+	ASSERT(callback == NULL_FUNC || callback == SLEEP_FUNC);
+#ifdef MPTSAS_TEST_EXTRN_ALLOC
+	statuslen *= 100; tgtlen *= 4;
+#endif
+	NDBG3(("mptsas_scsi_init_pkt:\n"
+	    "\ttgt=%d in=0x%p bp=0x%p clen=%d slen=%d tlen=%d flags=%x",
+	    ap->a_target, (void *)pkt, (void *)bp,
+	    cmdlen, statuslen, tgtlen, flags));
+
+	/*
+	 * Allocate the new packet.
+	 */
+	if (pkt == NULL) {
+		ddi_dma_handle_t	save_dma_handle;
+		ddi_dma_handle_t	save_arq_dma_handle;
+		struct buf		*save_arq_bp;
+		ddi_dma_cookie_t	save_arqcookie;
+
+		cmd = kmem_cache_alloc(mpt->m_kmem_cache, kf);
+
+		if (cmd) {
+			save_dma_handle = cmd->cmd_dmahandle;
+			save_arq_dma_handle = cmd->cmd_arqhandle;
+			save_arq_bp = cmd->cmd_arq_buf;
+			save_arqcookie = cmd->cmd_arqcookie;
+			bzero(cmd, sizeof (*cmd) + scsi_pkt_size());
+			cmd->cmd_dmahandle = save_dma_handle;
+			cmd->cmd_arqhandle = save_arq_dma_handle;
+			cmd->cmd_arq_buf = save_arq_bp;
+			cmd->cmd_arqcookie = save_arqcookie;
+
+			pkt = (void *)((uchar_t *)cmd +
+			    sizeof (struct mptsas_cmd));
+			pkt->pkt_ha_private = (opaque_t)cmd;
+			pkt->pkt_address = *ap;
+			pkt->pkt_private = (opaque_t)cmd->cmd_pkt_private;
+			pkt->pkt_scbp = (opaque_t)&cmd->cmd_scb;
+			pkt->pkt_cdbp = (opaque_t)&cmd->cmd_cdb;
+			cmd->cmd_pkt = (struct scsi_pkt *)pkt;
+			cmd->cmd_cdblen = (uchar_t)cmdlen;
+			cmd->cmd_scblen = statuslen;
+			cmd->cmd_rqslen = SENSE_LENGTH;
+			cmd->cmd_tgt_addr = ptgt;
+			failure = 0;
+		}
+
+		if (failure || (cmdlen > sizeof (cmd->cmd_cdb)) ||
+		    (tgtlen > PKT_PRIV_LEN) ||
+		    (statuslen > EXTCMDS_STATUS_SIZE)) {
+			if (failure == 0) {
+				/*
+				 * if extern alloc fails, all will be
+				 * deallocated, including cmd
+				 */
+				failure = mptsas_pkt_alloc_extern(mpt, cmd,
+				    cmdlen, tgtlen, statuslen, kf);
+			}
+			if (failure) {
+				/*
+				 * if extern allocation fails, it will
+				 * deallocate the new pkt as well
+				 */
+				return (NULL);
+			}
+		}
+		new_cmd = cmd;
+
+	} else {
+		cmd = PKT2CMD(pkt);
+		new_cmd = NULL;
+	}
+
+
+	/* grab cmd->cmd_cookiec here as oldcookiec */
+
+	oldcookiec = cmd->cmd_cookiec;
+
+	/*
+	 * If the dma was broken up into PARTIAL transfers cmd_nwin will be
+	 * greater than 0 and we'll need to grab the next dma window
+	 */
+	/*
+	 * SLM-not doing extra command frame right now; may add later
+	 */
+
+	if (cmd->cmd_nwin > 0) {
+
+		/*
+		 * Make sure we havn't gone past the the total number
+		 * of windows
+		 */
+		if (++cmd->cmd_winindex >= cmd->cmd_nwin) {
+			return (NULL);
+		}
+		if (ddi_dma_getwin(cmd->cmd_dmahandle, cmd->cmd_winindex,
+		    &cmd->cmd_dma_offset, &cmd->cmd_dma_len,
+		    &cmd->cmd_cookie, &cmd->cmd_cookiec) == DDI_FAILURE) {
+			return (NULL);
+		}
+		goto get_dma_cookies;
+	}
+
+
+	if (flags & PKT_XARQ) {
+		cmd->cmd_flags |= CFLAG_XARQ;
+	}
+
+	/*
+	 * DMA resource allocation.  This version assumes your
+	 * HBA has some sort of bus-mastering or onboard DMA capability, with a
+	 * scatter-gather list of length MPTSAS_MAX_DMA_SEGS, as given in the
+	 * ddi_dma_attr_t structure and passed to scsi_impl_dmaget.
+	 */
+	if (bp && (bp->b_bcount != 0) &&
+	    (cmd->cmd_flags & CFLAG_DMAVALID) == 0) {
+
+		int	cnt, dma_flags;
+		mptti_t	*dmap;		/* ptr to the S/G list */
+
+		/*
+		 * Set up DMA memory and position to the next DMA segment.
+		 */
+		ASSERT(cmd->cmd_dmahandle != NULL);
+
+		if (bp->b_flags & B_READ) {
+			dma_flags = DDI_DMA_READ;
+			cmd->cmd_flags &= ~CFLAG_DMASEND;
+		} else {
+			dma_flags = DDI_DMA_WRITE;
+			cmd->cmd_flags |= CFLAG_DMASEND;
+		}
+		if (flags & PKT_CONSISTENT) {
+			cmd->cmd_flags |= CFLAG_CMDIOPB;
+			dma_flags |= DDI_DMA_CONSISTENT;
+		}
+
+		if (flags & PKT_DMA_PARTIAL) {
+			dma_flags |= DDI_DMA_PARTIAL;
+		}
+
+		/*
+		 * workaround for byte hole issue on psycho and
+		 * schizo pre 2.1
+		 */
+		if ((bp->b_flags & B_READ) && ((bp->b_flags &
+		    (B_PAGEIO|B_REMAPPED)) != B_PAGEIO) &&
+		    ((uintptr_t)bp->b_un.b_addr & 0x7)) {
+			dma_flags |= DDI_DMA_CONSISTENT;
+		}
+
+		rval = ddi_dma_buf_bind_handle(cmd->cmd_dmahandle, bp,
+		    dma_flags, callback, arg,
+		    &cmd->cmd_cookie, &cmd->cmd_cookiec);
+		if (rval == DDI_DMA_PARTIAL_MAP) {
+			(void) ddi_dma_numwin(cmd->cmd_dmahandle,
+			    &cmd->cmd_nwin);
+			cmd->cmd_winindex = 0;
+			(void) ddi_dma_getwin(cmd->cmd_dmahandle,
+			    cmd->cmd_winindex, &cmd->cmd_dma_offset,
+			    &cmd->cmd_dma_len, &cmd->cmd_cookie,
+			    &cmd->cmd_cookiec);
+		} else if (rval && (rval != DDI_DMA_MAPPED)) {
+			switch (rval) {
+			case DDI_DMA_NORESOURCES:
+				bioerror(bp, 0);
+				break;
+			case DDI_DMA_BADATTR:
+			case DDI_DMA_NOMAPPING:
+				bioerror(bp, EFAULT);
+				break;
+			case DDI_DMA_TOOBIG:
+			default:
+				bioerror(bp, EINVAL);
+				break;
+			}
+			cmd->cmd_flags &= ~CFLAG_DMAVALID;
+			if (new_cmd) {
+				mptsas_scsi_destroy_pkt(ap, pkt);
+			}
+			return ((struct scsi_pkt *)NULL);
+		}
+
+get_dma_cookies:
+		cmd->cmd_flags |= CFLAG_DMAVALID;
+		ASSERT(cmd->cmd_cookiec > 0);
+
+		if (cmd->cmd_cookiec > MPTSAS_MAX_CMD_SEGS) {
+			mptsas_log(mpt, CE_NOTE, "large cookiec received %d\n",
+			    cmd->cmd_cookiec);
+			bioerror(bp, EINVAL);
+			if (new_cmd) {
+				mptsas_scsi_destroy_pkt(ap, pkt);
+			}
+			return ((struct scsi_pkt *)NULL);
+		}
+
+		/*
+		 * Allocate extra SGL buffer if needed.
+		 */
+		if ((cmd->cmd_cookiec > MPTSAS_MAX_FRAME_SGES64(mpt)) &&
+		    (cmd->cmd_extra_frames == NULL)) {
+			if (mptsas_alloc_extra_sgl_frame(mpt, cmd) ==
+			    DDI_FAILURE) {
+				mptsas_log(mpt, CE_WARN, "MPT SGL mem alloc "
+				    "failed");
+				bioerror(bp, ENOMEM);
+				if (new_cmd) {
+					mptsas_scsi_destroy_pkt(ap, pkt);
+				}
+				return ((struct scsi_pkt *)NULL);
+			}
+		}
+
+		/*
+		 * Always use scatter-gather transfer
+		 * Use the loop below to store physical addresses of
+		 * DMA segments, from the DMA cookies, into your HBA's
+		 * scatter-gather list.
+		 * We need to ensure we have enough kmem alloc'd
+		 * for the sg entries since we are no longer using an
+		 * array inside mptsas_cmd_t.
+		 *
+		 * We check cmd->cmd_cookiec against oldcookiec so
+		 * the scatter-gather list is correctly allocated
+		 */
+
+		if (oldcookiec != cmd->cmd_cookiec) {
+			if (cmd->cmd_sg != (mptti_t *)NULL) {
+				kmem_free(cmd->cmd_sg, sizeof (mptti_t) *
+				    oldcookiec);
+				cmd->cmd_sg = NULL;
+			}
+		}
+
+		if (cmd->cmd_sg == (mptti_t *)NULL) {
+			cmd->cmd_sg = kmem_alloc((size_t)(sizeof (mptti_t)*
+			    cmd->cmd_cookiec), kf);
+
+			if (cmd->cmd_sg == (mptti_t *)NULL) {
+				mptsas_log(mpt, CE_WARN,
+				    "unable to kmem_alloc enough memory "
+				    "for scatter/gather list");
+		/*
+		 * if we have an ENOMEM condition we need to behave
+		 * the same way as the rest of this routine
+		 */
+
+				bioerror(bp, ENOMEM);
+				if (new_cmd) {
+					mptsas_scsi_destroy_pkt(ap, pkt);
+				}
+				return ((struct scsi_pkt *)NULL);
+			}
+		}
+
+		dmap = cmd->cmd_sg;
+
+		ASSERT(cmd->cmd_cookie.dmac_size != 0);
+
+		/*
+		 * store the first segment into the S/G list
+		 */
+		dmap->count = cmd->cmd_cookie.dmac_size;
+		dmap->addr.address64.Low = (uint32_t)
+		    (cmd->cmd_cookie.dmac_laddress & 0xffffffffull);
+		dmap->addr.address64.High = (uint32_t)
+		    (cmd->cmd_cookie.dmac_laddress >> 32);
+
+		/*
+		 * dmacount counts the size of the dma for this window
+		 * (if partial dma is being used).  totaldmacount
+		 * keeps track of the total amount of dma we have
+		 * transferred for all the windows (needed to calculate
+		 * the resid value below).
+		 */
+		cmd->cmd_dmacount = cmd->cmd_cookie.dmac_size;
+		cmd->cmd_totaldmacount += cmd->cmd_cookie.dmac_size;
+
+		/*
+		 * We already stored the first DMA scatter gather segment,
+		 * start at 1 if we need to store more.
+		 */
+		for (cnt = 1; cnt < cmd->cmd_cookiec; cnt++) {
+			/*
+			 * Get next DMA cookie
+			 */
+			ddi_dma_nextcookie(cmd->cmd_dmahandle,
+			    &cmd->cmd_cookie);
+			dmap++;
+
+			cmd->cmd_dmacount += cmd->cmd_cookie.dmac_size;
+			cmd->cmd_totaldmacount += cmd->cmd_cookie.dmac_size;
+
+			/*
+			 * store the segment parms into the S/G list
+			 */
+			dmap->count = cmd->cmd_cookie.dmac_size;
+			dmap->addr.address64.Low = (uint32_t)
+			    (cmd->cmd_cookie.dmac_laddress & 0xffffffffull);
+			dmap->addr.address64.High = (uint32_t)
+			    (cmd->cmd_cookie.dmac_laddress >> 32);
+		}
+
+		/*
+		 * If this was partially allocated we set the resid
+		 * the amount of data NOT transferred in this window
+		 * If there is only one window, the resid will be 0
+		 */
+		pkt->pkt_resid = (bp->b_bcount - cmd->cmd_totaldmacount);
+		NDBG16(("mptsas_dmaget: cmd_dmacount=%d.", cmd->cmd_dmacount));
+	}
+	return (pkt);
+}
+
+/*
+ * tran_destroy_pkt(9E) - scsi_pkt(9s) deallocation
+ *
+ * Notes:
+ *	- also frees DMA resources if allocated
+ *	- implicit DMA synchonization
+ */
+static void
+mptsas_scsi_destroy_pkt(struct scsi_address *ap, struct scsi_pkt *pkt)
+{
+	mptsas_cmd_t	*cmd = PKT2CMD(pkt);
+	mptsas_t	*mpt = ADDR2MPT(ap);
+
+	NDBG3(("mptsas_scsi_destroy_pkt: target=%d pkt=0x%p",
+	    ap->a_target, (void *)pkt));
+
+	if (cmd->cmd_flags & CFLAG_DMAVALID) {
+		(void) ddi_dma_unbind_handle(cmd->cmd_dmahandle);
+		cmd->cmd_flags &= ~CFLAG_DMAVALID;
+	}
+
+	if (cmd->cmd_sg) {
+		kmem_free(cmd->cmd_sg, sizeof (mptti_t) * cmd->cmd_cookiec);
+		cmd->cmd_sg = NULL;
+	}
+
+	mptsas_free_extra_sgl_frame(mpt, cmd);
+
+	if ((cmd->cmd_flags &
+	    (CFLAG_FREE | CFLAG_CDBEXTERN | CFLAG_PRIVEXTERN |
+	    CFLAG_SCBEXTERN)) == 0) {
+		cmd->cmd_flags = CFLAG_FREE;
+		kmem_cache_free(mpt->m_kmem_cache, (void *)cmd);
+	} else {
+		mptsas_pkt_destroy_extern(mpt, cmd);
+	}
+}
+
+/*
+ * kmem cache constructor and destructor:
+ * When constructing, we bzero the cmd and allocate the dma handle
+ * When destructing, just free the dma handle
+ */
+static int
+mptsas_kmem_cache_constructor(void *buf, void *cdrarg, int kmflags)
+{
+	mptsas_cmd_t		*cmd = buf;
+	mptsas_t		*mpt  = cdrarg;
+	struct scsi_address	ap;
+	uint_t			cookiec;
+	ddi_dma_attr_t		arq_dma_attr;
+	int			(*callback)(caddr_t);
+
+	callback = (kmflags == KM_SLEEP)? DDI_DMA_SLEEP: DDI_DMA_DONTWAIT;
+
+	NDBG4(("mptsas_kmem_cache_constructor"));
+
+	ap.a_hba_tran = mpt->m_tran;
+	ap.a_target = 0;
+	ap.a_lun = 0;
+
+	/*
+	 * allocate a dma handle
+	 */
+	if ((ddi_dma_alloc_handle(mpt->m_dip, &mpt->m_io_dma_attr, callback,
+	    NULL, &cmd->cmd_dmahandle)) != DDI_SUCCESS) {
+		cmd->cmd_dmahandle = NULL;
+		return (-1);
+	}
+
+	cmd->cmd_arq_buf = scsi_alloc_consistent_buf(&ap, (struct buf *)NULL,
+	    SENSE_LENGTH, B_READ, callback, NULL);
+	if (cmd->cmd_arq_buf == NULL) {
+		ddi_dma_free_handle(&cmd->cmd_dmahandle);
+		cmd->cmd_dmahandle = NULL;
+		return (-1);
+	}
+
+	/*
+	 * allocate a arq handle
+	 */
+	arq_dma_attr = mpt->m_msg_dma_attr;
+	arq_dma_attr.dma_attr_sgllen = 1;
+	if ((ddi_dma_alloc_handle(mpt->m_dip, &arq_dma_attr, callback,
+	    NULL, &cmd->cmd_arqhandle)) != DDI_SUCCESS) {
+		ddi_dma_free_handle(&cmd->cmd_dmahandle);
+		scsi_free_consistent_buf(cmd->cmd_arq_buf);
+		cmd->cmd_dmahandle = NULL;
+		cmd->cmd_arqhandle = NULL;
+		return (-1);
+	}
+
+	if (ddi_dma_buf_bind_handle(cmd->cmd_arqhandle,
+	    cmd->cmd_arq_buf, (DDI_DMA_READ | DDI_DMA_CONSISTENT),
+	    callback, NULL, &cmd->cmd_arqcookie, &cookiec) != DDI_SUCCESS) {
+		ddi_dma_free_handle(&cmd->cmd_dmahandle);
+		ddi_dma_free_handle(&cmd->cmd_arqhandle);
+		scsi_free_consistent_buf(cmd->cmd_arq_buf);
+		cmd->cmd_dmahandle = NULL;
+		cmd->cmd_arqhandle = NULL;
+		cmd->cmd_arq_buf = NULL;
+		return (-1);
+	}
+
+	return (0);
+}
+
+static void
+mptsas_kmem_cache_destructor(void *buf, void *cdrarg)
+{
+#ifndef __lock_lint
+	_NOTE(ARGUNUSED(cdrarg))
+#endif
+	mptsas_cmd_t	*cmd = buf;
+
+	NDBG4(("mptsas_kmem_cache_destructor"));
+
+	if (cmd->cmd_arqhandle) {
+		(void) ddi_dma_unbind_handle(cmd->cmd_arqhandle);
+		ddi_dma_free_handle(&cmd->cmd_arqhandle);
+		cmd->cmd_arqhandle = NULL;
+	}
+	if (cmd->cmd_arq_buf) {
+		scsi_free_consistent_buf(cmd->cmd_arq_buf);
+		cmd->cmd_arq_buf = NULL;
+	}
+	if (cmd->cmd_dmahandle) {
+		ddi_dma_free_handle(&cmd->cmd_dmahandle);
+		cmd->cmd_dmahandle = NULL;
+	}
+}
+
+static int
+mptsas_cache_frames_constructor(void *buf, void *cdrarg, int kmflags)
+{
+	mptsas_cache_frames_t	*p = buf;
+	mptsas_t		*mpt = cdrarg;
+	ddi_dma_attr_t		frame_dma_attr;
+	size_t			mem_size, alloc_len;
+	ddi_dma_cookie_t	cookie;
+	uint_t			ncookie;
+	int (*callback)(caddr_t) = (kmflags == KM_SLEEP)
+	    ? DDI_DMA_SLEEP: DDI_DMA_DONTWAIT;
+
+	frame_dma_attr = mpt->m_msg_dma_attr;
+	frame_dma_attr.dma_attr_align = 0x10;
+	frame_dma_attr.dma_attr_sgllen = 1;
+
+	if (ddi_dma_alloc_handle(mpt->m_dip, &frame_dma_attr, callback, NULL,
+	    &p->m_dma_hdl) != DDI_SUCCESS) {
+		mptsas_log(mpt, CE_WARN, "Unable to allocate dma handle for"
+		    " extra SGL.");
+		return (DDI_FAILURE);
+	}
+
+	mem_size = (mpt->m_max_request_frames - 1) * mpt->m_req_frame_size;
+
+	if (ddi_dma_mem_alloc(p->m_dma_hdl, mem_size, &mpt->m_dev_acc_attr,
+	    DDI_DMA_CONSISTENT, callback, NULL, (caddr_t *)&p->m_frames_addr,
+	    &alloc_len, &p->m_acc_hdl) != DDI_SUCCESS) {
+		ddi_dma_free_handle(&p->m_dma_hdl);
+		p->m_dma_hdl = NULL;
+		mptsas_log(mpt, CE_WARN, "Unable to allocate dma memory for"
+		    " extra SGL.");
+		return (DDI_FAILURE);
+	}
+
+	if (ddi_dma_addr_bind_handle(p->m_dma_hdl, NULL, p->m_frames_addr,
+	    alloc_len, DDI_DMA_RDWR | DDI_DMA_CONSISTENT, callback, NULL,
+	    &cookie, &ncookie) != DDI_DMA_MAPPED) {
+		(void) ddi_dma_mem_free(&p->m_acc_hdl);
+		ddi_dma_free_handle(&p->m_dma_hdl);
+		p->m_dma_hdl = NULL;
+		mptsas_log(mpt, CE_WARN, "Unable to bind DMA resources for"
+		    " extra SGL");
+		return (DDI_FAILURE);
+	}
+
+	/*
+	 * Store the SGL memory address.  This chip uses this
+	 * address to dma to and from the driver.  The second
+	 * address is the address mpt uses to fill in the SGL.
+	 */
+	p->m_phys_addr = cookie.dmac_address;
+
+	return (DDI_SUCCESS);
+}
+
+static void
+mptsas_cache_frames_destructor(void *buf, void *cdrarg)
+{
+#ifndef __lock_lint
+	_NOTE(ARGUNUSED(cdrarg))
+#endif
+	mptsas_cache_frames_t	*p = buf;
+	if (p->m_dma_hdl != NULL) {
+		(void) ddi_dma_unbind_handle(p->m_dma_hdl);
+		(void) ddi_dma_mem_free(&p->m_acc_hdl);
+		ddi_dma_free_handle(&p->m_dma_hdl);
+		p->m_phys_addr = NULL;
+		p->m_frames_addr = NULL;
+		p->m_dma_hdl = NULL;
+		p->m_acc_hdl = NULL;
+	}
+
+}
+
+/*
+ * allocate and deallocate external pkt space (ie. not part of mptsas_cmd)
+ * for non-standard length cdb, pkt_private, status areas
+ * if allocation fails, then deallocate all external space and the pkt
+ */
+/* ARGSUSED */
+static int
+mptsas_pkt_alloc_extern(mptsas_t *mpt, mptsas_cmd_t *cmd,
+    int cmdlen, int tgtlen, int statuslen, int kf)
+{
+	caddr_t			cdbp, scbp, tgt;
+	int			(*callback)(caddr_t) = (kf == KM_SLEEP) ?
+	    DDI_DMA_SLEEP : DDI_DMA_DONTWAIT;
+	struct scsi_address	ap;
+	size_t			senselength;
+	ddi_dma_attr_t		ext_arq_dma_attr;
+	uint_t			cookiec;
+
+	NDBG3(("mptsas_pkt_alloc_extern: "
+	    "cmd=0x%p cmdlen=%d tgtlen=%d statuslen=%d kf=%x",
+	    (void *)cmd, cmdlen, tgtlen, statuslen, kf));
+
+	tgt = cdbp = scbp = NULL;
+	cmd->cmd_scblen		= statuslen;
+	cmd->cmd_privlen	= (uchar_t)tgtlen;
+
+	if (cmdlen > sizeof (cmd->cmd_cdb)) {
+		if ((cdbp = kmem_zalloc((size_t)cmdlen, kf)) == NULL) {
+			goto fail;
+		}
+		cmd->cmd_pkt->pkt_cdbp = (opaque_t)cdbp;
+		cmd->cmd_flags |= CFLAG_CDBEXTERN;
+	}
+	if (tgtlen > PKT_PRIV_LEN) {
+		if ((tgt = kmem_zalloc((size_t)tgtlen, kf)) == NULL) {
+			goto fail;
+		}
+		cmd->cmd_flags |= CFLAG_PRIVEXTERN;
+		cmd->cmd_pkt->pkt_private = tgt;
+	}
+	if (statuslen > EXTCMDS_STATUS_SIZE) {
+		if ((scbp = kmem_zalloc((size_t)statuslen, kf)) == NULL) {
+			goto fail;
+		}
+		cmd->cmd_flags |= CFLAG_SCBEXTERN;
+		cmd->cmd_pkt->pkt_scbp = (opaque_t)scbp;
+
+		/* allocate sense data buf for DMA */
+
+		senselength = statuslen - MPTSAS_GET_ITEM_OFF(
+		    struct scsi_arq_status, sts_sensedata);
+		cmd->cmd_rqslen = (uchar_t)senselength;
+
+		ap.a_hba_tran = mpt->m_tran;
+		ap.a_target = 0;
+		ap.a_lun = 0;
+
+		cmd->cmd_ext_arq_buf = scsi_alloc_consistent_buf(&ap,
+		    (struct buf *)NULL, senselength, B_READ,
+		    callback, NULL);
+
+		if (cmd->cmd_ext_arq_buf == NULL) {
+			goto fail;
+		}
+		/*
+		 * allocate a extern arq handle and bind the buf
+		 */
+		ext_arq_dma_attr = mpt->m_msg_dma_attr;
+		ext_arq_dma_attr.dma_attr_sgllen = 1;
+		if ((ddi_dma_alloc_handle(mpt->m_dip,
+		    &ext_arq_dma_attr, callback,
+		    NULL, &cmd->cmd_ext_arqhandle)) != DDI_SUCCESS) {
+			goto fail;
+		}
+
+		if (ddi_dma_buf_bind_handle(cmd->cmd_ext_arqhandle,
+		    cmd->cmd_ext_arq_buf, (DDI_DMA_READ | DDI_DMA_CONSISTENT),
+		    callback, NULL, &cmd->cmd_ext_arqcookie,
+		    &cookiec)
+		    != DDI_SUCCESS) {
+			goto fail;
+		}
+		cmd->cmd_flags |= CFLAG_EXTARQBUFVALID;
+	}
+	return (0);
+fail:
+	mptsas_pkt_destroy_extern(mpt, cmd);
+	return (1);
+}
+
+/*
+ * deallocate external pkt space and deallocate the pkt
+ */
+static void
+mptsas_pkt_destroy_extern(mptsas_t *mpt, mptsas_cmd_t *cmd)
+{
+	NDBG3(("mptsas_pkt_destroy_extern: cmd=0x%p", (void *)cmd));
+
+	if (cmd->cmd_flags & CFLAG_FREE) {
+		mptsas_log(mpt, CE_PANIC,
+		    "mptsas_pkt_destroy_extern: freeing free packet");
+		_NOTE(NOT_REACHED)
+		/* NOTREACHED */
+	}
+	if (cmd->cmd_flags & CFLAG_CDBEXTERN) {
+		kmem_free(cmd->cmd_pkt->pkt_cdbp, (size_t)cmd->cmd_cdblen);
+	}
+	if (cmd->cmd_flags & CFLAG_SCBEXTERN) {
+		kmem_free(cmd->cmd_pkt->pkt_scbp, (size_t)cmd->cmd_scblen);
+		if (cmd->cmd_flags & CFLAG_EXTARQBUFVALID) {
+			(void) ddi_dma_unbind_handle(cmd->cmd_ext_arqhandle);
+		}
+		if (cmd->cmd_ext_arqhandle) {
+			ddi_dma_free_handle(&cmd->cmd_ext_arqhandle);
+			cmd->cmd_ext_arqhandle = NULL;
+		}
+		if (cmd->cmd_ext_arq_buf)
+			scsi_free_consistent_buf(cmd->cmd_ext_arq_buf);
+	}
+	if (cmd->cmd_flags & CFLAG_PRIVEXTERN) {
+		kmem_free(cmd->cmd_pkt->pkt_private, (size_t)cmd->cmd_privlen);
+	}
+	cmd->cmd_flags = CFLAG_FREE;
+	kmem_cache_free(mpt->m_kmem_cache, (void *)cmd);
+}
+
+/*
+ * tran_sync_pkt(9E) - explicit DMA synchronization
+ */
+/*ARGSUSED*/
+static void
+mptsas_scsi_sync_pkt(struct scsi_address *ap, struct scsi_pkt *pkt)
+{
+	mptsas_cmd_t	*cmd = PKT2CMD(pkt);
+
+	NDBG3(("mptsas_scsi_sync_pkt: target=%d, pkt=0x%p",
+	    ap->a_target, (void *)pkt));
+
+	if (cmd->cmd_dmahandle) {
+		(void) ddi_dma_sync(cmd->cmd_dmahandle, 0, 0,
+		    (cmd->cmd_flags & CFLAG_DMASEND) ?
+		    DDI_DMA_SYNC_FORDEV : DDI_DMA_SYNC_FORCPU);
+	}
+}
+
+/*
+ * tran_dmafree(9E) - deallocate DMA resources allocated for command
+ */
+/*ARGSUSED*/
+static void
+mptsas_scsi_dmafree(struct scsi_address *ap, struct scsi_pkt *pkt)
+{
+	mptsas_cmd_t	*cmd = PKT2CMD(pkt);
+	mptsas_t	*mpt = ADDR2MPT(ap);
+
+	NDBG3(("mptsas_scsi_dmafree: target=%d pkt=0x%p",
+	    ap->a_target, (void *)pkt));
+
+	if (cmd->cmd_flags & CFLAG_DMAVALID) {
+		(void) ddi_dma_unbind_handle(cmd->cmd_dmahandle);
+		cmd->cmd_flags &= ~CFLAG_DMAVALID;
+	}
+
+	if (cmd->cmd_flags & CFLAG_EXTARQBUFVALID) {
+		(void) ddi_dma_unbind_handle(cmd->cmd_ext_arqhandle);
+		cmd->cmd_flags &= ~CFLAG_EXTARQBUFVALID;
+	}
+
+	mptsas_free_extra_sgl_frame(mpt, cmd);
+}
+
+static void
+mptsas_pkt_comp(struct scsi_pkt *pkt, mptsas_cmd_t *cmd)
+{
+	if ((cmd->cmd_flags & CFLAG_CMDIOPB) &&
+	    (!(cmd->cmd_flags & CFLAG_DMASEND))) {
+		(void) ddi_dma_sync(cmd->cmd_dmahandle, 0, 0,
+		    DDI_DMA_SYNC_FORCPU);
+	}
+	(*pkt->pkt_comp)(pkt);
+}
+
+static void
+mptsas_sge_setup(mptsas_t *mpt, mptsas_cmd_t *cmd, uint32_t *control,
+	pMpi2SCSIIORequest_t frame, ddi_acc_handle_t acc_hdl)
+{
+	uint_t			cookiec;
+	mptti_t			*dmap;
+	uint32_t		flags;
+	pMpi2SGESimple64_t	sge;
+	pMpi2SGEChain64_t	sgechain;
+	ASSERT(cmd->cmd_flags & CFLAG_DMAVALID);
+
+	/*
+	 * Save the number of entries in the DMA
+	 * Scatter/Gather list
+	 */
+	cookiec = cmd->cmd_cookiec;
+
+	NDBG1(("mptsas_sge_setup: cookiec=%d", cookiec));
+
+	/*
+	 * Set read/write bit in control.
+	 */
+	if (cmd->cmd_flags & CFLAG_DMASEND) {
+		*control |= MPI2_SCSIIO_CONTROL_WRITE;
+	} else {
+		*control |= MPI2_SCSIIO_CONTROL_READ;
+	}
+
+	ddi_put32(acc_hdl, &frame->DataLength, cmd->cmd_dmacount);
+
+	/*
+	 * We have 2 cases here.  First where we can fit all the
+	 * SG elements into the main frame, and the case
+	 * where we can't.
+	 * If we have more cookies than we can attach to a frame
+	 * we will need to use a chain element to point
+	 * a location of memory where the rest of the S/G
+	 * elements reside.
+	 */
+	if (cookiec <= MPTSAS_MAX_FRAME_SGES64(mpt)) {
+		dmap = cmd->cmd_sg;
+		sge = (pMpi2SGESimple64_t)(&frame->SGL);
+		while (cookiec--) {
+			ddi_put32(acc_hdl,
+			    &sge->Address.Low, dmap->addr.address64.Low);
+			ddi_put32(acc_hdl,
+			    &sge->Address.High, dmap->addr.address64.High);
+			ddi_put32(acc_hdl, &sge->FlagsLength,
+			    dmap->count);
+			flags = ddi_get32(acc_hdl, &sge->FlagsLength);
+			flags |= ((uint32_t)
+			    (MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
+			    MPI2_SGE_FLAGS_SYSTEM_ADDRESS |
+			    MPI2_SGE_FLAGS_64_BIT_ADDRESSING) <<
+			    MPI2_SGE_FLAGS_SHIFT);
+
+			/*
+			 * If this is the last cookie, we set the flags
+			 * to indicate so
+			 */
+			if (cookiec == 0) {
+				flags |=
+				    ((uint32_t)(MPI2_SGE_FLAGS_LAST_ELEMENT
+				    | MPI2_SGE_FLAGS_END_OF_BUFFER
+				    | MPI2_SGE_FLAGS_END_OF_LIST) <<
+				    MPI2_SGE_FLAGS_SHIFT);
+			}
+			if (cmd->cmd_flags & CFLAG_DMASEND) {
+				flags |= (MPI2_SGE_FLAGS_HOST_TO_IOC <<
+				    MPI2_SGE_FLAGS_SHIFT);
+			} else {
+				flags |= (MPI2_SGE_FLAGS_IOC_TO_HOST <<
+				    MPI2_SGE_FLAGS_SHIFT);
+			}
+			ddi_put32(acc_hdl, &sge->FlagsLength, flags);
+			dmap++;
+			sge++;
+		}
+	} else {
+		/*
+		 * Hereby we start to deal with multiple frames.
+		 * The process is as follows:
+		 * 1. Determine how many frames are needed for SGL element
+		 *    storage; Note that all frames are stored in contiguous
+		 *    memory space and in 64-bit DMA mode each element is
+		 *    3 double-words (12 bytes) long.
+		 * 2. Fill up the main frame. We need to do this separately
+		 *    since it contains the SCSI IO request header and needs
+		 *    dedicated processing. Note that the last 4 double-words
+		 *    of the SCSI IO header is for SGL element storage
+		 *    (MPI2_SGE_IO_UNION).
+		 * 3. Fill the chain element in the main frame, so the DMA
+		 *    engine can use the following frames.
+		 * 4. Enter a loop to fill the remaining frames. Note that the
+		 *    last frame contains no chain element.  The remaining
+		 *    frames go into the mpt SGL buffer allocated on the fly,
+		 *    not immediately following the main message frame, as in
+		 *    Gen1.
+		 * Some restrictions:
+		 * 1. For 64-bit DMA, the simple element and chain element
+		 *    are both of 3 double-words (12 bytes) in size, even
+		 *    though all frames are stored in the first 4G of mem
+		 *    range and the higher 32-bits of the address are always 0.
+		 * 2. On some controllers (like the 1064/1068), a frame can
+		 *    hold SGL elements with the last 1 or 2 double-words
+		 *    (4 or 8 bytes) un-used. On these controllers, we should
+		 *    recognize that there's not enough room for another SGL
+		 *    element and move the sge pointer to the next frame.
+		 */
+		int		i, j, k, l, frames, sgemax;
+		int		temp;
+		uint8_t		chainflags;
+		uint16_t	chainlength;
+		mptsas_cache_frames_t *p;
+
+		/*
+		 * Sgemax is the number of SGE's that will fit
+		 * each extra frame and frames is total
+		 * number of frames we'll need.  1 sge entry per
+		 * frame is reseverd for the chain element thus the -1 below.
+		 */
+		sgemax = ((mpt->m_req_frame_size / sizeof (MPI2_SGE_SIMPLE64))
+		    - 1);
+		temp = (cookiec - (MPTSAS_MAX_FRAME_SGES64(mpt) - 1)) / sgemax;
+
+		/*
+		 * A little check to see if we need to round up the number
+		 * of frames we need
+		 */
+		if ((cookiec - (MPTSAS_MAX_FRAME_SGES64(mpt) - 1)) - (temp *
+		    sgemax) > 1) {
+			frames = (temp + 1);
+		} else {
+			frames = temp;
+		}
+		dmap = cmd->cmd_sg;
+		sge = (pMpi2SGESimple64_t)(&frame->SGL);
+
+		/*
+		 * First fill in the main frame
+		 */
+		for (j = 1; j < MPTSAS_MAX_FRAME_SGES64(mpt); j++) {
+			ddi_put32(acc_hdl, &sge->Address.Low,
+			    dmap->addr.address64.Low);
+			ddi_put32(acc_hdl, &sge->Address.High,
+			    dmap->addr.address64.High);
+			ddi_put32(acc_hdl, &sge->FlagsLength, dmap->count);
+			flags = ddi_get32(acc_hdl, &sge->FlagsLength);
+			flags |= ((uint32_t)(MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
+			    MPI2_SGE_FLAGS_SYSTEM_ADDRESS |
+			    MPI2_SGE_FLAGS_64_BIT_ADDRESSING) <<
+			    MPI2_SGE_FLAGS_SHIFT);
+
+			/*
+			 * If this is the last SGE of this frame
+			 * we set the end of list flag
+			 */
+			if (j == (MPTSAS_MAX_FRAME_SGES64(mpt) - 1)) {
+				flags |= ((uint32_t)
+				    (MPI2_SGE_FLAGS_LAST_ELEMENT) <<
+				    MPI2_SGE_FLAGS_SHIFT);
+			}
+			if (cmd->cmd_flags & CFLAG_DMASEND) {
+				flags |=
+				    (MPI2_SGE_FLAGS_HOST_TO_IOC <<
+				    MPI2_SGE_FLAGS_SHIFT);
+			} else {
+				flags |=
+				    (MPI2_SGE_FLAGS_IOC_TO_HOST <<
+				    MPI2_SGE_FLAGS_SHIFT);
+			}
+			ddi_put32(acc_hdl, &sge->FlagsLength, flags);
+			dmap++;
+			sge++;
+		}
+
+		/*
+		 * Fill in the chain element in the main frame.
+		 * About calculation on ChainOffset:
+		 * 1. Struct msg_scsi_io_request has 4 double-words (16 bytes)
+		 *    in the end reserved for SGL element storage
+		 *    (MPI2_SGE_IO_UNION); we should count it in our
+		 *    calculation.  See its definition in the header file.
+		 * 2. Constant j is the counter of the current SGL element
+		 *    that will be processed, and (j - 1) is the number of
+		 *    SGL elements that have been processed (stored in the
+		 *    main frame).
+		 * 3. ChainOffset value should be in units of double-words (4
+		 *    bytes) so the last value should be divided by 4.
+		 */
+		ddi_put8(acc_hdl, &frame->ChainOffset,
+		    (sizeof (MPI2_SCSI_IO_REQUEST) -
+		    sizeof (MPI2_SGE_IO_UNION) +
+		    (j - 1) * sizeof (MPI2_SGE_SIMPLE64)) >> 2);
+		sgechain = (pMpi2SGEChain64_t)sge;
+		chainflags = (MPI2_SGE_FLAGS_CHAIN_ELEMENT |
+		    MPI2_SGE_FLAGS_SYSTEM_ADDRESS |
+		    MPI2_SGE_FLAGS_64_BIT_ADDRESSING);
+		ddi_put8(acc_hdl, &sgechain->Flags, chainflags);
+
+		/*
+		 * The size of the next frame is the accurate size of space
+		 * (in bytes) used to store the SGL elements. j is the counter
+		 * of SGL elements. (j - 1) is the number of SGL elements that
+		 * have been processed (stored in frames).
+		 */
+		if (frames >= 2) {
+			chainlength = mpt->m_req_frame_size /
+			    sizeof (MPI2_SGE_SIMPLE64) *
+			    sizeof (MPI2_SGE_SIMPLE64);
+		} else {
+			chainlength = ((cookiec - (j - 1)) *
+			    sizeof (MPI2_SGE_SIMPLE64));
+		}
+
+		p = cmd->cmd_extra_frames;
+
+		ddi_put16(acc_hdl, &sgechain->Length, chainlength);
+		ddi_put32(acc_hdl, &sgechain->Address.Low,
+		    p->m_phys_addr);
+		/* SGL is allocated in the first 4G mem range */
+		ddi_put32(acc_hdl, &sgechain->Address.High, 0);
+
+		/*
+		 * If there are more than 2 frames left we have to
+		 * fill in the next chain offset to the location of
+		 * the chain element in the next frame.
+		 * sgemax is the number of simple elements in an extra
+		 * frame. Note that the value NextChainOffset should be
+		 * in double-words (4 bytes).
+		 */
+		if (frames >= 2) {
+			ddi_put8(acc_hdl, &sgechain->NextChainOffset,
+			    (sgemax * sizeof (MPI2_SGE_SIMPLE64)) >> 2);
+		} else {
+			ddi_put8(acc_hdl, &sgechain->NextChainOffset, 0);
+		}
+
+		/*
+		 * Jump to next frame;
+		 * Starting here, chain buffers go into the per command SGL.
+		 * This buffer is allocated when chain buffers are needed.
+		 */
+		sge = (pMpi2SGESimple64_t)p->m_frames_addr;
+		i = cookiec;
+
+		/*
+		 * Start filling in frames with SGE's.  If we
+		 * reach the end of frame and still have SGE's
+		 * to fill we need to add a chain element and
+		 * use another frame.  j will be our counter
+		 * for what cookie we are at and i will be
+		 * the total cookiec. k is the current frame
+		 */
+		for (k = 1; k <= frames; k++) {
+			for (l = 1; (l <= (sgemax + 1)) && (j <= i); j++, l++) {
+
+				/*
+				 * If we have reached the end of frame
+				 * and we have more SGE's to fill in
+				 * we have to fill the final entry
+				 * with a chain element and then
+				 * continue to the next frame
+				 */
+				if ((l == (sgemax + 1)) && (k != frames)) {
+					sgechain = (pMpi2SGEChain64_t)sge;
+					j--;
+					chainflags = (
+					    MPI2_SGE_FLAGS_CHAIN_ELEMENT |
+					    MPI2_SGE_FLAGS_SYSTEM_ADDRESS |
+					    MPI2_SGE_FLAGS_64_BIT_ADDRESSING);
+					ddi_put8(p->m_acc_hdl,
+					    &sgechain->Flags, chainflags);
+					/*
+					 * k is the frame counter and (k + 1)
+					 * is the number of the next frame.
+					 * Note that frames are in contiguous
+					 * memory space.
+					 */
+					ddi_put32(p->m_acc_hdl,
+					    &sgechain->Address.Low,
+					    (p->m_phys_addr +
+					    (mpt->m_req_frame_size * k)));
+					ddi_put32(p->m_acc_hdl,
+					    &sgechain->Address.High, 0);
+
+					/*
+					 * If there are more than 2 frames left
+					 * we have to next chain offset to
+					 * the location of the chain element
+					 * in the next frame and fill in the
+					 * length of the next chain
+					 */
+					if ((frames - k) >= 2) {
+						ddi_put8(p->m_acc_hdl,
+						    &sgechain->NextChainOffset,
+						    (sgemax *
+						    sizeof (MPI2_SGE_SIMPLE64))
+						    >> 2);
+						ddi_put16(p->m_acc_hdl,
+						    &sgechain->Length,
+						    mpt->m_req_frame_size /
+						    sizeof (MPI2_SGE_SIMPLE64) *
+						    sizeof (MPI2_SGE_SIMPLE64));
+					} else {
+						/*
+						 * This is the last frame. Set
+						 * the NextChainOffset to 0 and
+						 * Length is the total size of
+						 * all remaining simple elements
+						 */
+						ddi_put8(p->m_acc_hdl,
+						    &sgechain->NextChainOffset,
+						    0);
+						ddi_put16(p->m_acc_hdl,
+						    &sgechain->Length,
+						    (cookiec - j) *
+						    sizeof (MPI2_SGE_SIMPLE64));
+					}
+
+					/* Jump to the next frame */
+					sge = (pMpi2SGESimple64_t)
+					    ((char *)p->m_frames_addr +
+					    (int)mpt->m_req_frame_size * k);
+
+					continue;
+				}
+
+				ddi_put32(p->m_acc_hdl,
+				    &sge->Address.Low,
+				    dmap->addr.address64.Low);
+				ddi_put32(p->m_acc_hdl,
+				    &sge->Address.High,
+				    dmap->addr.address64.High);
+				ddi_put32(p->m_acc_hdl,
+				    &sge->FlagsLength, dmap->count);
+				flags = ddi_get32(p->m_acc_hdl,
+				    &sge->FlagsLength);
+				flags |= ((uint32_t)(
+				    MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
+				    MPI2_SGE_FLAGS_SYSTEM_ADDRESS |
+				    MPI2_SGE_FLAGS_64_BIT_ADDRESSING) <<
+				    MPI2_SGE_FLAGS_SHIFT);
+
+				/*
+				 * If we are at the end of the frame and
+				 * there is another frame to fill in
+				 * we set the last simple element as last
+				 * element
+				 */
+				if ((l == sgemax) && (k != frames)) {
+					flags |= ((uint32_t)
+					    (MPI2_SGE_FLAGS_LAST_ELEMENT) <<
+					    MPI2_SGE_FLAGS_SHIFT);
+				}
+
+				/*
+				 * If this is the final cookie we
+				 * indicate it by setting the flags
+				 */
+				if (j == i) {
+					flags |= ((uint32_t)
+					    (MPI2_SGE_FLAGS_LAST_ELEMENT |
+					    MPI2_SGE_FLAGS_END_OF_BUFFER |
+					    MPI2_SGE_FLAGS_END_OF_LIST) <<
+					    MPI2_SGE_FLAGS_SHIFT);
+				}
+				if (cmd->cmd_flags & CFLAG_DMASEND) {
+					flags |=
+					    (MPI2_SGE_FLAGS_HOST_TO_IOC <<
+					    MPI2_SGE_FLAGS_SHIFT);
+				} else {
+					flags |=
+					    (MPI2_SGE_FLAGS_IOC_TO_HOST <<
+					    MPI2_SGE_FLAGS_SHIFT);
+				}
+				ddi_put32(p->m_acc_hdl,
+				    &sge->FlagsLength, flags);
+				dmap++;
+				sge++;
+			}
+		}
+
+		/*
+		 * Sync DMA with the chain buffers that were just created
+		 */
+		(void) ddi_dma_sync(p->m_dma_hdl, 0, 0, DDI_DMA_SYNC_FORDEV);
+	}
+}
+
+/*
+ * Interrupt handling
+ * Utility routine.  Poll for status of a command sent to HBA
+ * without interrupts (a FLAG_NOINTR command).
+ */
+int
+mptsas_poll(mptsas_t *mpt, mptsas_cmd_t *poll_cmd, int polltime)
+{
+	int	rval = TRUE;
+
+	NDBG5(("mptsas_poll: cmd=0x%p", (void *)poll_cmd));
+
+	if ((poll_cmd->cmd_flags & CFLAG_TM_CMD) == 0) {
+		mptsas_restart_hba(mpt);
+	}
+
+	/*
+	 * Wait, using drv_usecwait(), long enough for the command to
+	 * reasonably return from the target if the target isn't
+	 * "dead".  A polled command may well be sent from scsi_poll, and
+	 * there are retries built in to scsi_poll if the transport
+	 * accepted the packet (TRAN_ACCEPT).  scsi_poll waits 1 second
+	 * and retries the transport up to scsi_poll_busycnt times
+	 * (currently 60) if
+	 * 1. pkt_reason is CMD_INCOMPLETE and pkt_state is 0, or
+	 * 2. pkt_reason is CMD_CMPLT and *pkt_scbp has STATUS_BUSY
+	 *
+	 * limit the waiting to avoid a hang in the event that the
+	 * cmd never gets started but we are still receiving interrupts
+	 */
+	while (!(poll_cmd->cmd_flags & CFLAG_FINISHED)) {
+		if (mptsas_wait_intr(mpt, polltime) == FALSE) {
+			NDBG5(("mptsas_poll: command incomplete"));
+			rval = FALSE;
+			break;
+		}
+	}
+
+	if (rval == FALSE) {
+
+		/*
+		 * this isn't supposed to happen, the hba must be wedged
+		 * Mark this cmd as a timeout.
+		 */
+		mptsas_set_pkt_reason(mpt, poll_cmd, CMD_TIMEOUT,
+		    (STAT_TIMEOUT|STAT_ABORTED));
+
+		if (poll_cmd->cmd_queued == FALSE) {
+
+			NDBG5(("mptsas_poll: not on waitq"));
+
+			poll_cmd->cmd_pkt->pkt_state |=
+			    (STATE_GOT_BUS|STATE_GOT_TARGET|STATE_SENT_CMD);
+		} else {
+
+			/* find and remove it from the waitq */
+			NDBG5(("mptsas_poll: delete from waitq"));
+			mptsas_waitq_delete(mpt, poll_cmd);
+		}
+
+	}
+	mptsas_fma_check(mpt, poll_cmd);
+	NDBG5(("mptsas_poll: done"));
+	return (rval);
+}
+
+/*
+ * Used for polling cmds and TM function
+ */
+static int
+mptsas_wait_intr(mptsas_t *mpt, int polltime)
+{
+	int				cnt;
+	uint32_t			reply_index;
+	pMpi2ReplyDescriptorsUnion_t	reply_desc_union;
+
+	NDBG5(("mptsas_wait_intr"));
+
+	/*
+	 * Keep polling for at least (polltime * 1000) seconds
+	 */
+	reply_index = mpt->m_post_index;
+	for (cnt = 0; cnt < polltime; cnt++) {
+		reply_desc_union = (pMpi2ReplyDescriptorsUnion_t)
+		    MPTSAS_GET_NEXT_REPLY(mpt, reply_index);
+
+		if (ddi_get32(mpt->m_acc_post_queue_hdl,
+		    &reply_desc_union->Words.Low) == 0xFFFFFFFF ||
+		    ddi_get32(mpt->m_acc_post_queue_hdl,
+		    &reply_desc_union->Words.High) == 0xFFFFFFFF) {
+			drv_usecwait(1000);
+			continue;
+		}
+		mpt->m_polled_intr = 1;
+		/*
+		 * The reply is valid, process it according to its
+		 * type.  Also, set a flag for updated the reply index
+		 * after they've all been processed.
+		 */
+		mptsas_process_intr(mpt, reply_desc_union);
+
+		if (++reply_index == mpt->m_post_queue_depth) {
+			reply_index = 0;
+		}
+		/*
+		 * Update the global reply index
+		 */
+		mpt->m_post_index = reply_index;
+		ddi_put32(mpt->m_datap,
+		    &mpt->m_reg->ReplyPostHostIndex, reply_index);
+
+		return (TRUE);
+
+	}
+	return (FALSE);
+}
+
+static void
+mptsas_handle_scsi_io_success(mptsas_t *mpt,
+    pMpi2ReplyDescriptorsUnion_t reply_desc)
+{
+	pMpi2SCSIIOSuccessReplyDescriptor_t	scsi_io_success;
+	uint16_t				SMID;
+	mptsas_slots_t				*slots = mpt->m_active;
+	mptsas_cmd_t				*cmd = NULL;
+	struct scsi_pkt				*pkt;
+
+	ASSERT(mutex_owned(&mpt->m_mutex));
+
+	scsi_io_success = (pMpi2SCSIIOSuccessReplyDescriptor_t)reply_desc;
+	SMID = ddi_get16(mpt->m_acc_post_queue_hdl, &scsi_io_success->SMID);
+
+	/*
+	 * This is a success reply so just complete the IO.  First, do a sanity
+	 * check on the SMID.  The final slot is used for TM requests, which
+	 * would not come into this reply handler.
+	 */
+	if ((SMID == 0) || (SMID > slots->m_n_slots)) {
+		mptsas_log(mpt, CE_WARN, "?Received invalid SMID of %d\n",
+		    SMID);
+		ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
+		return;
+	}
+
+	cmd = slots->m_slot[SMID];
+
+	/*
+	 * print warning and return if the slot is empty
+	 */
+	if (cmd == NULL) {
+		mptsas_log(mpt, CE_WARN, "?NULL command for successful SCSI IO "
+		    "in slot %d", SMID);
+		return;
+	}
+
+	pkt = CMD2PKT(cmd);
+	pkt->pkt_state |= (STATE_GOT_BUS | STATE_GOT_TARGET | STATE_SENT_CMD |
+	    STATE_GOT_STATUS);
+	if (cmd->cmd_flags & CFLAG_DMAVALID) {
+		pkt->pkt_state |= STATE_XFERRED_DATA;
+	}
+	pkt->pkt_resid = 0;
+
+	if (cmd->cmd_flags & CFLAG_PASSTHRU) {
+		cmd->cmd_flags |= CFLAG_FINISHED;
+		cv_broadcast(&mpt->m_passthru_cv);
+		return;
+	} else {
+		mptsas_remove_cmd(mpt, cmd);
+	}
+
+	if (cmd->cmd_flags & CFLAG_RETRY) {
+		/*
+		 * The target returned QFULL or busy, do not add tihs
+		 * pkt to the doneq since the hba will retry
+		 * this cmd.
+		 *
+		 * The pkt has already been resubmitted in
+		 * mptsas_handle_qfull() or in mptsas_check_scsi_io_error().
+		 * Remove this cmd_flag here.
+		 */
+		cmd->cmd_flags &= ~CFLAG_RETRY;
+	} else {
+		mptsas_doneq_add(mpt, cmd);
+	}
+}
+
+static void
+mptsas_handle_address_reply(mptsas_t *mpt,
+    pMpi2ReplyDescriptorsUnion_t reply_desc)
+{
+	pMpi2AddressReplyDescriptor_t	address_reply;
+	pMPI2DefaultReply_t		reply;
+	uint32_t			reply_addr, reply_index;
+	uint16_t			SMID;
+	mptsas_slots_t			*slots = mpt->m_active;
+	mptsas_cmd_t			*cmd = NULL;
+	uint8_t				function;
+	m_replyh_arg_t			*args;
+	int				reply_frame_no;
+
+	ASSERT(mutex_owned(&mpt->m_mutex));
+
+	address_reply = (pMpi2AddressReplyDescriptor_t)reply_desc;
+	reply_addr = ddi_get32(mpt->m_acc_post_queue_hdl,
+	    &address_reply->ReplyFrameAddress);
+	SMID = ddi_get16(mpt->m_acc_post_queue_hdl, &address_reply->SMID);
+
+	/*
+	 * If reply frame is not in the proper range we should ignore this
+	 * message and exit the interrupt handler.
+	 */
+	if ((reply_addr < mpt->m_reply_frame_dma_addr) ||
+	    (reply_addr >= (mpt->m_reply_frame_dma_addr +
+	    (mpt->m_reply_frame_size * mpt->m_free_queue_depth))) ||
+	    ((reply_addr - mpt->m_reply_frame_dma_addr) %
+	    mpt->m_reply_frame_size != 0)) {
+		mptsas_log(mpt, CE_WARN, "?Received invalid reply frame "
+		    "address 0x%x\n", reply_addr);
+		ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
+		return;
+	}
+
+	(void) ddi_dma_sync(mpt->m_dma_reply_frame_hdl, 0, 0,
+	    DDI_DMA_SYNC_FORCPU);
+	reply = (pMPI2DefaultReply_t)(mpt->m_reply_frame + (reply_addr -
+	    mpt->m_reply_frame_dma_addr));
+	function = ddi_get8(mpt->m_acc_reply_frame_hdl, &reply->Function);
+
+	/*
+	 * don't get slot information and command for events since these values
+	 * don't exist
+	 */
+	if (function != MPI2_FUNCTION_EVENT_NOTIFICATION) {
+		/*
+		 * This could be a TM reply, which use the last allocated SMID,
+		 * so allow for that.
+		 */
+		if ((SMID == 0) || (SMID > (slots->m_n_slots + 1))) {
+			mptsas_log(mpt, CE_WARN, "?Received invalid SMID of "
+			    "%d\n", SMID);
+			ddi_fm_service_impact(mpt->m_dip,
+			    DDI_SERVICE_UNAFFECTED);
+			return;
+		}
+
+		cmd = slots->m_slot[SMID];
+
+		/*
+		 * print warning and return if the slot is empty
+		 */
+		if (cmd == NULL) {
+			mptsas_log(mpt, CE_WARN, "?NULL command for address "
+			    "reply in slot %d", SMID);
+			return;
+		}
+		if ((cmd->cmd_flags & CFLAG_PASSTHRU) ||
+		    (cmd->cmd_flags & CFLAG_CONFIG)) {
+			cmd->cmd_rfm = reply_addr;
+			cmd->cmd_flags |= CFLAG_FINISHED;
+			cv_broadcast(&mpt->m_passthru_cv);
+			cv_broadcast(&mpt->m_config_cv);
+			return;
+		} else if (!(cmd->cmd_flags & CFLAG_FW_CMD)) {
+			mptsas_remove_cmd(mpt, cmd);
+		}
+		NDBG31(("\t\tmptsas_process_intr: slot=%d", SMID));
+	}
+	/*
+	 * Depending on the function, we need to handle
+	 * the reply frame (and cmd) differently.
+	 */
+	switch (function) {
+	case MPI2_FUNCTION_SCSI_IO_REQUEST:
+		mptsas_check_scsi_io_error(mpt, (pMpi2SCSIIOReply_t)reply, cmd);
+		break;
+	case MPI2_FUNCTION_SCSI_TASK_MGMT:
+		mptsas_check_task_mgt(mpt, (pMpi2SCSIManagementReply_t)reply,
+		    cmd);
+		break;
+	case MPI2_FUNCTION_FW_DOWNLOAD:
+		cmd->cmd_flags |= CFLAG_FINISHED;
+		cv_signal(&mpt->m_fw_cv);
+		break;
+	case MPI2_FUNCTION_EVENT_NOTIFICATION:
+		reply_frame_no = (reply_addr - mpt->m_reply_frame_dma_addr) /
+		    mpt->m_reply_frame_size;
+		args = &mpt->m_replyh_args[reply_frame_no];
+		args->mpt = (void *)mpt;
+		args->rfm = reply_addr;
+
+		/*
+		 * Record the event if its type is enabled in
+		 * this mpt instance by ioctl.
+		 */
+		mptsas_record_event(args);
+
+		/*
+		 * Handle time critical events
+		 * NOT_RESPONDING/ADDED only now
+		 */
+		if (mptsas_handle_event_sync(args) == DDI_SUCCESS) {
+			/*
+			 * Would not return main process,
+			 * just let taskq resolve ack action
+			 * and ack would be sent in taskq thread
+			 */
+			NDBG20(("send mptsas_handle_event_sync success"));
+		}
+		if ((ddi_taskq_dispatch(mpt->m_event_taskq, mptsas_handle_event,
+		    (void *)args, DDI_NOSLEEP)) != DDI_SUCCESS) {
+			mptsas_log(mpt, CE_WARN, "No memory available"
+			"for dispatch taskq");
+			/*
+			 * Return the reply frame to the free queue.
+			 */
+			reply_index = mpt->m_free_index;
+			ddi_put32(mpt->m_acc_free_queue_hdl,
+			    &((uint32_t *)(void *)
+			    mpt->m_free_queue)[reply_index], reply_addr);
+			(void) ddi_dma_sync(mpt->m_dma_free_queue_hdl, 0, 0,
+			    DDI_DMA_SYNC_FORDEV);
+			if (++reply_index == mpt->m_free_queue_depth) {
+				reply_index = 0;
+			}
+			mpt->m_free_index = reply_index;
+
+			ddi_put32(mpt->m_datap,
+			    &mpt->m_reg->ReplyFreeHostIndex, reply_index);
+		}
+		return;
+	default:
+		mptsas_log(mpt, CE_WARN, "Unknown function 0x%x ", function);
+		break;
+	}
+
+	/*
+	 * Return the reply frame to the free queue.
+	 */
+	reply_index = mpt->m_free_index;
+	ddi_put32(mpt->m_acc_free_queue_hdl,
+	    &((uint32_t *)(void *)mpt->m_free_queue)[reply_index],
+	    reply_addr);
+	(void) ddi_dma_sync(mpt->m_dma_free_queue_hdl, 0, 0,
+	    DDI_DMA_SYNC_FORDEV);
+	if (++reply_index == mpt->m_free_queue_depth) {
+		reply_index = 0;
+	}
+	mpt->m_free_index = reply_index;
+	ddi_put32(mpt->m_datap, &mpt->m_reg->ReplyFreeHostIndex, reply_index);
+
+	if (cmd->cmd_flags & CFLAG_FW_CMD)
+		return;
+
+	if (cmd->cmd_flags & CFLAG_RETRY) {
+		/*
+		 * The target returned QFULL or busy, do not add tihs
+		 * pkt to the doneq since the hba will retry
+		 * this cmd.
+		 *
+		 * The pkt has already been resubmitted in
+		 * mptsas_handle_qfull() or in mptsas_check_scsi_io_error().
+		 * Remove this cmd_flag here.
+		 */
+		cmd->cmd_flags &= ~CFLAG_RETRY;
+	} else {
+		struct scsi_pkt *pkt = CMD2PKT(cmd);
+
+		ASSERT((cmd->cmd_flags & CFLAG_COMPLETED) == 0);
+		cmd->cmd_linkp = NULL;
+		cmd->cmd_flags |= CFLAG_FINISHED;
+		cmd->cmd_flags &= ~CFLAG_IN_TRANSPORT;
+
+		if (pkt && pkt->pkt_comp) {
+			cmd->cmd_flags |= CFLAG_COMPLETED;
+			mutex_exit(&mpt->m_mutex);
+			mptsas_pkt_comp(pkt, cmd);
+			mutex_enter(&mpt->m_mutex);
+		}
+	}
+}
+
+static void
+mptsas_check_scsi_io_error(mptsas_t *mpt, pMpi2SCSIIOReply_t reply,
+    mptsas_cmd_t *cmd)
+{
+	uint8_t			scsi_status, scsi_state;
+	uint16_t		ioc_status;
+	uint32_t		xferred, sensecount, loginfo = 0;
+	struct scsi_pkt		*pkt;
+	struct scsi_arq_status	*arqstat;
+	struct buf		*bp;
+	mptsas_target_t		*ptgt = cmd->cmd_tgt_addr;
+	uint8_t			*sensedata = NULL;
+
+	if ((cmd->cmd_flags & (CFLAG_SCBEXTERN | CFLAG_EXTARQBUFVALID)) ==
+	    (CFLAG_SCBEXTERN | CFLAG_EXTARQBUFVALID)) {
+		bp = cmd->cmd_ext_arq_buf;
+	} else {
+		bp = cmd->cmd_arq_buf;
+	}
+
+	scsi_status = ddi_get8(mpt->m_acc_reply_frame_hdl, &reply->SCSIStatus);
+	ioc_status = ddi_get16(mpt->m_acc_reply_frame_hdl, &reply->IOCStatus);
+	scsi_state = ddi_get8(mpt->m_acc_reply_frame_hdl, &reply->SCSIState);
+	xferred = ddi_get32(mpt->m_acc_reply_frame_hdl, &reply->TransferCount);
+	sensecount = ddi_get32(mpt->m_acc_reply_frame_hdl, &reply->SenseCount);
+
+	if (ioc_status & MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
+		loginfo = ddi_get32(mpt->m_acc_reply_frame_hdl,
+		    &reply->IOCLogInfo);
+		mptsas_log(mpt, CE_NOTE,
+		    "?Log info 0x%x received for target %d.\n"
+		    "\tscsi_status=0x%x, ioc_status=0x%x, scsi_state=0x%x",
+		    loginfo, Tgt(cmd), scsi_status, ioc_status,
+		    scsi_state);
+	}
+
+	NDBG31(("\t\tscsi_status=0x%x, ioc_status=0x%x, scsi_state=0x%x",
+	    scsi_status, ioc_status, scsi_state));
+
+	pkt = CMD2PKT(cmd);
+	*(pkt->pkt_scbp) = scsi_status;
+
+	if (loginfo == 0x31170000) {
+		/*
+		 * if loginfo PL_LOGINFO_CODE_IO_DEVICE_MISSING_DELAY_RETRY
+		 * 0x31170000 comes, that means the device missing delay
+		 * is in progressing, the command need retry later.
+		 */
+		*(pkt->pkt_scbp) = STATUS_BUSY;
+		return;
+	}
+
+	if ((scsi_state & MPI2_SCSI_STATE_NO_SCSI_STATUS) &&
+	    ((ioc_status & MPI2_IOCSTATUS_MASK) ==
+	    MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE)) {
+		pkt->pkt_reason = CMD_INCOMPLETE;
+		pkt->pkt_state |= STATE_GOT_BUS;
+		if (ptgt->m_reset_delay == 0) {
+			mptsas_set_throttle(mpt, ptgt,
+			    DRAIN_THROTTLE);
+		}
+		return;
+	}
+
+	switch (scsi_status) {
+	case MPI2_SCSI_STATUS_CHECK_CONDITION:
+		pkt->pkt_resid = (cmd->cmd_dmacount - xferred);
+		arqstat = (void*)(pkt->pkt_scbp);
+		arqstat->sts_rqpkt_status = *((struct scsi_status *)
+		    (pkt->pkt_scbp));
+		pkt->pkt_state |= (STATE_GOT_BUS | STATE_GOT_TARGET |
+		    STATE_SENT_CMD | STATE_GOT_STATUS | STATE_ARQ_DONE);
+		if (cmd->cmd_flags & CFLAG_XARQ) {
+			pkt->pkt_state |= STATE_XARQ_DONE;
+		}
+		if (pkt->pkt_resid != cmd->cmd_dmacount) {
+			pkt->pkt_state |= STATE_XFERRED_DATA;
+		}
+		arqstat->sts_rqpkt_reason = pkt->pkt_reason;
+		arqstat->sts_rqpkt_state  = pkt->pkt_state;
+		arqstat->sts_rqpkt_state |= STATE_XFERRED_DATA;
+		arqstat->sts_rqpkt_statistics = pkt->pkt_statistics;
+		sensedata = (uint8_t *)&arqstat->sts_sensedata;
+
+		bcopy((uchar_t *)bp->b_un.b_addr, sensedata,
+		    ((cmd->cmd_rqslen >= sensecount) ? sensecount :
+		    cmd->cmd_rqslen));
+		arqstat->sts_rqpkt_resid = (cmd->cmd_rqslen - sensecount);
+		cmd->cmd_flags |= CFLAG_CMDARQ;
+		/*
+		 * Set proper status for pkt if autosense was valid
+		 */
+		if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID) {
+			struct scsi_status zero_status = { 0 };
+			arqstat->sts_rqpkt_status = zero_status;
+		}
+
+		/*
+		 * ASC=0x47 is parity error
+		 * ASC=0x48 is initiator detected error received
+		 */
+		if ((scsi_sense_key(sensedata) == KEY_ABORTED_COMMAND) &&
+		    ((scsi_sense_asc(sensedata) == 0x47) ||
+		    (scsi_sense_asc(sensedata) == 0x48))) {
+			mptsas_log(mpt, CE_NOTE, "Aborted_command!");
+		}
+
+		/*
+		 * ASC/ASCQ=0x3F/0x0E means report_luns data changed
+		 * ASC/ASCQ=0x25/0x00 means invalid lun
+		 */
+		if (((scsi_sense_key(sensedata) == KEY_UNIT_ATTENTION) &&
+		    (scsi_sense_asc(sensedata) == 0x3F) &&
+		    (scsi_sense_ascq(sensedata) == 0x0E)) ||
+		    ((scsi_sense_key(sensedata) == KEY_ILLEGAL_REQUEST) &&
+		    (scsi_sense_asc(sensedata) == 0x25) &&
+		    (scsi_sense_ascq(sensedata) == 0x00))) {
+			mptsas_topo_change_list_t *topo_node = NULL;
+
+			topo_node = kmem_zalloc(
+			    sizeof (mptsas_topo_change_list_t),
+			    KM_NOSLEEP);
+			if (topo_node == NULL) {
+				mptsas_log(mpt, CE_NOTE, "No memory"
+				    "resource for handle SAS dynamic"
+				    "reconfigure.\n");
+				break;
+			}
+			topo_node->mpt = mpt;
+			topo_node->event = MPTSAS_DR_EVENT_RECONFIG_TARGET;
+			topo_node->un.phymask = ptgt->m_phymask;
+			topo_node->devhdl = ptgt->m_devhdl;
+			topo_node->object = (void *)ptgt;
+			topo_node->flags = MPTSAS_TOPO_FLAG_LUN_ASSOCIATED;
+
+			if ((ddi_taskq_dispatch(mpt->m_dr_taskq,
+			    mptsas_handle_dr,
+			    (void *)topo_node,
+			    DDI_NOSLEEP)) != DDI_SUCCESS) {
+				mptsas_log(mpt, CE_NOTE, "mptsas start taskq"
+				    "for handle SAS dynamic reconfigure"
+				    "failed. \n");
+			}
+		}
+		break;
+	case MPI2_SCSI_STATUS_GOOD:
+		switch (ioc_status & MPI2_IOCSTATUS_MASK) {
+		case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
+			pkt->pkt_reason = CMD_DEV_GONE;
+			pkt->pkt_state |= STATE_GOT_BUS;
+			if (ptgt->m_reset_delay == 0) {
+				mptsas_set_throttle(mpt, ptgt, DRAIN_THROTTLE);
+			}
+			NDBG31(("lost disk for target%d, command:%x",
+			    Tgt(cmd), pkt->pkt_cdbp[0]));
+			break;
+		case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN:
+			NDBG31(("data overrun: xferred=%d", xferred));
+			NDBG31(("dmacount=%d", cmd->cmd_dmacount));
+			pkt->pkt_reason = CMD_DATA_OVR;
+			pkt->pkt_state |= (STATE_GOT_BUS | STATE_GOT_TARGET
+			    | STATE_SENT_CMD | STATE_GOT_STATUS
+			    | STATE_XFERRED_DATA);
+			pkt->pkt_resid = 0;
+			break;
+		case MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:
+		case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN:
+			NDBG31(("data underrun: xferred=%d", xferred));
+			NDBG31(("dmacount=%d", cmd->cmd_dmacount));
+			pkt->pkt_state |= (STATE_GOT_BUS | STATE_GOT_TARGET
+			    | STATE_SENT_CMD | STATE_GOT_STATUS);
+			pkt->pkt_resid = (cmd->cmd_dmacount - xferred);
+			if (pkt->pkt_resid != cmd->cmd_dmacount) {
+				pkt->pkt_state |= STATE_XFERRED_DATA;
+			}
+			break;
+		case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED:
+			mptsas_set_pkt_reason(mpt,
+			    cmd, CMD_RESET, STAT_BUS_RESET);
+			break;
+		case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED:
+		case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED:
+			mptsas_set_pkt_reason(mpt,
+			    cmd, CMD_RESET, STAT_DEV_RESET);
+			break;
+		case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR:
+		case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR:
+			pkt->pkt_state |= (STATE_GOT_BUS | STATE_GOT_TARGET);
+			mptsas_set_pkt_reason(mpt,
+			    cmd, CMD_TERMINATED, STAT_TERMINATED);
+			break;
+		case MPI2_IOCSTATUS_INSUFFICIENT_RESOURCES:
+		case MPI2_IOCSTATUS_BUSY:
+			/*
+			 * set throttles to drain
+			 */
+			ptgt = (mptsas_target_t *)mptsas_hash_traverse(
+			    &mpt->m_active->m_tgttbl, MPTSAS_HASH_FIRST);
+			while (ptgt != NULL) {
+				mptsas_set_throttle(mpt, ptgt, DRAIN_THROTTLE);
+
+				ptgt = (mptsas_target_t *)mptsas_hash_traverse(
+				    &mpt->m_active->m_tgttbl, MPTSAS_HASH_NEXT);
+			}
+
+			/*
+			 * retry command
+			 */
+			cmd->cmd_flags |= CFLAG_RETRY;
+			cmd->cmd_pkt_flags |= FLAG_HEAD;
+
+			(void) mptsas_accept_pkt(mpt, cmd);
+			break;
+		default:
+			mptsas_log(mpt, CE_WARN,
+			    "unknown ioc_status = %x\n", ioc_status);
+			mptsas_log(mpt, CE_CONT, "scsi_state = %x, transfer "
+			    "count = %x, scsi_status = %x", scsi_state,
+			    xferred, scsi_status);
+			break;
+		}
+		break;
+	case MPI2_SCSI_STATUS_TASK_SET_FULL:
+		mptsas_handle_qfull(mpt, cmd);
+		break;
+	case MPI2_SCSI_STATUS_BUSY:
+		NDBG31(("scsi_status busy received"));
+		break;
+	case MPI2_SCSI_STATUS_RESERVATION_CONFLICT:
+		NDBG31(("scsi_status reservation conflict received"));
+		break;
+	default:
+		mptsas_log(mpt, CE_WARN, "scsi_status=%x, ioc_status=%x\n",
+		    scsi_status, ioc_status);
+		mptsas_log(mpt, CE_WARN,
+		    "mptsas_process_intr: invalid scsi status\n");
+		break;
+	}
+}
+
+static void
+mptsas_check_task_mgt(mptsas_t *mpt, pMpi2SCSIManagementReply_t reply,
+	mptsas_cmd_t *cmd)
+{
+	uint8_t		task_type;
+	uint16_t	ioc_status;
+	uint32_t	log_info;
+	uint16_t	dev_handle;
+	struct scsi_pkt *pkt = CMD2PKT(cmd);
+
+	task_type = ddi_get8(mpt->m_acc_reply_frame_hdl, &reply->TaskType);
+	ioc_status = ddi_get16(mpt->m_acc_reply_frame_hdl, &reply->IOCStatus);
+	log_info = ddi_get32(mpt->m_acc_reply_frame_hdl, &reply->IOCLogInfo);
+	dev_handle = ddi_get16(mpt->m_acc_reply_frame_hdl, &reply->DevHandle);
+
+	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
+		mptsas_log(mpt, CE_WARN, "mptsas_check_task_mgt: Task 0x%x "
+		    "failed. IOCStatus=0x%x IOCLogInfo=0x%x target=%d\n",
+		    task_type, ioc_status, log_info, dev_handle);
+		pkt->pkt_reason = CMD_INCOMPLETE;
+		return;
+	}
+
+	switch (task_type) {
+	case MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK:
+	case MPI2_SCSITASKMGMT_TASKTYPE_CLEAR_TASK_SET:
+	case MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK:
+	case MPI2_SCSITASKMGMT_TASKTYPE_CLR_ACA:
+	case MPI2_SCSITASKMGMT_TASKTYPE_QRY_TASK_SET:
+	case MPI2_SCSITASKMGMT_TASKTYPE_QRY_UNIT_ATTENTION:
+		break;
+	case MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET:
+	case MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET:
+	case MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET:
+		mptsas_flush_target(mpt, dev_handle, Lun(cmd), task_type);
+		break;
+	default:
+		mptsas_log(mpt, CE_WARN, "Unknown task management type %d.",
+		    task_type);
+		mptsas_log(mpt, CE_WARN, "ioc status = %x", ioc_status);
+		break;
+	}
+}
+
+static void
+mptsas_doneq_thread(mptsas_doneq_thread_arg_t *arg)
+{
+	mptsas_t			*mpt = arg->mpt;
+	uint64_t			t = arg->t;
+	mptsas_cmd_t			*cmd;
+	struct scsi_pkt			*pkt;
+	mptsas_doneq_thread_list_t	*item = &mpt->m_doneq_thread_id[t];
+
+	mutex_enter(&item->mutex);
+	while (item->flag & MPTSAS_DONEQ_THREAD_ACTIVE) {
+		if (!item->doneq) {
+			cv_wait(&item->cv, &item->mutex);
+		}
+		pkt = NULL;
+		if ((cmd = mptsas_doneq_thread_rm(mpt, t)) != NULL) {
+			cmd->cmd_flags |= CFLAG_COMPLETED;
+			pkt = CMD2PKT(cmd);
+		}
+		mutex_exit(&item->mutex);
+		if (pkt) {
+			mptsas_pkt_comp(pkt, cmd);
+		}
+		mutex_enter(&item->mutex);
+	}
+	mutex_exit(&item->mutex);
+	mutex_enter(&mpt->m_doneq_mutex);
+	mpt->m_doneq_thread_n--;
+	cv_broadcast(&mpt->m_doneq_thread_cv);
+	mutex_exit(&mpt->m_doneq_mutex);
+}
+
+
+/*
+ * mpt interrupt handler.
+ */
+static uint_t
+mptsas_intr(caddr_t arg1, caddr_t arg2)
+{
+	mptsas_t			*mpt = (void *)arg1;
+	uint32_t			reply_index;
+	pMpi2ReplyDescriptorsUnion_t	reply_desc_union;
+	uchar_t				did_reply = FALSE;
+
+	NDBG1(("mptsas_intr: arg1 0x%p arg2 0x%p", (void *)arg1, (void *)arg2));
+
+	mutex_enter(&mpt->m_mutex);
+
+	/*
+	 * If interrupts are shared by two channels then
+	 * check whether this interrupt is genuinely for this
+	 * channel by making sure first the chip is in high
+	 * power state.
+	 */
+	if ((mpt->m_options & MPTSAS_OPT_PM) &&
+	    (mpt->m_power_level != PM_LEVEL_D0)) {
+		mutex_exit(&mpt->m_mutex);
+		return (DDI_INTR_UNCLAIMED);
+	}
+
+	/*
+	 * Save the current reply post host index value.
+	 */
+	reply_index = mpt->m_post_index;
+
+	/*
+	 * Read the istat register.
+	 */
+	if ((INTPENDING(mpt)) != 0) {
+		/*
+		 * read fifo until empty.
+		 */
+		(void) ddi_dma_sync(mpt->m_dma_post_queue_hdl, 0, 0,
+		    DDI_DMA_SYNC_FORCPU);
+#ifndef __lock_lint
+		_NOTE(CONSTCOND)
+#endif
+		while (TRUE) {
+			reply_desc_union = (pMpi2ReplyDescriptorsUnion_t)
+			    MPTSAS_GET_NEXT_REPLY(mpt, reply_index);
+
+			if (ddi_get32(mpt->m_acc_post_queue_hdl,
+			    &reply_desc_union->Words.Low) == 0xFFFFFFFF ||
+			    ddi_get32(mpt->m_acc_post_queue_hdl,
+			    &reply_desc_union->Words.High) == 0xFFFFFFFF) {
+				break;
+			}
+
+			/*
+			 * The reply is valid, process it according to its
+			 * type.  Also, set a flag for updated the reply index
+			 * after they've all been processed.
+			 */
+			did_reply = TRUE;
+
+			mptsas_process_intr(mpt, reply_desc_union);
+
+			if (++reply_index == mpt->m_post_queue_depth) {
+				reply_index = 0;
+			}
+			mpt->m_post_index = reply_index;
+		}
+
+		/*
+		 * Update the global reply index if at least one reply was
+		 * processed.
+		 */
+		if (did_reply) {
+			ddi_put32(mpt->m_datap,
+			    &mpt->m_reg->ReplyPostHostIndex, reply_index);
+		}
+	} else {
+		if (mpt->m_polled_intr) {
+			mpt->m_polled_intr = 0;
+			mutex_exit(&mpt->m_mutex);
+			return (DDI_INTR_CLAIMED);
+		}
+		mutex_exit(&mpt->m_mutex);
+		return (DDI_INTR_UNCLAIMED);
+	}
+	NDBG1(("mptsas_intr complete"));
+
+	/*
+	 * If no helper threads are created, process the doneq in ISR.
+	 * If helpers are created, use the doneq length as a metric to
+	 * measure the load on the interrupt CPU. If it is long enough,
+	 * which indicates the load is heavy, then we deliver the IO
+	 * completions to the helpers.
+	 * this measurement has some limitations although, it is simple
+	 * and straightforward and works well for most of the cases at
+	 * present.
+	 */
+
+	if (!mpt->m_doneq_thread_n ||
+	    (mpt->m_doneq_len <= mpt->m_doneq_length_threshold)) {
+		mptsas_doneq_empty(mpt);
+	} else {
+		mptsas_deliver_doneq_thread(mpt);
+	}
+
+	/*
+	 * If there are queued cmd, start them now.
+	 */
+	if (mpt->m_waitq != NULL) {
+		mptsas_restart_waitq(mpt);
+	}
+
+	if (mpt->m_polled_intr) {
+		mpt->m_polled_intr = 0;
+	}
+
+	mutex_exit(&mpt->m_mutex);
+	return (DDI_INTR_CLAIMED);
+}
+
+static void
+mptsas_process_intr(mptsas_t *mpt,
+    pMpi2ReplyDescriptorsUnion_t reply_desc_union)
+{
+	uint8_t	reply_type;
+
+	ASSERT(mutex_owned(&mpt->m_mutex));
+
+	/*
+	 * The reply is valid, process it according to its
+	 * type.  Also, set a flag for updated the reply index
+	 * after they've all been processed.
+	 */
+	reply_type = ddi_get8(mpt->m_acc_post_queue_hdl,
+	    &reply_desc_union->Default.ReplyFlags);
+	reply_type &= MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK;
+	if (reply_type == MPI2_RPY_DESCRIPT_FLAGS_SCSI_IO_SUCCESS) {
+		mptsas_handle_scsi_io_success(mpt, reply_desc_union);
+	} else if (reply_type == MPI2_RPY_DESCRIPT_FLAGS_ADDRESS_REPLY) {
+		mptsas_handle_address_reply(mpt, reply_desc_union);
+	} else {
+		mptsas_log(mpt, CE_WARN, "?Bad reply type %x", reply_type);
+		ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
+	}
+
+	/*
+	 * Clear the reply descriptor for re-use and increment
+	 * index.
+	 */
+	ddi_put64(mpt->m_acc_post_queue_hdl,
+	    &((uint64_t *)(void *)mpt->m_post_queue)[mpt->m_post_index],
+	    0xFFFFFFFFFFFFFFFF);
+	(void) ddi_dma_sync(mpt->m_dma_post_queue_hdl, 0, 0,
+	    DDI_DMA_SYNC_FORDEV);
+}
+
+/*
+ * handle qfull condition
+ */
+static void
+mptsas_handle_qfull(mptsas_t *mpt, mptsas_cmd_t *cmd)
+{
+	mptsas_target_t	*ptgt = cmd->cmd_tgt_addr;
+
+	if ((++cmd->cmd_qfull_retries > ptgt->m_qfull_retries) ||
+	    (ptgt->m_qfull_retries == 0)) {
+		/*
+		 * We have exhausted the retries on QFULL, or,
+		 * the target driver has indicated that it
+		 * wants to handle QFULL itself by setting
+		 * qfull-retries capability to 0. In either case
+		 * we want the target driver's QFULL handling
+		 * to kick in. We do this by having pkt_reason
+		 * as CMD_CMPLT and pkt_scbp as STATUS_QFULL.
+		 */
+		mptsas_set_throttle(mpt, ptgt, DRAIN_THROTTLE);
+	} else {
+		if (ptgt->m_reset_delay == 0) {
+			ptgt->m_t_throttle =
+			    max((ptgt->m_t_ncmds - 2), 0);
+		}
+
+		cmd->cmd_pkt_flags |= FLAG_HEAD;
+		cmd->cmd_flags &= ~(CFLAG_TRANFLAG);
+		cmd->cmd_flags |= CFLAG_RETRY;
+
+		(void) mptsas_accept_pkt(mpt, cmd);
+
+		/*
+		 * when target gives queue full status with no commands
+		 * outstanding (m_t_ncmds == 0), throttle is set to 0
+		 * (HOLD_THROTTLE), and the queue full handling start
+		 * (see psarc/1994/313); if there are commands outstanding,
+		 * throttle is set to (m_t_ncmds - 2)
+		 */
+		if (ptgt->m_t_throttle == HOLD_THROTTLE) {
+			/*
+			 * By setting throttle to QFULL_THROTTLE, we
+			 * avoid submitting new commands and in
+			 * mptsas_restart_cmd find out slots which need
+			 * their throttles to be cleared.
+			 */
+			mptsas_set_throttle(mpt, ptgt, QFULL_THROTTLE);
+			if (mpt->m_restart_cmd_timeid == 0) {
+				mpt->m_restart_cmd_timeid =
+				    timeout(mptsas_restart_cmd, mpt,
+				    ptgt->m_qfull_retry_interval);
+			}
+		}
+	}
+}
+
+uint8_t
+mptsas_phymask_to_physport(mptsas_t *mpt, uint8_t phymask)
+{
+	int i;
+
+	/*
+	 * RAID doesn't have valid phymask and physport so we use phymask == 0
+	 * and physport == 0xff to indicate that it's RAID.
+	 */
+	if (phymask == 0) {
+		return (0xff);
+	}
+	for (i = 0; i < 8; i++) {
+		if (phymask & (1 << i)) {
+			break;
+		}
+	}
+	return (mpt->m_phy_info[i].port_num);
+}
+uint8_t
+mptsas_physport_to_phymask(mptsas_t *mpt, uint8_t physport)
+{
+	uint8_t		phy_mask = 0;
+	uint8_t		i = 0;
+
+	NDBG20(("mptsas%d physport_to_phymask enter", mpt->m_instance));
+
+	ASSERT(mutex_owned(&mpt->m_mutex));
+
+	/*
+	 * If physport is 0xFF, this is a RAID volume.  Use phymask of 0.
+	 */
+	if (physport == 0xFF) {
+		return (0);
+	}
+
+	for (i = 0; i < MPTSAS_MAX_PHYS; i++) {
+		if (mpt->m_phy_info[i].attached_devhdl &&
+		    (mpt->m_phy_info[i].phy_mask != 0) &&
+		    (mpt->m_phy_info[i].port_num == physport)) {
+			phy_mask = mpt->m_phy_info[i].phy_mask;
+			break;
+		}
+	}
+	NDBG20(("mptsas%d physport_to_phymask:physport :%x phymask :%x, ",
+	    mpt->m_instance, physport, phy_mask));
+	return (phy_mask);
+}
+
+/*
+ * mpt free device handle after device gone, by use of passthrough
+ */
+static int
+mptsas_free_devhdl(mptsas_t *mpt, uint16_t devhdl)
+{
+	Mpi2SasIoUnitControlRequest_t	req;
+	Mpi2SasIoUnitControlReply_t	rep;
+	int				ret;
+
+	ASSERT(mutex_owned(&mpt->m_mutex));
+
+	/*
+	 * Need to compose a SAS IO Unit Control request message
+	 * and call mptsas_do_passthru() function
+	 */
+	bzero(&req, sizeof (req));
+	bzero(&rep, sizeof (rep));
+
+	req.Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL;
+	req.Operation = MPI2_SAS_OP_REMOVE_DEVICE;
+	req.DevHandle = LE_16(devhdl);
+
+	ret = mptsas_do_passthru(mpt, (uint8_t *)&req, (uint8_t *)&rep, NULL,
+	    sizeof (req), sizeof (rep), NULL, 0, NULL, 0, 60, FKIOCTL);
+	if (ret != 0) {
+		cmn_err(CE_WARN, "mptsas_free_devhdl: passthru SAS IO Unit "
+		    "Control error %d", ret);
+		return (DDI_FAILURE);
+	}
+
+	/* do passthrough success, check the ioc status */
+	if (LE_16(rep.IOCStatus) != MPI2_IOCSTATUS_SUCCESS) {
+		cmn_err(CE_WARN, "mptsas_free_devhdl: passthru SAS IO Unit "
+		    "Control IOCStatus %d", LE_16(rep.IOCStatus));
+		return (DDI_FAILURE);
+	}
+
+	return (DDI_SUCCESS);
+}
+
+static void
+mptsas_update_phymask(mptsas_t *mpt)
+{
+	uint8_t	mask = 0, phy_mask;
+	char	*phy_mask_name;
+	uint8_t current_port;
+	int	i, j;
+
+	NDBG20(("mptsas%d update phymask ", mpt->m_instance));
+
+	ASSERT(mutex_owned(&mpt->m_mutex));
+
+	(void) mptsas_get_sas_io_unit_page(mpt);
+
+	phy_mask_name = kmem_zalloc(8, KM_SLEEP);
+
+	for (i = 0; i < mpt->m_num_phys; i++) {
+		phy_mask = 0x00;
+
+		if (mpt->m_phy_info[i].attached_devhdl == 0)
+			continue;
+
+		bzero(phy_mask_name, sizeof (phy_mask_name));
+
+		current_port = mpt->m_phy_info[i].port_num;
+
+		if ((mask & (1 << i)) != 0)
+			continue;
+
+		for (j = 0; j < mpt->m_num_phys; j++) {
+			if (mpt->m_phy_info[j].attached_devhdl &&
+			    (mpt->m_phy_info[j].port_num == current_port)) {
+				phy_mask |= (1 << j);
+			}
+		}
+		mask = mask | phy_mask;
+
+		for (j = 0; j < mpt->m_num_phys; j++) {
+			if ((phy_mask >> j) & 0x01) {
+				mpt->m_phy_info[j].phy_mask = phy_mask;
+			}
+		}
+
+		(void) sprintf(phy_mask_name, "%x", phy_mask);
+
+		mutex_exit(&mpt->m_mutex);
+		/*
+		 * register a iport, if the port has already been existed
+		 * SCSA will do nothing and just return.
+		 */
+		(void) scsi_hba_iport_register(mpt->m_dip, phy_mask_name);
+		mutex_enter(&mpt->m_mutex);
+	}
+	kmem_free(phy_mask_name, 8);
+	NDBG20(("mptsas%d update phymask return", mpt->m_instance));
+}
+
+/*
+ * mptsas_handle_dr is a task handler for DR, the DR action includes:
+ * 1. Directly attched Device Added/Removed.
+ * 2. Expander Device Added/Removed.
+ * 3. Indirectly Attached Device Added/Expander.
+ * 4. LUNs of a existing device status change.
+ * 5. RAID volume created/deleted.
+ * 6. Member of RAID volume is released because of RAID deletion.
+ * 7. Physical disks are removed because of RAID creation.
+ */
+static void
+mptsas_handle_dr(void *args) {
+	mptsas_topo_change_list_t	*topo_node = NULL;
+	mptsas_topo_change_list_t	*save_node = NULL;
+	mptsas_t			*mpt;
+	dev_info_t			*parent = NULL;
+	uint8_t				phymask = 0;
+	char				*phy_mask_name;
+	uint8_t				flags = 0, physport = 0xff;
+	uint8_t				port_update = 0;
+	uint_t				event;
+
+	topo_node = (mptsas_topo_change_list_t *)args;
+
+	mpt = topo_node->mpt;
+	event = topo_node->event;
+	flags = topo_node->flags;
+
+	phy_mask_name = kmem_zalloc(8, KM_SLEEP);
+
+	NDBG20(("mptsas%d handle_dr enter", mpt->m_instance));
+
+	switch (event) {
+	case MPTSAS_DR_EVENT_RECONFIG_TARGET:
+		if ((flags == MPTSAS_TOPO_FLAG_DIRECT_ATTACHED_DEVICE) ||
+		    (flags == MPTSAS_TOPO_FLAG_EXPANDER_ATTACHED_DEVICE) ||
+		    (flags == MPTSAS_TOPO_FLAG_RAID_PHYSDRV_ASSOCIATED)) {
+			/*
+			 * Direct attached or expander attached device added
+			 * into system or a Phys Disk that is being unhidden.
+			 */
+			port_update = 1;
+		}
+		break;
+	case MPTSAS_DR_EVENT_RECONFIG_SMP:
+		/*
+		 * New expander added into system, it must be the head
+		 * of topo_change_list_t
+		 */
+		port_update = 1;
+		break;
+	default:
+		port_update = 0;
+		break;
+	}
+	/*
+	 * All cases port_update == 1 may cause initiator port form change
+	 */
+	mutex_enter(&mpt->m_mutex);
+	if (mpt->m_port_chng && port_update) {
+		/*
+		 * mpt->m_port_chng flag indicates some PHYs of initiator
+		 * port have changed to online. So when expander added or
+		 * directly attached device online event come, we force to
+		 * update port information by issueing SAS IO Unit Page and
+		 * update PHYMASKs.
+		 */
+		(void) mptsas_update_phymask(mpt);
+		mpt->m_port_chng = 0;
+
+	}
+	mutex_exit(&mpt->m_mutex);
+	while (topo_node) {
+		phymask = 0;
+		if (parent == NULL) {
+			physport = topo_node->un.physport;
+			event = topo_node->event;
+			flags = topo_node->flags;
+			if (event & (MPTSAS_DR_EVENT_OFFLINE_TARGET |
+			    MPTSAS_DR_EVENT_OFFLINE_SMP)) {
+				/*
+				 * For all offline events, phymask is known
+				 */
+				phymask = topo_node->un.phymask;
+				goto find_parent;
+			}
+			if (event & MPTSAS_TOPO_FLAG_REMOVE_HANDLE) {
+				goto handle_topo_change;
+			}
+			if (flags & MPTSAS_TOPO_FLAG_LUN_ASSOCIATED) {
+				phymask = topo_node->un.phymask;
+				goto find_parent;
+			}
+
+			if ((flags ==
+			    MPTSAS_TOPO_FLAG_RAID_PHYSDRV_ASSOCIATED) &&
+			    (event == MPTSAS_DR_EVENT_RECONFIG_TARGET)) {
+				/*
+				 * There is no any field in IR_CONFIG_CHANGE
+				 * event indicate physport/phynum, let's get
+				 * parent after SAS Device Page0 request.
+				 */
+				goto handle_topo_change;
+			}
+
+			mutex_enter(&mpt->m_mutex);
+			if (flags == MPTSAS_TOPO_FLAG_DIRECT_ATTACHED_DEVICE) {
+				/*
+				 * If the direct attached device added or a
+				 * phys disk is being unhidden, argument
+				 * physport actually is PHY#, so we have to get
+				 * phymask according PHY#.
+				 */
+				physport = mpt->m_phy_info[physport].port_num;
+			}
+
+			/*
+			 * Translate physport to phymask so that we can search
+			 * parent dip.
+			 */
+			phymask = mptsas_physport_to_phymask(mpt,
+			    physport);
+			mutex_exit(&mpt->m_mutex);
+
+find_parent:
+			bzero(phy_mask_name, 8);
+			/*
+			 * For RAID topology change node, write the iport name
+			 * as v0.
+			 */
+			if (flags & MPTSAS_TOPO_FLAG_RAID_ASSOCIATED) {
+				(void) sprintf(phy_mask_name, "v0");
+			} else {
+				/*
+				 * phymask can bo 0 if the drive has been
+				 * pulled by the time an add event is
+				 * processed.  If phymask is 0, just skip this
+				 * event and continue.
+				 */
+				if (phymask == 0) {
+					mutex_enter(&mpt->m_mutex);
+					save_node = topo_node;
+					topo_node = topo_node->next;
+					ASSERT(save_node);
+					kmem_free(save_node,
+					    sizeof (mptsas_topo_change_list_t));
+					mutex_exit(&mpt->m_mutex);
+
+					parent = NULL;
+					continue;
+				}
+				(void) sprintf(phy_mask_name, "%x", phymask);
+			}
+			parent = scsi_hba_iport_find(mpt->m_dip,
+			    phy_mask_name);
+			if (parent == NULL) {
+				mptsas_log(mpt, CE_WARN, "Failed to find a "
+				    "iport, should not happen!");
+				goto out;
+			}
+
+		}
+		ASSERT(parent);
+handle_topo_change:
+
+		mutex_enter(&mpt->m_mutex);
+
+		mptsas_handle_topo_change(topo_node, parent);
+		save_node = topo_node;
+		topo_node = topo_node->next;
+		ASSERT(save_node);
+		kmem_free(save_node, sizeof (mptsas_topo_change_list_t));
+		mutex_exit(&mpt->m_mutex);
+
+		if ((flags == MPTSAS_TOPO_FLAG_DIRECT_ATTACHED_DEVICE) ||
+		    (flags == MPTSAS_TOPO_FLAG_RAID_PHYSDRV_ASSOCIATED) ||
+		    (flags == MPTSAS_TOPO_FLAG_RAID_ASSOCIATED)) {
+			/*
+			 * If direct attached device associated, make sure
+			 * reset the parent before start the next one. But
+			 * all devices associated with expander shares the
+			 * parent.  Also, reset parent if this is for RAID.
+			 */
+			parent = NULL;
+		}
+	}
+out:
+	kmem_free(phy_mask_name, 8);
+}
+
+static void
+mptsas_handle_topo_change(mptsas_topo_change_list_t *topo_node,
+    dev_info_t *parent)
+{
+	mptsas_target_t	*ptgt = NULL;
+	mptsas_smp_t	*psmp = NULL;
+	mptsas_t	*mpt = (void *)topo_node->mpt;
+	uint16_t	devhdl;
+	uint64_t	sas_wwn = 0;
+	int		rval = 0;
+	uint32_t	page_address;
+	uint8_t		phy, flags;
+	char		*addr = NULL;
+	dev_info_t	*lundip;
+	int		circ = 0, circ1 = 0;
+
+	NDBG20(("mptsas%d handle_topo_change enter", mpt->m_instance));
+
+	ASSERT(mutex_owned(&mpt->m_mutex));
+
+	switch (topo_node->event) {
+	case MPTSAS_DR_EVENT_RECONFIG_TARGET:
+	{
+		char *phy_mask_name;
+		uint8_t phymask = 0;
+
+		if (topo_node->flags == MPTSAS_TOPO_FLAG_RAID_ASSOCIATED) {
+			/*
+			 * Get latest RAID info.
+			 */
+			(void) mptsas_get_raid_info(mpt);
+			ptgt = mptsas_search_by_devhdl(
+			    &mpt->m_active->m_tgttbl, topo_node->devhdl);
+			if (ptgt == NULL)
+				break;
+		} else {
+			ptgt = (void *)topo_node->object;
+		}
+
+		if (ptgt == NULL) {
+			/*
+			 * Get sas device page 0 by DevHandle to make sure if
+			 * SSP/SATA end device exist.
+			 */
+			page_address = (MPI2_SAS_DEVICE_PGAD_FORM_HANDLE &
+			    MPI2_SAS_DEVICE_PGAD_FORM_MASK) |
+			    topo_node->devhdl;
+
+			rval = mptsas_get_target_device_info(mpt, page_address,
+			    &devhdl, &ptgt);
+			if (rval == DEV_INFO_WRONG_DEVICE_TYPE) {
+				mptsas_log(mpt, CE_NOTE,
+				    "mptsas_handle_topo_change: target %d is "
+				    "not a SAS/SATA device. \n",
+				    topo_node->devhdl);
+			} else if (rval == DEV_INFO_FAIL_ALLOC) {
+				mptsas_log(mpt, CE_NOTE,
+				    "mptsas_handle_topo_change: could not "
+				    "allocate memory. \n");
+			}
+			/*
+			 * If rval is DEV_INFO_PHYS_DISK than there is nothing
+			 * else to do, just leave.
+			 */
+			if (rval != DEV_INFO_SUCCESS) {
+				return;
+			}
+		}
+
+		ASSERT(ptgt->m_devhdl == topo_node->devhdl);
+
+		mutex_exit(&mpt->m_mutex);
+		flags = topo_node->flags;
+
+		if (flags == MPTSAS_TOPO_FLAG_RAID_PHYSDRV_ASSOCIATED) {
+			phymask = ptgt->m_phymask;
+			phy_mask_name = kmem_zalloc(8, KM_SLEEP);
+			(void) sprintf(phy_mask_name, "%x", phymask);
+			parent = scsi_hba_iport_find(mpt->m_dip,
+			    phy_mask_name);
+			kmem_free(phy_mask_name, 8);
+			if (parent == NULL) {
+				mptsas_log(mpt, CE_WARN, "Failed to find a "
+				    "iport for PD, should not happen!");
+				mutex_enter(&mpt->m_mutex);
+				break;
+			}
+		}
+
+		if (flags == MPTSAS_TOPO_FLAG_RAID_ASSOCIATED) {
+			ndi_devi_enter(parent, &circ1);
+			(void) mptsas_config_raid(parent, topo_node->devhdl,
+			    &lundip);
+			ndi_devi_exit(parent, circ1);
+		} else {
+			/*
+			 * hold nexus for bus configure
+			 */
+			ndi_devi_enter(scsi_vhci_dip, &circ);
+			ndi_devi_enter(parent, &circ1);
+			rval = mptsas_config_target(parent, ptgt);
+			/*
+			 * release nexus for bus configure
+			 */
+			ndi_devi_exit(parent, circ1);
+			ndi_devi_exit(scsi_vhci_dip, circ);
+
+		}
+		mutex_enter(&mpt->m_mutex);
+
+		NDBG20(("mptsas%d handle_topo_change to online devhdl:%x, "
+		    "phymask:%x.", mpt->m_instance, ptgt->m_devhdl,
+		    ptgt->m_phymask));
+		break;
+	}
+	case MPTSAS_DR_EVENT_OFFLINE_TARGET:
+	{
+		mptsas_hash_table_t *tgttbl = &mpt->m_active->m_tgttbl;
+		devhdl = topo_node->devhdl;
+		ptgt = mptsas_search_by_devhdl(tgttbl, devhdl);
+		if (ptgt == NULL)
+			break;
+
+		sas_wwn = ptgt->m_sas_wwn;
+		phy = ptgt->m_phynum;
+
+		addr = kmem_zalloc(SCSI_MAXNAMELEN, KM_SLEEP);
+
+		if (sas_wwn) {
+			(void) sprintf(addr, "w%016"PRIx64, sas_wwn);
+		} else {
+			(void) sprintf(addr, "p%x", phy);
+		}
+		ASSERT(ptgt->m_devhdl == devhdl);
+
+		if (topo_node->flags == MPTSAS_TOPO_FLAG_RAID_ASSOCIATED) {
+			/*
+			 * Get latest RAID info, if RAID volume status change
+			 */
+			(void) mptsas_get_raid_info(mpt);
+		}
+		/*
+		 * Abort all outstanding command on the device
+		 */
+		rval = mptsas_do_scsi_reset(mpt, devhdl);
+		if (rval) {
+			NDBG20(("mptsas%d handle_topo_change to reset target "
+			    "before offline devhdl:%x, phymask:%x, rval:%x",
+			    mpt->m_instance, ptgt->m_devhdl, ptgt->m_phymask,
+			    rval));
+		}
+
+		mutex_exit(&mpt->m_mutex);
+
+		ndi_devi_enter(scsi_vhci_dip, &circ);
+		ndi_devi_enter(parent, &circ1);
+		rval = mptsas_offline_target(parent, addr);
+		ndi_devi_exit(parent, circ1);
+		ndi_devi_exit(scsi_vhci_dip, circ);
+		NDBG20(("mptsas%d handle_topo_change to offine devhdl:%x, "
+		    "phymask:%x, rval:%x", mpt->m_instance,
+		    ptgt->m_devhdl, ptgt->m_phymask, rval));
+
+		kmem_free(addr, SCSI_MAXNAMELEN);
+
+		mutex_enter(&mpt->m_mutex);
+		if (rval == DDI_SUCCESS) {
+			mptsas_tgt_free(&mpt->m_active->m_tgttbl,
+			    ptgt->m_sas_wwn, ptgt->m_phymask);
+			ptgt = NULL;
+		} else {
+			/*
+			 * clean DR_INTRANSITION flag to allow I/O down to
+			 * PHCI driver since failover finished.
+			 * Invalidate the devhdl
+			 */
+			ptgt->m_devhdl = MPTSAS_INVALID_DEVHDL;
+			mutex_enter(&mpt->m_tx_waitq_mutex);
+			ptgt->m_dr_flag = MPTSAS_DR_INACTIVE;
+			mutex_exit(&mpt->m_tx_waitq_mutex);
+		}
+
+		/*
+		 * Send SAS IO Unit Control to free the dev handle
+		 */
+		flags = topo_node->flags;
+		if ((flags == MPTSAS_TOPO_FLAG_DIRECT_ATTACHED_DEVICE) ||
+		    (flags == MPTSAS_TOPO_FLAG_EXPANDER_ATTACHED_DEVICE)) {
+			rval = mptsas_free_devhdl(mpt, devhdl);
+
+			NDBG20(("mptsas%d handle_topo_change to remove "
+			    "devhdl:%x, rval:%x", mpt->m_instance, devhdl,
+			    rval));
+		}
+		break;
+	}
+	case MPTSAS_TOPO_FLAG_REMOVE_HANDLE:
+	{
+		devhdl = topo_node->devhdl;
+		/*
+		 * If this is the remove handle event, do a reset first.
+		 */
+		if (topo_node->event == MPTSAS_TOPO_FLAG_REMOVE_HANDLE) {
+			rval = mptsas_do_scsi_reset(mpt, devhdl);
+			if (rval) {
+				NDBG20(("mpt%d reset target before remove "
+				    "devhdl:%x, rval:%x", mpt->m_instance,
+				    devhdl, rval));
+			}
+		}
+
+		/*
+		 * Send SAS IO Unit Control to free the dev handle
+		 */
+		rval = mptsas_free_devhdl(mpt, devhdl);
+		NDBG20(("mptsas%d handle_topo_change to remove "
+		    "devhdl:%x, rval:%x", mpt->m_instance, devhdl,
+		    rval));
+		break;
+	}
+	case MPTSAS_DR_EVENT_RECONFIG_SMP:
+	{
+		mptsas_smp_t smp;
+		dev_info_t *smpdip;
+		mptsas_hash_table_t *smptbl = &mpt->m_active->m_smptbl;
+
+		devhdl = topo_node->devhdl;
+
+		page_address = (MPI2_SAS_EXPAND_PGAD_FORM_HNDL &
+		    MPI2_SAS_EXPAND_PGAD_FORM_MASK) | (uint32_t)devhdl;
+		rval = mptsas_get_sas_expander_page0(mpt, page_address, &smp);
+		if (rval != DDI_SUCCESS) {
+			mptsas_log(mpt, CE_WARN, "failed to online smp, "
+			    "handle %x", devhdl);
+			return;
+		}
+
+		psmp = mptsas_smp_alloc(smptbl, &smp);
+		if (psmp == NULL) {
+			return;
+		}
+
+		mutex_exit(&mpt->m_mutex);
+		ndi_devi_enter(parent, &circ1);
+		(void) mptsas_online_smp(parent, psmp, &smpdip);
+		ndi_devi_exit(parent, circ1);
+		mutex_enter(&mpt->m_mutex);
+		break;
+	}
+	case MPTSAS_DR_EVENT_OFFLINE_SMP:
+	{
+		mptsas_hash_table_t *smptbl = &mpt->m_active->m_smptbl;
+		devhdl = topo_node->devhdl;
+		psmp = mptsas_search_by_devhdl(smptbl, devhdl);
+		if (psmp == NULL)
+			break;
+		/*
+		 * The mptsas_smp_t data is released only if the dip is offlined
+		 * successfully.
+		 */
+		mutex_exit(&mpt->m_mutex);
+		ndi_devi_enter(parent, &circ1);
+		rval = mptsas_offline_smp(parent, psmp, NDI_DEVI_REMOVE);
+		ndi_devi_exit(parent, circ1);
+		mutex_enter(&mpt->m_mutex);
+		NDBG20(("mptsas%d handle_topo_change to remove devhdl:%x, "
+		    "rval:%x", mpt->m_instance, psmp->m_devhdl, rval));
+		if (rval == DDI_SUCCESS) {
+			mptsas_smp_free(smptbl, psmp->m_sasaddr,
+			    psmp->m_phymask);
+		} else {
+			psmp->m_devhdl = MPTSAS_INVALID_DEVHDL;
+		}
+		break;
+	}
+	default:
+		return;
+	}
+}
+
+/*
+ * Record the event if its type is enabled in mpt instance by ioctl.
+ */
+static void
+mptsas_record_event(void *args)
+{
+	m_replyh_arg_t			*replyh_arg;
+	pMpi2EventNotificationReply_t	eventreply;
+	uint32_t			event, rfm;
+	mptsas_t			*mpt;
+	int				i, j;
+	uint16_t			event_data_len;
+	boolean_t			sendAEN = FALSE;
+
+	replyh_arg = (m_replyh_arg_t *)args;
+	rfm = replyh_arg->rfm;
+	mpt = replyh_arg->mpt;
+
+	eventreply = (pMpi2EventNotificationReply_t)
+	    (mpt->m_reply_frame + (rfm - mpt->m_reply_frame_dma_addr));
+	event = ddi_get16(mpt->m_acc_reply_frame_hdl, &eventreply->Event);
+
+
+	/*
+	 * Generate a system event to let anyone who cares know that a
+	 * LOG_ENTRY_ADDED event has occurred.  This is sent no matter what the
+	 * event mask is set to.
+	 */
+	if (event == MPI2_EVENT_LOG_ENTRY_ADDED) {
+		sendAEN = TRUE;
+	}
+
+	/*
+	 * Record the event only if it is not masked.  Determine which dword
+	 * and bit of event mask to test.
+	 */
+	i = (uint8_t)(event / 32);
+	j = (uint8_t)(event % 32);
+	if ((i < 4) && ((1 << j) & mpt->m_event_mask[i])) {
+		i = mpt->m_event_number;
+		mpt->m_events[i].Type = event;
+		mpt->m_events[i].Number = ++mpt->m_event_number;
+		bzero(mpt->m_events[i].Data, MPTSAS_MAX_EVENT_DATA_LENGTH * 4);
+		event_data_len = ddi_get16(mpt->m_acc_reply_frame_hdl,
+		    &eventreply->EventDataLength);
+
+		if (event_data_len > 0) {
+			/*
+			 * Limit data to size in m_event entry
+			 */
+			if (event_data_len > MPTSAS_MAX_EVENT_DATA_LENGTH) {
+				event_data_len = MPTSAS_MAX_EVENT_DATA_LENGTH;
+			}
+			for (j = 0; j < event_data_len; j++) {
+				mpt->m_events[i].Data[j] =
+				    ddi_get32(mpt->m_acc_reply_frame_hdl,
+				    &(eventreply->EventData[j]));
+			}
+
+			/*
+			 * check for index wrap-around
+			 */
+			if (++i == MPTSAS_EVENT_QUEUE_SIZE) {
+				i = 0;
+			}
+			mpt->m_event_number = i;
+
+			/*
+			 * Set flag to send the event.
+			 */
+			sendAEN = TRUE;
+		}
+	}
+
+	/*
+	 * Generate a system event if flag is set to let anyone who cares know
+	 * that an event has occurred.
+	 */
+	if (sendAEN) {
+		(void) ddi_log_sysevent(mpt->m_dip, DDI_VENDOR_LSI, "MPT_SAS",
+		    "SAS", NULL, NULL, DDI_NOSLEEP);
+	}
+}
+
+#define	SMP_RESET_IN_PROGRESS MPI2_EVENT_SAS_TOPO_LR_SMP_RESET_IN_PROGRESS
+/*
+ * handle sync events from ioc in interrupt
+ * return value:
+ * DDI_SUCCESS: The event is handled by this func
+ * DDI_FAILURE: Event is not handled
+ */
+static int
+mptsas_handle_event_sync(void *args)
+{
+	m_replyh_arg_t			*replyh_arg;
+	pMpi2EventNotificationReply_t	eventreply;
+	uint32_t			event, rfm;
+	mptsas_t			*mpt;
+	uint_t				iocstatus;
+
+	replyh_arg = (m_replyh_arg_t *)args;
+	rfm = replyh_arg->rfm;
+	mpt = replyh_arg->mpt;
+
+	ASSERT(mutex_owned(&mpt->m_mutex));
+
+	eventreply = (pMpi2EventNotificationReply_t)
+	    (mpt->m_reply_frame + (rfm - mpt->m_reply_frame_dma_addr));
+	event = ddi_get16(mpt->m_acc_reply_frame_hdl, &eventreply->Event);
+
+	if (iocstatus = ddi_get16(mpt->m_acc_reply_frame_hdl,
+	    &eventreply->IOCStatus)) {
+		if (iocstatus == MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
+			mptsas_log(mpt, CE_WARN,
+			    "!mptsas_handle_event_sync: IOCStatus=0x%x, "
+			    "IOCLogInfo=0x%x", iocstatus,
+			    ddi_get32(mpt->m_acc_reply_frame_hdl,
+			    &eventreply->IOCLogInfo));
+		} else {
+			mptsas_log(mpt, CE_WARN,
+			    "mptsas_handle_event_sync: IOCStatus=0x%x, "
+			    "IOCLogInfo=0x%x", iocstatus,
+			    ddi_get32(mpt->m_acc_reply_frame_hdl,
+			    &eventreply->IOCLogInfo));
+		}
+	}
+
+	/*
+	 * figure out what kind of event we got and handle accordingly
+	 */
+	switch (event) {
+	case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST:
+	{
+		pMpi2EventDataSasTopologyChangeList_t	sas_topo_change_list;
+		uint8_t				num_entries, expstatus, phy;
+		uint8_t				phystatus, physport, state, i;
+		uint8_t				start_phy_num, link_rate;
+		uint16_t			dev_handle;
+		uint16_t			enc_handle, expd_handle;
+		char				string[80], curr[80], prev[80];
+		mptsas_topo_change_list_t	*topo_head = NULL;
+		mptsas_topo_change_list_t	*topo_tail = NULL;
+		mptsas_topo_change_list_t	*topo_node = NULL;
+		mptsas_target_t			*ptgt;
+		mptsas_smp_t			*psmp;
+		mptsas_hash_table_t		*tgttbl, *smptbl;
+		uint8_t				flags = 0, exp_flag;
+
+		NDBG20(("mptsas_handle_event_sync: SAS topology change"));
+
+		tgttbl = &mpt->m_active->m_tgttbl;
+		smptbl = &mpt->m_active->m_smptbl;
+
+		sas_topo_change_list = (pMpi2EventDataSasTopologyChangeList_t)
+		    eventreply->EventData;
+
+		enc_handle = ddi_get16(mpt->m_acc_reply_frame_hdl,
+		    &sas_topo_change_list->EnclosureHandle);
+		expd_handle = ddi_get16(mpt->m_acc_reply_frame_hdl,
+		    &sas_topo_change_list->ExpanderDevHandle);
+		num_entries = ddi_get8(mpt->m_acc_reply_frame_hdl,
+		    &sas_topo_change_list->NumEntries);
+		start_phy_num = ddi_get8(mpt->m_acc_reply_frame_hdl,
+		    &sas_topo_change_list->StartPhyNum);
+		expstatus = ddi_get8(mpt->m_acc_reply_frame_hdl,
+		    &sas_topo_change_list->ExpStatus);
+		physport = ddi_get8(mpt->m_acc_reply_frame_hdl,
+		    &sas_topo_change_list->PhysicalPort);
+
+		string[0] = 0;
+		if (expd_handle) {
+			flags = MPTSAS_TOPO_FLAG_EXPANDER_ASSOCIATED;
+			switch (expstatus) {
+			case MPI2_EVENT_SAS_TOPO_ES_ADDED:
+				(void) sprintf(string, " added");
+				/*
+				 * New expander device added
+				 */
+				mpt->m_port_chng = 1;
+				topo_node = kmem_zalloc(
+				    sizeof (mptsas_topo_change_list_t),
+				    KM_SLEEP);
+				topo_node->mpt = mpt;
+				topo_node->event = MPTSAS_DR_EVENT_RECONFIG_SMP;
+				topo_node->un.physport = physport;
+				topo_node->devhdl = expd_handle;
+				topo_node->flags = flags;
+				topo_node->object = NULL;
+				if (topo_head == NULL) {
+					topo_head = topo_tail = topo_node;
+				} else {
+					topo_tail->next = topo_node;
+					topo_tail = topo_node;
+				}
+				break;
+			case MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING:
+				(void) sprintf(string, " not responding, "
+				    "removed");
+				psmp = mptsas_search_by_devhdl(smptbl,
+				    expd_handle);
+				if (psmp == NULL)
+					break;
+
+				topo_node = kmem_zalloc(
+				    sizeof (mptsas_topo_change_list_t),
+				    KM_SLEEP);
+				topo_node->mpt = mpt;
+				topo_node->un.phymask = psmp->m_phymask;
+				topo_node->event = MPTSAS_DR_EVENT_OFFLINE_SMP;
+				topo_node->devhdl = expd_handle;
+				topo_node->flags = flags;
+				topo_node->object = NULL;
+				if (topo_head == NULL) {
+					topo_head = topo_tail = topo_node;
+				} else {
+					topo_tail->next = topo_node;
+					topo_tail = topo_node;
+				}
+				break;
+			case MPI2_EVENT_SAS_TOPO_ES_RESPONDING:
+				break;
+			case MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING:
+				(void) sprintf(string, " not responding, "
+				    "delaying removal");
+				break;
+			default:
+				break;
+			}
+		} else {
+			flags = MPTSAS_TOPO_FLAG_DIRECT_ATTACHED_DEVICE;
+		}
+
+		NDBG20(("SAS TOPOLOGY CHANGE for enclosure %x expander %x%s\n",
+		    enc_handle, expd_handle, string));
+		for (i = 0; i < num_entries; i++) {
+			phy = i + start_phy_num;
+			phystatus = ddi_get8(mpt->m_acc_reply_frame_hdl,
+			    &sas_topo_change_list->PHY[i].PhyStatus);
+			dev_handle = ddi_get16(mpt->m_acc_reply_frame_hdl,
+			    &sas_topo_change_list->PHY[i].AttachedDevHandle);
+			if (phystatus & MPI2_EVENT_SAS_TOPO_PHYSTATUS_VACANT) {
+				continue;
+			}
+			curr[0] = 0;
+			prev[0] = 0;
+			string[0] = 0;
+			switch (phystatus & MPI2_EVENT_SAS_TOPO_RC_MASK) {
+			case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED:
+			{
+				NDBG20(("mptsas%d phy %d physical_port %d "
+				    "dev_handle %d added", mpt->m_instance, phy,
+				    physport, dev_handle));
+				link_rate = ddi_get8(mpt->m_acc_reply_frame_hdl,
+				    &sas_topo_change_list->PHY[i].LinkRate);
+				state = (link_rate &
+				    MPI2_EVENT_SAS_TOPO_LR_CURRENT_MASK) >>
+				    MPI2_EVENT_SAS_TOPO_LR_CURRENT_SHIFT;
+				switch (state) {
+				case MPI2_EVENT_SAS_TOPO_LR_PHY_DISABLED:
+					(void) sprintf(curr, "is disabled");
+					break;
+				case MPI2_EVENT_SAS_TOPO_LR_NEGOTIATION_FAILED:
+					(void) sprintf(curr, "is offline, "
+					    "failed speed negotiation");
+					break;
+				case MPI2_EVENT_SAS_TOPO_LR_SATA_OOB_COMPLETE:
+					(void) sprintf(curr, "SATA OOB "
+					    "complete");
+					break;
+				case SMP_RESET_IN_PROGRESS:
+					(void) sprintf(curr, "SMP reset in "
+					    "progress");
+					break;
+				case MPI2_EVENT_SAS_TOPO_LR_RATE_1_5:
+					(void) sprintf(curr, "is online at "
+					    "1.5 Gbps");
+					break;
+				case MPI2_EVENT_SAS_TOPO_LR_RATE_3_0:
+					(void) sprintf(curr, "is online at 3.0 "
+					    "Gbps");
+					break;
+				case MPI2_EVENT_SAS_TOPO_LR_RATE_6_0:
+					(void) sprintf(curr, "is online at 6.0 "
+					    "Gbps");
+					break;
+				default:
+					(void) sprintf(curr, "state is "
+					    "unknown");
+					break;
+				}
+				/*
+				 * New target device added into the system.
+				 * Set association flag according to if an
+				 * expander is used or not.
+				 */
+				exp_flag =
+				    MPTSAS_TOPO_FLAG_EXPANDER_ATTACHED_DEVICE;
+				if (flags ==
+				    MPTSAS_TOPO_FLAG_EXPANDER_ASSOCIATED) {
+					flags = exp_flag;
+				}
+				topo_node = kmem_zalloc(
+				    sizeof (mptsas_topo_change_list_t),
+				    KM_SLEEP);
+				topo_node->mpt = mpt;
+				topo_node->event =
+				    MPTSAS_DR_EVENT_RECONFIG_TARGET;
+				if (expd_handle == 0) {
+					/*
+					 * Per MPI 2, if expander dev handle
+					 * is 0, it's a directly attached
+					 * device. So driver use PHY to decide
+					 * which iport is associated
+					 */
+					physport = phy;
+					mpt->m_port_chng = 1;
+				}
+				topo_node->un.physport = physport;
+				topo_node->devhdl = dev_handle;
+				topo_node->flags = flags;
+				topo_node->object = NULL;
+				if (topo_head == NULL) {
+					topo_head = topo_tail = topo_node;
+				} else {
+					topo_tail->next = topo_node;
+					topo_tail = topo_node;
+				}
+				break;
+			}
+			case MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING:
+			{
+				NDBG20(("mptsas%d phy %d physical_port %d "
+				    "dev_handle %d removed", mpt->m_instance,
+				    phy, physport, dev_handle));
+				/*
+				 * Set association flag according to if an
+				 * expander is used or not.
+				 */
+				exp_flag =
+				    MPTSAS_TOPO_FLAG_EXPANDER_ATTACHED_DEVICE;
+				if (flags ==
+				    MPTSAS_TOPO_FLAG_EXPANDER_ASSOCIATED) {
+					flags = exp_flag;
+				}
+				/*
+				 * Target device is removed from the system
+				 * Before the device is really offline from
+				 * from system.
+				 */
+				ptgt = mptsas_search_by_devhdl(tgttbl,
+				    dev_handle);
+				/*
+				 * If ptgt is NULL here, it means that the
+				 * DevHandle is not in the hash table.  This is
+				 * reasonable sometimes.  For example, if a
+				 * disk was pulled, then added, then pulled
+				 * again, the disk will not have been put into
+				 * the hash table because the add event will
+				 * have an invalid phymask.  BUT, this does not
+				 * mean that the DevHandle is invalid.  The
+				 * controller will still have a valid DevHandle
+				 * that must be removed.  To do this, use the
+				 * MPTSAS_TOPO_FLAG_REMOVE_HANDLE event.
+				 */
+				if (ptgt == NULL) {
+					topo_node = kmem_zalloc(
+					    sizeof (mptsas_topo_change_list_t),
+					    KM_SLEEP);
+					topo_node->mpt = mpt;
+					topo_node->un.phymask = 0;
+					topo_node->event =
+					    MPTSAS_TOPO_FLAG_REMOVE_HANDLE;
+					topo_node->devhdl = dev_handle;
+					topo_node->flags = flags;
+					topo_node->object = NULL;
+					if (topo_head == NULL) {
+						topo_head = topo_tail =
+						    topo_node;
+					} else {
+						topo_tail->next = topo_node;
+						topo_tail = topo_node;
+					}
+					break;
+				}
+
+				/*
+				 * Update DR flag immediately avoid I/O failure
+				 * before failover finish. Pay attention to the
+				 * mutex protect, we need grab m_tx_waitq_mutex
+				 * during set m_dr_flag because we won't add
+				 * the following command into waitq, instead,
+				 * we need return TRAN_BUSY in the tran_start
+				 * context.
+				 */
+				mutex_enter(&mpt->m_tx_waitq_mutex);
+				ptgt->m_dr_flag = MPTSAS_DR_INTRANSITION;
+				mutex_exit(&mpt->m_tx_waitq_mutex);
+
+				topo_node = kmem_zalloc(
+				    sizeof (mptsas_topo_change_list_t),
+				    KM_SLEEP);
+				topo_node->mpt = mpt;
+				topo_node->un.phymask = ptgt->m_phymask;
+				topo_node->event =
+				    MPTSAS_DR_EVENT_OFFLINE_TARGET;
+				topo_node->devhdl = dev_handle;
+				topo_node->flags = flags;
+				topo_node->object = NULL;
+				if (topo_head == NULL) {
+					topo_head = topo_tail = topo_node;
+				} else {
+					topo_tail->next = topo_node;
+					topo_tail = topo_node;
+				}
+
+				break;
+			}
+			case MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED:
+				link_rate = ddi_get8(mpt->m_acc_reply_frame_hdl,
+				    &sas_topo_change_list->PHY[i].LinkRate);
+				state = (link_rate &
+				    MPI2_EVENT_SAS_TOPO_LR_CURRENT_MASK) >>
+				    MPI2_EVENT_SAS_TOPO_LR_CURRENT_SHIFT;
+				switch (state) {
+				case MPI2_EVENT_SAS_TOPO_LR_PHY_DISABLED:
+					(void) sprintf(curr, "is disabled");
+					break;
+				case MPI2_EVENT_SAS_TOPO_LR_NEGOTIATION_FAILED:
+					(void) sprintf(curr, "is offline, "
+					    "failed speed negotiation");
+					break;
+				case MPI2_EVENT_SAS_TOPO_LR_SATA_OOB_COMPLETE:
+					(void) sprintf(curr, "SATA OOB "
+					    "complete");
+					break;
+				case SMP_RESET_IN_PROGRESS:
+					(void) sprintf(curr, "SMP reset in "
+					    "progress");
+					break;
+				case MPI2_EVENT_SAS_TOPO_LR_RATE_1_5:
+					(void) sprintf(curr, "is online at "
+					    "1.5 Gbps");
+					if ((expd_handle == 0) &&
+					    (enc_handle == 1)) {
+						mpt->m_port_chng = 1;
+					}
+					break;
+				case MPI2_EVENT_SAS_TOPO_LR_RATE_3_0:
+					(void) sprintf(curr, "is online at 3.0 "
+					    "Gbps");
+					if ((expd_handle == 0) &&
+					    (enc_handle == 1)) {
+						mpt->m_port_chng = 1;
+					}
+					break;
+				case MPI2_EVENT_SAS_TOPO_LR_RATE_6_0:
+					(void) sprintf(curr, "is online at "
+					    "6.0 Gbps");
+					if ((expd_handle == 0) &&
+					    (enc_handle == 1)) {
+						mpt->m_port_chng = 1;
+					}
+					break;
+				default:
+					(void) sprintf(curr, "state is "
+					    "unknown");
+					break;
+				}
+
+				state = (link_rate &
+				    MPI2_EVENT_SAS_TOPO_LR_PREV_MASK) >>
+				    MPI2_EVENT_SAS_TOPO_LR_PREV_SHIFT;
+				switch (state) {
+				case MPI2_EVENT_SAS_TOPO_LR_PHY_DISABLED:
+					(void) sprintf(prev, ", was disabled");
+					break;
+				case MPI2_EVENT_SAS_TOPO_LR_NEGOTIATION_FAILED:
+					(void) sprintf(prev, ", was offline, "
+					    "failed speed negotiation");
+					break;
+				case MPI2_EVENT_SAS_TOPO_LR_SATA_OOB_COMPLETE:
+					(void) sprintf(prev, ", was SATA OOB "
+					    "complete");
+					break;
+				case SMP_RESET_IN_PROGRESS:
+					(void) sprintf(prev, ", was SMP reset "
+					    "in progress");
+					break;
+				case MPI2_EVENT_SAS_TOPO_LR_RATE_1_5:
+					(void) sprintf(prev, ", was online at "
+					    "1.5 Gbps");
+					break;
+				case MPI2_EVENT_SAS_TOPO_LR_RATE_3_0:
+					(void) sprintf(prev, ", was online at "
+					    "3.0 Gbps");
+					break;
+				case MPI2_EVENT_SAS_TOPO_LR_RATE_6_0:
+					(void) sprintf(prev, ", was online at "
+					    "6.0 Gbps");
+					break;
+				default:
+				break;
+				}
+				(void) sprintf(&string[strlen(string)], "link "
+				    "changed, ");
+				break;
+			case MPI2_EVENT_SAS_TOPO_RC_NO_CHANGE:
+				continue;
+			case MPI2_EVENT_SAS_TOPO_RC_DELAY_NOT_RESPONDING:
+				(void) sprintf(&string[strlen(string)],
+				    "target not responding, delaying "
+				    "removal");
+				break;
+			}
+			NDBG20(("mptsas%d phy %d DevHandle %x, %s%s%s\n",
+			    mpt->m_instance, phy, dev_handle, string, curr,
+			    prev));
+		}
+		if (topo_head != NULL) {
+			/*
+			 * Launch DR taskq to handle topology change
+			 */
+			if ((ddi_taskq_dispatch(mpt->m_dr_taskq,
+			    mptsas_handle_dr, (void *)topo_head,
+			    DDI_NOSLEEP)) != DDI_SUCCESS) {
+				mptsas_log(mpt, CE_NOTE, "mptsas start taskq "
+				    "for handle SAS DR event failed. \n");
+			}
+		}
+		break;
+	}
+	case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST:
+	{
+		Mpi2EventDataIrConfigChangeList_t	*irChangeList;
+		mptsas_topo_change_list_t		*topo_head = NULL;
+		mptsas_topo_change_list_t		*topo_tail = NULL;
+		mptsas_topo_change_list_t		*topo_node = NULL;
+		mptsas_target_t				*ptgt;
+		mptsas_hash_table_t			*tgttbl;
+		uint8_t					num_entries, i, reason;
+		uint16_t				volhandle, diskhandle;
+
+		irChangeList = (pMpi2EventDataIrConfigChangeList_t)
+		    eventreply->EventData;
+		num_entries = ddi_get8(mpt->m_acc_reply_frame_hdl,
+		    &irChangeList->NumElements);
+
+		tgttbl = &mpt->m_active->m_tgttbl;
+
+		NDBG20(("mptsas%d IR_CONFIGURATION_CHANGE_LIST event received",
+		    mpt->m_instance));
+
+		for (i = 0; i < num_entries; i++) {
+			reason = ddi_get8(mpt->m_acc_reply_frame_hdl,
+			    &irChangeList->ConfigElement[i].ReasonCode);
+			volhandle = ddi_get16(mpt->m_acc_reply_frame_hdl,
+			    &irChangeList->ConfigElement[i].VolDevHandle);
+			diskhandle = ddi_get16(mpt->m_acc_reply_frame_hdl,
+			    &irChangeList->ConfigElement[i].PhysDiskDevHandle);
+
+			switch (reason) {
+			case MPI2_EVENT_IR_CHANGE_RC_ADDED:
+			case MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED:
+			{
+				NDBG20(("mptsas %d volume added\n",
+				    mpt->m_instance));
+
+				topo_node = kmem_zalloc(
+				    sizeof (mptsas_topo_change_list_t),
+				    KM_SLEEP);
+
+				topo_node->mpt = mpt;
+				topo_node->event =
+				    MPTSAS_DR_EVENT_RECONFIG_TARGET;
+				topo_node->un.physport = 0xff;
+				topo_node->devhdl = volhandle;
+				topo_node->flags =
+				    MPTSAS_TOPO_FLAG_RAID_ASSOCIATED;
+				topo_node->object = NULL;
+				if (topo_head == NULL) {
+					topo_head = topo_tail = topo_node;
+				} else {
+					topo_tail->next = topo_node;
+					topo_tail = topo_node;
+				}
+				break;
+			}
+			case MPI2_EVENT_IR_CHANGE_RC_REMOVED:
+			case MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED:
+			{
+				NDBG20(("mptsas %d volume deleted\n",
+				    mpt->m_instance));
+				ptgt = mptsas_search_by_devhdl(tgttbl,
+				    volhandle);
+				if (ptgt == NULL)
+					break;
+
+				/*
+				 * Clear any flags related to volume
+				 */
+				(void) mptsas_delete_volume(mpt, volhandle);
+
+				/*
+				 * Update DR flag immediately avoid I/O failure
+				 */
+				mutex_enter(&mpt->m_tx_waitq_mutex);
+				ptgt->m_dr_flag = MPTSAS_DR_INTRANSITION;
+				mutex_exit(&mpt->m_tx_waitq_mutex);
+
+				topo_node = kmem_zalloc(
+				    sizeof (mptsas_topo_change_list_t),
+				    KM_SLEEP);
+				topo_node->mpt = mpt;
+				topo_node->un.phymask = ptgt->m_phymask;
+				topo_node->event =
+				    MPTSAS_DR_EVENT_OFFLINE_TARGET;
+				topo_node->devhdl = volhandle;
+				topo_node->flags =
+				    MPTSAS_TOPO_FLAG_RAID_ASSOCIATED;
+				topo_node->object = (void *)ptgt;
+				if (topo_head == NULL) {
+					topo_head = topo_tail = topo_node;
+				} else {
+					topo_tail->next = topo_node;
+					topo_tail = topo_node;
+				}
+				break;
+			}
+			case MPI2_EVENT_IR_CHANGE_RC_PD_CREATED:
+			case MPI2_EVENT_IR_CHANGE_RC_HIDE:
+			{
+				ptgt = mptsas_search_by_devhdl(tgttbl,
+				    diskhandle);
+				if (ptgt == NULL)
+					break;
+
+				/*
+				 * Update DR flag immediately avoid I/O failure
+				 */
+				mutex_enter(&mpt->m_tx_waitq_mutex);
+				ptgt->m_dr_flag = MPTSAS_DR_INTRANSITION;
+				mutex_exit(&mpt->m_tx_waitq_mutex);
+
+				topo_node = kmem_zalloc(
+				    sizeof (mptsas_topo_change_list_t),
+				    KM_SLEEP);
+				topo_node->mpt = mpt;
+				topo_node->un.phymask = ptgt->m_phymask;
+				topo_node->event =
+				    MPTSAS_DR_EVENT_OFFLINE_TARGET;
+				topo_node->devhdl = diskhandle;
+				topo_node->flags =
+				    MPTSAS_TOPO_FLAG_RAID_PHYSDRV_ASSOCIATED;
+				topo_node->object = (void *)ptgt;
+				if (topo_head == NULL) {
+					topo_head = topo_tail = topo_node;
+				} else {
+					topo_tail->next = topo_node;
+					topo_tail = topo_node;
+				}
+				break;
+			}
+			case MPI2_EVENT_IR_CHANGE_RC_UNHIDE:
+			case MPI2_EVENT_IR_CHANGE_RC_PD_DELETED:
+			{
+				/*
+				 * The physical drive is released by a IR
+				 * volume. But we cannot get the the physport
+				 * or phynum from the event data, so we only
+				 * can get the physport/phynum after SAS
+				 * Device Page0 request for the devhdl.
+				 */
+				topo_node = kmem_zalloc(
+				    sizeof (mptsas_topo_change_list_t),
+				    KM_SLEEP);
+				topo_node->mpt = mpt;
+				topo_node->un.phymask = 0;
+				topo_node->event =
+				    MPTSAS_DR_EVENT_RECONFIG_TARGET;
+				topo_node->devhdl = diskhandle;
+				topo_node->flags =
+				    MPTSAS_TOPO_FLAG_RAID_PHYSDRV_ASSOCIATED;
+				topo_node->object = NULL;
+				mpt->m_port_chng = 1;
+				if (topo_head == NULL) {
+					topo_head = topo_tail = topo_node;
+				} else {
+					topo_tail->next = topo_node;
+					topo_tail = topo_node;
+				}
+				break;
+			}
+			default:
+				break;
+			}
+		}
+
+		if (topo_head != NULL) {
+			/*
+			 * Launch DR taskq to handle topology change
+			 */
+			if ((ddi_taskq_dispatch(mpt->m_dr_taskq,
+			    mptsas_handle_dr, (void *)topo_head,
+			    DDI_NOSLEEP)) != DDI_SUCCESS) {
+				mptsas_log(mpt, CE_NOTE, "mptsas start taskq "
+				    "for handle SAS DR event failed. \n");
+			}
+		}
+		break;
+	}
+	default:
+		return (DDI_FAILURE);
+	}
+
+	return (DDI_SUCCESS);
+}
+
+/*
+ * handle events from ioc
+ */
+static void
+mptsas_handle_event(void *args)
+{
+	m_replyh_arg_t			*replyh_arg;
+	pMpi2EventNotificationReply_t	eventreply;
+	uint32_t			event, iocloginfo, rfm;
+	uint32_t			status, reply_index;
+	uint8_t				port;
+	mptsas_t			*mpt;
+	uint_t				iocstatus;
+
+	replyh_arg = (m_replyh_arg_t *)args;
+	rfm = replyh_arg->rfm;
+	mpt = replyh_arg->mpt;
+
+	mutex_enter(&mpt->m_mutex);
+
+	eventreply = (pMpi2EventNotificationReply_t)
+	    (mpt->m_reply_frame + (rfm - mpt->m_reply_frame_dma_addr));
+	event = ddi_get16(mpt->m_acc_reply_frame_hdl, &eventreply->Event);
+
+	if (iocstatus = ddi_get16(mpt->m_acc_reply_frame_hdl,
+	    &eventreply->IOCStatus)) {
+		if (iocstatus == MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
+			mptsas_log(mpt, CE_WARN,
+			    "!mptsas_handle_event: IOCStatus=0x%x, "
+			    "IOCLogInfo=0x%x", iocstatus,
+			    ddi_get32(mpt->m_acc_reply_frame_hdl,
+			    &eventreply->IOCLogInfo));
+		} else {
+			mptsas_log(mpt, CE_WARN,
+			    "mptsas_handle_event: IOCStatus=0x%x, "
+			    "IOCLogInfo=0x%x", iocstatus,
+			    ddi_get32(mpt->m_acc_reply_frame_hdl,
+			    &eventreply->IOCLogInfo));
+		}
+	}
+
+	/*
+	 * figure out what kind of event we got and handle accordingly
+	 */
+	switch (event) {
+	case MPI2_EVENT_LOG_ENTRY_ADDED:
+		break;
+	case MPI2_EVENT_LOG_DATA:
+		iocloginfo = ddi_get32(mpt->m_acc_reply_frame_hdl,
+		    &eventreply->IOCLogInfo);
+		NDBG20(("mptsas %d log info %x received.\n", mpt->m_instance,
+		    iocloginfo));
+		break;
+	case MPI2_EVENT_STATE_CHANGE:
+		NDBG20(("mptsas%d state change.", mpt->m_instance));
+		break;
+	case MPI2_EVENT_HARD_RESET_RECEIVED:
+		NDBG20(("mptsas%d event change.", mpt->m_instance));
+		break;
+	case MPI2_EVENT_SAS_DISCOVERY:
+	{
+		MPI2_EVENT_DATA_SAS_DISCOVERY	*sasdiscovery;
+		char				string[80];
+		uint8_t				rc;
+
+		sasdiscovery =
+		    (pMpi2EventDataSasDiscovery_t)eventreply->EventData;
+
+		rc = ddi_get8(mpt->m_acc_reply_frame_hdl,
+		    &sasdiscovery->ReasonCode);
+		port = ddi_get8(mpt->m_acc_reply_frame_hdl,
+		    &sasdiscovery->PhysicalPort);
+		status = ddi_get32(mpt->m_acc_reply_frame_hdl,
+		    &sasdiscovery->DiscoveryStatus);
+
+		string[0] = 0;
+		switch (rc) {
+		case MPI2_EVENT_SAS_DISC_RC_STARTED:
+			(void) sprintf(string, "STARTING");
+			break;
+		case MPI2_EVENT_SAS_DISC_RC_COMPLETED:
+			(void) sprintf(string, "COMPLETED");
+			break;
+		default:
+			(void) sprintf(string, "UNKNOWN");
+			break;
+		}
+
+		NDBG20(("SAS DISCOVERY is %s for port %d, status %x", string,
+		    port, status));
+
+		break;
+	}
+	case MPI2_EVENT_EVENT_CHANGE:
+		NDBG20(("mptsas%d event change.", mpt->m_instance));
+		break;
+	case MPI2_EVENT_TASK_SET_FULL:
+	{
+		pMpi2EventDataTaskSetFull_t	taskfull;
+
+		taskfull = (pMpi2EventDataTaskSetFull_t)eventreply->EventData;
+
+		NDBG20(("TASK_SET_FULL received for mptsas%d, depth %d\n",
+		    mpt->m_instance,  ddi_get16(mpt->m_acc_reply_frame_hdl,
+		    &taskfull->CurrentDepth)));
+		break;
+	}
+	case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST:
+	{
+		/*
+		 * SAS TOPOLOGY CHANGE LIST Event has already been handled
+		 * in mptsas_handle_event_sync() of interrupt context
+		 */
+		break;
+	}
+	case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE:
+	{
+		pMpi2EventDataSasEnclDevStatusChange_t	encstatus;
+		uint8_t					rc;
+		char					string[80];
+
+		encstatus = (pMpi2EventDataSasEnclDevStatusChange_t)
+		    eventreply->EventData;
+
+		rc = ddi_get8(mpt->m_acc_reply_frame_hdl,
+		    &encstatus->ReasonCode);
+		switch (rc) {
+		case MPI2_EVENT_SAS_ENCL_RC_ADDED:
+			(void) sprintf(string, "added");
+			break;
+		case MPI2_EVENT_SAS_ENCL_RC_NOT_RESPONDING:
+			(void) sprintf(string, ", not responding");
+			break;
+		default:
+		break;
+		}
+		NDBG20(("mptsas%d ENCLOSURE STATUS CHANGE for enclosure %x%s\n",
+		    mpt->m_instance, ddi_get16(mpt->m_acc_reply_frame_hdl,
+		    &encstatus->EnclosureHandle), string));
+		break;
+	}
+
+	/*
+	 * MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE is handled by
+	 * mptsas_handle_event_sync,in here just send ack message.
+	 */
+	case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE:
+	{
+		pMpi2EventDataSasDeviceStatusChange_t	statuschange;
+		uint8_t					rc;
+		uint16_t				devhdl;
+		uint64_t				wwn = 0;
+		uint32_t				wwn_lo, wwn_hi;
+
+		statuschange = (pMpi2EventDataSasDeviceStatusChange_t)
+		    eventreply->EventData;
+		rc = ddi_get8(mpt->m_acc_reply_frame_hdl,
+		    &statuschange->ReasonCode);
+		wwn_lo = ddi_get32(mpt->m_acc_reply_frame_hdl,
+		    (uint32_t *)(void *)&statuschange->SASAddress);
+		wwn_hi = ddi_get32(mpt->m_acc_reply_frame_hdl,
+		    (uint32_t *)(void *)&statuschange->SASAddress + 1);
+		wwn = ((uint64_t)wwn_hi << 32) | wwn_lo;
+		devhdl =  ddi_get16(mpt->m_acc_reply_frame_hdl,
+		    &statuschange->DevHandle);
+
+		NDBG13(("MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE wwn is %"PRIx64,
+		    wwn));
+
+		switch (rc) {
+		case MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
+			NDBG20(("SMART data received, ASC/ASCQ = %02x/%02x",
+			    ddi_get8(mpt->m_acc_reply_frame_hdl,
+			    &statuschange->ASC),
+			    ddi_get8(mpt->m_acc_reply_frame_hdl,
+			    &statuschange->ASCQ)));
+			break;
+
+		case MPI2_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
+			NDBG20(("Device not supported"));
+			break;
+
+		case MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
+			NDBG20(("IOC internally generated the Target Reset "
+			    "for devhdl:%x", devhdl));
+			break;
+
+		case MPI2_EVENT_SAS_DEV_STAT_RC_CMP_INTERNAL_DEV_RESET:
+			NDBG20(("IOC's internally generated Target Reset "
+			    "completed for devhdl:%x", devhdl));
+			break;
+
+		case MPI2_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
+			NDBG20(("IOC internally generated Abort Task"));
+			break;
+
+		case MPI2_EVENT_SAS_DEV_STAT_RC_CMP_TASK_ABORT_INTERNAL:
+			NDBG20(("IOC's internally generated Abort Task "
+			    "completed"));
+			break;
+
+		case MPI2_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
+			NDBG20(("IOC internally generated Abort Task Set"));
+			break;
+
+		case MPI2_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
+			NDBG20(("IOC internally generated Clear Task Set"));
+			break;
+
+		case MPI2_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
+			NDBG20(("IOC internally generated Query Task"));
+			break;
+
+		case MPI2_EVENT_SAS_DEV_STAT_RC_ASYNC_NOTIFICATION:
+			NDBG20(("Device sent an Asynchronous Notification"));
+			break;
+
+		default:
+			break;
+		}
+		break;
+	}
+	case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST:
+	{
+		/*
+		 * IR TOPOLOGY CHANGE LIST Event has already been handled
+		 * in mpt_handle_event_sync() of interrupt context
+		 */
+		break;
+	}
+	case MPI2_EVENT_IR_OPERATION_STATUS:
+	{
+		Mpi2EventDataIrOperationStatus_t	*irOpStatus;
+		char					reason_str[80];
+		uint8_t					rc, percent;
+		uint16_t				handle;
+
+		irOpStatus = (pMpi2EventDataIrOperationStatus_t)
+		    eventreply->EventData;
+		rc = ddi_get8(mpt->m_acc_reply_frame_hdl,
+		    &irOpStatus->RAIDOperation);
+		percent = ddi_get8(mpt->m_acc_reply_frame_hdl,
+		    &irOpStatus->PercentComplete);
+		handle = ddi_get16(mpt->m_acc_reply_frame_hdl,
+		    &irOpStatus->VolDevHandle);
+
+		switch (rc) {
+			case MPI2_EVENT_IR_RAIDOP_RESYNC:
+				(void) sprintf(reason_str, "resync");
+				break;
+			case MPI2_EVENT_IR_RAIDOP_ONLINE_CAP_EXPANSION:
+				(void) sprintf(reason_str, "online capacity "
+				    "expansion");
+				break;
+			case MPI2_EVENT_IR_RAIDOP_CONSISTENCY_CHECK:
+				(void) sprintf(reason_str, "consistency check");
+				break;
+			default:
+				(void) sprintf(reason_str, "unknown reason %x",
+				    rc);
+		}
+
+		NDBG20(("mptsas%d raid operational status: (%s)"
+		    "\thandle(0x%04x), percent complete(%d)\n",
+		    mpt->m_instance, reason_str, handle, percent));
+		break;
+	}
+	case MPI2_EVENT_IR_VOLUME:
+	{
+		Mpi2EventDataIrVolume_t		*irVolume;
+		uint16_t			devhandle;
+		uint32_t			state;
+		int				config, vol;
+		mptsas_slots_t			*slots = mpt->m_active;
+		uint8_t				found = FALSE;
+
+		irVolume = (pMpi2EventDataIrVolume_t)eventreply->EventData;
+		state = ddi_get32(mpt->m_acc_reply_frame_hdl,
+		    &irVolume->NewValue);
+		devhandle = ddi_get16(mpt->m_acc_reply_frame_hdl,
+		    &irVolume->VolDevHandle);
+
+		NDBG20(("EVENT_IR_VOLUME event is received"));
+
+		/*
+		 * Get latest RAID info and then find the DevHandle for this
+		 * event in the configuration.  If the DevHandle is not found
+		 * just exit the event.
+		 */
+		(void) mptsas_get_raid_info(mpt);
+		for (config = 0; config < slots->m_num_raid_configs;
+		    config++) {
+			for (vol = 0; vol < MPTSAS_MAX_RAIDVOLS; vol++) {
+				if (slots->m_raidconfig[config].m_raidvol[vol].
+				    m_raidhandle == devhandle) {
+					found = TRUE;
+					break;
+				}
+			}
+		}
+		if (!found) {
+			break;
+		}
+
+		switch (irVolume->ReasonCode) {
+		case MPI2_EVENT_IR_VOLUME_RC_SETTINGS_CHANGED:
+		{
+			uint32_t i;
+			slots->m_raidconfig[config].m_raidvol[vol].m_settings =
+			    state;
+
+			i = state & MPI2_RAIDVOL0_SETTING_MASK_WRITE_CACHING;
+			mptsas_log(mpt, CE_NOTE, " Volume %d settings changed"
+			    ", auto-config of hot-swap drives is %s"
+			    ", write caching is %s"
+			    ", hot-spare pool mask is %02x\n",
+			    vol, state &
+			    MPI2_RAIDVOL0_SETTING_AUTO_CONFIG_HSWAP_DISABLE
+			    ? "disabled" : "enabled",
+			    i == MPI2_RAIDVOL0_SETTING_UNCHANGED
+			    ? "controlled by member disks" :
+			    i == MPI2_RAIDVOL0_SETTING_DISABLE_WRITE_CACHING
+			    ? "disabled" :
+			    i == MPI2_RAIDVOL0_SETTING_ENABLE_WRITE_CACHING
+			    ? "enabled" :
+			    "incorrectly set",
+			    (state >> 16) & 0xff);
+				break;
+		}
+		case MPI2_EVENT_IR_VOLUME_RC_STATE_CHANGED:
+		{
+			slots->m_raidconfig[config].m_raidvol[vol].m_state =
+			    (uint8_t)state;
+
+			mptsas_log(mpt, CE_NOTE,
+			    "Volume %d is now %s\n", vol,
+			    state == MPI2_RAID_VOL_STATE_OPTIMAL
+			    ? "optimal" :
+			    state == MPI2_RAID_VOL_STATE_DEGRADED
+			    ? "degraded" :
+			    state == MPI2_RAID_VOL_STATE_ONLINE
+			    ? "online" :
+			    state == MPI2_RAID_VOL_STATE_INITIALIZING
+			    ? "initializing" :
+			    state == MPI2_RAID_VOL_STATE_FAILED
+			    ? "failed" :
+			    state == MPI2_RAID_VOL_STATE_MISSING
+			    ? "missing" :
+			    "state unknown");
+			break;
+		}
+		case MPI2_EVENT_IR_VOLUME_RC_STATUS_FLAGS_CHANGED:
+		{
+			slots->m_raidconfig[config].m_raidvol[vol].
+			    m_statusflags = state;
+
+			mptsas_log(mpt, CE_NOTE,
+			    " Volume %d is now %s%s%s%s%s%s%s%s%s\n",
+			    vol,
+			    state & MPI2_RAIDVOL0_STATUS_FLAG_ENABLED
+			    ? ", enabled" : ", disabled",
+			    state & MPI2_RAIDVOL0_STATUS_FLAG_QUIESCED
+			    ? ", quiesced" : "",
+			    state & MPI2_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE
+			    ? ", inactive" : ", active",
+			    state &
+			    MPI2_RAIDVOL0_STATUS_FLAG_BAD_BLOCK_TABLE_FULL
+			    ? ", bad block table is full" : "",
+			    state &
+			    MPI2_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS
+			    ? ", resync in progress" : "",
+			    state & MPI2_RAIDVOL0_STATUS_FLAG_BACKGROUND_INIT
+			    ? ", background initialization in progress" : "",
+			    state &
+			    MPI2_RAIDVOL0_STATUS_FLAG_CAPACITY_EXPANSION
+			    ? ", capacity expansion in progress" : "",
+			    state &
+			    MPI2_RAIDVOL0_STATUS_FLAG_CONSISTENCY_CHECK
+			    ? ", consistency check in progress" : "",
+			    state & MPI2_RAIDVOL0_STATUS_FLAG_DATA_SCRUB
+			    ? ", data scrub in progress" : "");
+			break;
+		}
+		default:
+			break;
+		}
+		break;
+	}
+	case MPI2_EVENT_IR_PHYSICAL_DISK:
+	{
+		Mpi2EventDataIrPhysicalDisk_t	*irPhysDisk;
+		uint16_t			devhandle, enchandle, slot;
+		uint32_t			status, state;
+		uint8_t				physdisknum, reason;
+
+		irPhysDisk = (Mpi2EventDataIrPhysicalDisk_t *)
+		    eventreply->EventData;
+		physdisknum = ddi_get8(mpt->m_acc_reply_frame_hdl,
+		    &irPhysDisk->PhysDiskNum);
+		devhandle = ddi_get16(mpt->m_acc_reply_frame_hdl,
+		    &irPhysDisk->PhysDiskDevHandle);
+		enchandle = ddi_get16(mpt->m_acc_reply_frame_hdl,
+		    &irPhysDisk->EnclosureHandle);
+		slot = ddi_get16(mpt->m_acc_reply_frame_hdl,
+		    &irPhysDisk->Slot);
+		state = ddi_get32(mpt->m_acc_reply_frame_hdl,
+		    &irPhysDisk->NewValue);
+		reason = ddi_get8(mpt->m_acc_reply_frame_hdl,
+		    &irPhysDisk->ReasonCode);
+
+		NDBG20(("EVENT_IR_PHYSICAL_DISK event is received"));
+
+		switch (reason) {
+		case MPI2_EVENT_IR_PHYSDISK_RC_SETTINGS_CHANGED:
+			mptsas_log(mpt, CE_NOTE,
+			    " PhysDiskNum %d with DevHandle 0x%x in slot %d "
+			    "for enclosure with handle 0x%x is now in hot "
+			    "spare pool %d",
+			    physdisknum, devhandle, slot, enchandle,
+			    (state >> 16) & 0xff);
+			break;
+
+		case MPI2_EVENT_IR_PHYSDISK_RC_STATUS_FLAGS_CHANGED:
+			status = state;
+			mptsas_log(mpt, CE_NOTE,
+			    " PhysDiskNum %d with DevHandle 0x%x in slot %d "
+			    "for enclosure with handle 0x%x is now "
+			    "%s%s%s%s%s\n", physdisknum, devhandle, slot,
+			    enchandle,
+			    status & MPI2_PHYSDISK0_STATUS_FLAG_INACTIVE_VOLUME
+			    ? ", inactive" : ", active",
+			    status & MPI2_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC
+			    ? ", out of sync" : "",
+			    status & MPI2_PHYSDISK0_STATUS_FLAG_QUIESCED
+			    ? ", quiesced" : "",
+			    status &
+			    MPI2_PHYSDISK0_STATUS_FLAG_WRITE_CACHE_ENABLED
+			    ? ", write cache enabled" : "",
+			    status & MPI2_PHYSDISK0_STATUS_FLAG_OCE_TARGET
+			    ? ", capacity expansion target" : "");
+			break;
+
+		case MPI2_EVENT_IR_PHYSDISK_RC_STATE_CHANGED:
+			mptsas_log(mpt, CE_NOTE,
+			    " PhysDiskNum %d with DevHandle 0x%x in slot %d "
+			    "for enclosure with handle 0x%x is now %s\n",
+			    physdisknum, devhandle, slot, enchandle,
+			    state == MPI2_RAID_PD_STATE_OPTIMAL
+			    ? "optimal" :
+			    state == MPI2_RAID_PD_STATE_REBUILDING
+			    ? "rebuilding" :
+			    state == MPI2_RAID_PD_STATE_DEGRADED
+			    ? "degraded" :
+			    state == MPI2_RAID_PD_STATE_HOT_SPARE
+			    ? "a hot spare" :
+			    state == MPI2_RAID_PD_STATE_ONLINE
+			    ? "online" :
+			    state == MPI2_RAID_PD_STATE_OFFLINE
+			    ? "offline" :
+			    state == MPI2_RAID_PD_STATE_NOT_COMPATIBLE
+			    ? "not compatible" :
+			    state == MPI2_RAID_PD_STATE_NOT_CONFIGURED
+			    ? "not configured" :
+			    "state unknown");
+			break;
+		}
+		break;
+	}
+	default:
+		mptsas_log(mpt, CE_NOTE, "mptsas%d: unknown event %x received",
+		    mpt->m_instance, event);
+		break;
+	}
+
+	/*
+	 * Return the reply frame to the free queue.
+	 */
+	reply_index = mpt->m_free_index;
+	ddi_put32(mpt->m_acc_free_queue_hdl,
+	    &((uint32_t *)(void *)mpt->m_free_queue)[reply_index], rfm);
+	(void) ddi_dma_sync(mpt->m_dma_free_queue_hdl, 0, 0,
+	    DDI_DMA_SYNC_FORDEV);
+	if (++reply_index == mpt->m_free_queue_depth) {
+		reply_index = 0;
+	}
+	mpt->m_free_index = reply_index;
+	ddi_put32(mpt->m_datap, &mpt->m_reg->ReplyFreeHostIndex, reply_index);
+	mutex_exit(&mpt->m_mutex);
+}
+
+/*
+ * invoked from timeout() to restart qfull cmds with throttle == 0
+ */
+static void
+mptsas_restart_cmd(void *arg)
+{
+	mptsas_t	*mpt = arg;
+	mptsas_target_t	*ptgt = NULL;
+
+	mutex_enter(&mpt->m_mutex);
+
+	mpt->m_restart_cmd_timeid = 0;
+
+	ptgt = (mptsas_target_t *)mptsas_hash_traverse(&mpt->m_active->m_tgttbl,
+	    MPTSAS_HASH_FIRST);
+	while (ptgt != NULL) {
+		if (ptgt->m_reset_delay == 0) {
+			if (ptgt->m_t_throttle == QFULL_THROTTLE) {
+				mptsas_set_throttle(mpt, ptgt,
+				    MAX_THROTTLE);
+			}
+		}
+
+		ptgt = (mptsas_target_t *)mptsas_hash_traverse(
+		    &mpt->m_active->m_tgttbl, MPTSAS_HASH_NEXT);
+	}
+	mptsas_restart_hba(mpt);
+	mutex_exit(&mpt->m_mutex);
+}
+
+void
+mptsas_remove_cmd(mptsas_t *mpt, mptsas_cmd_t *cmd)
+{
+	int		slot;
+	mptsas_slots_t	*slots = mpt->m_active;
+	int		t;
+	mptsas_target_t	*ptgt = cmd->cmd_tgt_addr;
+
+	ASSERT(cmd != NULL);
+	ASSERT(cmd->cmd_queued == FALSE);
+
+	/*
+	 * Task Management cmds are removed in their own routines.  Also,
+	 * we don't want to modify timeout based on TM cmds.
+	 */
+	if (cmd->cmd_flags & CFLAG_TM_CMD) {
+		return;
+	}
+
+	t = Tgt(cmd);
+	slot = cmd->cmd_slot;
+
+	/*
+	 * remove the cmd.
+	 */
+	if (cmd == slots->m_slot[slot]) {
+		NDBG31(("mptsas_remove_cmd: removing cmd=0x%p", (void *)cmd));
+		slots->m_slot[slot] = NULL;
+		mpt->m_ncmds--;
+
+		/*
+		 * only decrement per target ncmds if command
+		 * has a target associated with it.
+		 */
+		if ((cmd->cmd_flags & CFLAG_CMDIOC) == 0) {
+			ptgt->m_t_ncmds--;
+			/*
+			 * reset throttle if we just ran an untagged command
+			 * to a tagged target
+			 */
+			if ((ptgt->m_t_ncmds == 0) &&
+			    ((cmd->cmd_pkt_flags & FLAG_TAGMASK) == 0)) {
+				mptsas_set_throttle(mpt, ptgt, MAX_THROTTLE);
+			}
+		}
+
+	}
+
+	/*
+	 * This is all we need to do for ioc commands.
+	 */
+	if (cmd->cmd_flags & CFLAG_CMDIOC) {
+		mptsas_return_to_pool(mpt, cmd);
+		return;
+	}
+
+	/*
+	 * Figure out what to set tag Q timeout for...
+	 *
+	 * Optimize: If we have duplicate's of same timeout
+	 * we're using, then we'll use it again until we run
+	 * out of duplicates.  This should be the normal case
+	 * for block and raw I/O.
+	 * If no duplicates, we have to scan through tag que and
+	 * find the longest timeout value and use it.  This is
+	 * going to take a while...
+	 * Add 1 to m_n_slots to account for TM request.
+	 */
+	if (cmd->cmd_pkt->pkt_time == ptgt->m_timebase) {
+		if (--(ptgt->m_dups) == 0) {
+			if (ptgt->m_t_ncmds) {
+				mptsas_cmd_t *ssp;
+				uint_t n = 0;
+				ushort_t nslots = (slots->m_n_slots + 1);
+				ushort_t i;
+				/*
+				 * This crude check assumes we don't do
+				 * this too often which seems reasonable
+				 * for block and raw I/O.
+				 */
+				for (i = 0; i < nslots; i++) {
+					ssp = slots->m_slot[i];
+					if (ssp && (Tgt(ssp) == t) &&
+					    (ssp->cmd_pkt->pkt_time > n)) {
+						n = ssp->cmd_pkt->pkt_time;
+						ptgt->m_dups = 1;
+					} else if (ssp && (Tgt(ssp) == t) &&
+					    (ssp->cmd_pkt->pkt_time == n)) {
+						ptgt->m_dups++;
+					}
+				}
+				ptgt->m_timebase = n;
+			} else {
+				ptgt->m_dups = 0;
+				ptgt->m_timebase = 0;
+			}
+		}
+	}
+	ptgt->m_timeout = ptgt->m_timebase;
+
+	ASSERT(cmd != slots->m_slot[cmd->cmd_slot]);
+}
+
+/*
+ * accept all cmds on the tx_waitq if any and then
+ * start a fresh request from the top of the device queue.
+ *
+ * since there are always cmds queued on the tx_waitq, and rare cmds on
+ * the instance waitq, so this function should not be invoked in the ISR,
+ * the mptsas_restart_waitq() is invoked in the ISR instead. otherwise, the
+ * burden belongs to the IO dispatch CPUs is moved the interrupt CPU.
+ */
+static void
+mptsas_restart_hba(mptsas_t *mpt)
+{
+	ASSERT(mutex_owned(&mpt->m_mutex));
+
+	mutex_enter(&mpt->m_tx_waitq_mutex);
+	if (mpt->m_tx_waitq) {
+		mptsas_accept_tx_waitq(mpt);
+	}
+	mutex_exit(&mpt->m_tx_waitq_mutex);
+	mptsas_restart_waitq(mpt);
+}
+
+/*
+ * start a fresh request from the top of the device queue
+ */
+static void
+mptsas_restart_waitq(mptsas_t *mpt)
+{
+	mptsas_cmd_t	*cmd, *next_cmd;
+	mptsas_target_t *ptgt = NULL;
+
+	NDBG1(("mptsas_restart_waitq: mpt=0x%p", (void *)mpt));
+
+	ASSERT(mutex_owned(&mpt->m_mutex));
+
+	/*
+	 * If there is a reset delay, don't start any cmds.  Otherwise, start
+	 * as many cmds as possible.
+	 * Since SMID 0 is reserved and the TM slot is reserved, the actual max
+	 * commands is m_max_requests - 2.
+	 */
+	cmd = mpt->m_waitq;
+
+	while (cmd != NULL) {
+		next_cmd = cmd->cmd_linkp;
+		if (cmd->cmd_flags & CFLAG_PASSTHRU) {
+			if (mptsas_save_cmd(mpt, cmd) == TRUE) {
+				/*
+				 * passthru command get slot need
+				 * set CFLAG_PREPARED.
+				 */
+				cmd->cmd_flags |= CFLAG_PREPARED;
+				mptsas_waitq_delete(mpt, cmd);
+				mptsas_start_passthru(mpt, cmd);
+			}
+			cmd = next_cmd;
+			continue;
+		}
+		if (cmd->cmd_flags & CFLAG_CONFIG) {
+			if (mptsas_save_cmd(mpt, cmd) == TRUE) {
+				/*
+				 * Send the config page request and delete it
+				 * from the waitq.
+				 */
+				cmd->cmd_flags |= CFLAG_PREPARED;
+				mptsas_waitq_delete(mpt, cmd);
+				mptsas_start_config_page_access(mpt, cmd);
+			}
+			cmd = next_cmd;
+			continue;
+		}
+
+		ptgt = cmd->cmd_tgt_addr;
+		if (ptgt && (ptgt->m_t_throttle == DRAIN_THROTTLE) &&
+		    (ptgt->m_t_ncmds == 0)) {
+			mptsas_set_throttle(mpt, ptgt, MAX_THROTTLE);
+		}
+		if ((mpt->m_ncmds <= (mpt->m_max_requests - 2)) &&
+		    (ptgt && (ptgt->m_reset_delay == 0)) &&
+		    (ptgt && (ptgt->m_t_ncmds <
+		    ptgt->m_t_throttle))) {
+			if (mptsas_save_cmd(mpt, cmd) == TRUE) {
+				mptsas_waitq_delete(mpt, cmd);
+				(void) mptsas_start_cmd(mpt, cmd);
+			}
+		}
+		cmd = next_cmd;
+	}
+}
+/*
+ * Cmds are queued if tran_start() doesn't get the m_mutexlock(no wait).
+ * Accept all those queued cmds before new cmd is accept so that the
+ * cmds are sent in order.
+ */
+static void
+mptsas_accept_tx_waitq(mptsas_t *mpt)
+{
+	mptsas_cmd_t *cmd;
+
+	ASSERT(mutex_owned(&mpt->m_mutex));
+	ASSERT(mutex_owned(&mpt->m_tx_waitq_mutex));
+
+	/*
+	 * A Bus Reset could occur at any time and flush the tx_waitq,
+	 * so we cannot count on the tx_waitq to contain even one cmd.
+	 * And when the m_tx_waitq_mutex is released and run
+	 * mptsas_accept_pkt(), the tx_waitq may be flushed.
+	 */
+	cmd = mpt->m_tx_waitq;
+	for (;;) {
+		if ((cmd = mpt->m_tx_waitq) == NULL) {
+			mpt->m_tx_draining = 0;
+			break;
+		}
+		if ((mpt->m_tx_waitq = cmd->cmd_linkp) == NULL) {
+			mpt->m_tx_waitqtail = &mpt->m_tx_waitq;
+		}
+		cmd->cmd_linkp = NULL;
+		mutex_exit(&mpt->m_tx_waitq_mutex);
+		if (mptsas_accept_pkt(mpt, cmd) != TRAN_ACCEPT)
+			cmn_err(CE_WARN, "mpt: mptsas_accept_tx_waitq: failed "
+			    "to accept cmd on queue\n");
+		mutex_enter(&mpt->m_tx_waitq_mutex);
+	}
+}
+
+
+/*
+ * mpt tag type lookup
+ */
+static char mptsas_tag_lookup[] =
+	{0, MSG_HEAD_QTAG, MSG_ORDERED_QTAG, 0, MSG_SIMPLE_QTAG};
+
+static int
+mptsas_start_cmd(mptsas_t *mpt, mptsas_cmd_t *cmd)
+{
+	struct scsi_pkt		*pkt = CMD2PKT(cmd);
+	uint32_t		control = 0;
+	int			n;
+	caddr_t			mem;
+	pMpi2SCSIIORequest_t	io_request;
+	ddi_dma_handle_t	dma_hdl = mpt->m_dma_req_frame_hdl;
+	ddi_acc_handle_t	acc_hdl = mpt->m_acc_req_frame_hdl;
+	mptsas_target_t		*ptgt = cmd->cmd_tgt_addr;
+	uint16_t		SMID, io_flags = 0;
+	uint32_t		request_desc_low, request_desc_high;
+
+	NDBG1(("mptsas_start_cmd: cmd=0x%p", (void *)cmd));
+
+	/*
+	 * Set SMID and increment index.  Rollover to 1 instead of 0 if index
+	 * is at the max.  0 is an invalid SMID, so we call the first index 1.
+	 */
+	SMID = cmd->cmd_slot;
+
+	/*
+	 * It is possible for back to back device reset to
+	 * happen before the reset delay has expired.  That's
+	 * ok, just let the device reset go out on the bus.
+	 */
+	if ((cmd->cmd_pkt_flags & FLAG_NOINTR) == 0) {
+		ASSERT(ptgt->m_reset_delay == 0);
+	}
+
+	/*
+	 * if a non-tagged cmd is submitted to an active tagged target
+	 * then drain before submitting this cmd; SCSI-2 allows RQSENSE
+	 * to be untagged
+	 */
+	if (((cmd->cmd_pkt_flags & FLAG_TAGMASK) == 0) &&
+	    (ptgt->m_t_ncmds > 1) &&
+	    ((cmd->cmd_flags & CFLAG_TM_CMD) == 0) &&
+	    (*(cmd->cmd_pkt->pkt_cdbp) != SCMD_REQUEST_SENSE)) {
+		if ((cmd->cmd_pkt_flags & FLAG_NOINTR) == 0) {
+			NDBG23(("target=%d, untagged cmd, start draining\n",
+			    ptgt->m_devhdl));
+
+			if (ptgt->m_reset_delay == 0) {
+				mptsas_set_throttle(mpt, ptgt, DRAIN_THROTTLE);
+			}
+
+			mptsas_remove_cmd(mpt, cmd);
+			cmd->cmd_pkt_flags |= FLAG_HEAD;
+			mptsas_waitq_add(mpt, cmd);
+		}
+		return (DDI_FAILURE);
+	}
+
+	/*
+	 * Set correct tag bits.
+	 */
+	if (cmd->cmd_pkt_flags & FLAG_TAGMASK) {
+		switch (mptsas_tag_lookup[((cmd->cmd_pkt_flags &
+		    FLAG_TAGMASK) >> 12)]) {
+		case MSG_SIMPLE_QTAG:
+			control |= MPI2_SCSIIO_CONTROL_SIMPLEQ;
+			break;
+		case MSG_HEAD_QTAG:
+			control |= MPI2_SCSIIO_CONTROL_HEADOFQ;
+			break;
+		case MSG_ORDERED_QTAG:
+			control |= MPI2_SCSIIO_CONTROL_ORDEREDQ;
+			break;
+		default:
+			mptsas_log(mpt, CE_WARN, "mpt: Invalid tag type\n");
+			break;
+		}
+	} else {
+		if (*(cmd->cmd_pkt->pkt_cdbp) != SCMD_REQUEST_SENSE) {
+				ptgt->m_t_throttle = 1;
+		}
+		control |= MPI2_SCSIIO_CONTROL_SIMPLEQ;
+	}
+
+	mem = mpt->m_req_frame + (mpt->m_req_frame_size * SMID);
+	io_request = (pMpi2SCSIIORequest_t)mem;
+
+	bzero(io_request, sizeof (Mpi2SCSIIORequest_t));
+	ddi_put8(acc_hdl, &io_request->SGLOffset0, offsetof
+	    (MPI2_SCSI_IO_REQUEST, SGL) / 4);
+	mptsas_init_std_hdr(acc_hdl, io_request, ptgt->m_devhdl, Lun(cmd), 0,
+	    MPI2_FUNCTION_SCSI_IO_REQUEST);
+
+	(void) ddi_rep_put8(acc_hdl, (uint8_t *)pkt->pkt_cdbp,
+	    io_request->CDB.CDB32, cmd->cmd_cdblen, DDI_DEV_AUTOINCR);
+
+	io_flags = cmd->cmd_cdblen;
+	ddi_put16(acc_hdl, &io_request->IoFlags, io_flags);
+	/*
+	 * setup the Scatter/Gather DMA list for this request
+	 */
+	if (cmd->cmd_cookiec > 0) {
+		mptsas_sge_setup(mpt, cmd, &control, io_request, acc_hdl);
+	} else {
+		ddi_put32(acc_hdl, &io_request->SGL.MpiSimple.FlagsLength,
+		    ((uint32_t)MPI2_SGE_FLAGS_LAST_ELEMENT |
+		    MPI2_SGE_FLAGS_END_OF_BUFFER |
+		    MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
+		    MPI2_SGE_FLAGS_END_OF_LIST) << MPI2_SGE_FLAGS_SHIFT);
+	}
+
+	/*
+	 * save ARQ information
+	 */
+	ddi_put8(acc_hdl, &io_request->SenseBufferLength, cmd->cmd_rqslen);
+	if ((cmd->cmd_flags & (CFLAG_SCBEXTERN | CFLAG_EXTARQBUFVALID)) ==
+	    (CFLAG_SCBEXTERN | CFLAG_EXTARQBUFVALID)) {
+		ddi_put32(acc_hdl, &io_request->SenseBufferLowAddress,
+		    cmd->cmd_ext_arqcookie.dmac_address);
+	} else {
+		ddi_put32(acc_hdl, &io_request->SenseBufferLowAddress,
+		    cmd->cmd_arqcookie.dmac_address);
+	}
+
+	ddi_put32(acc_hdl, &io_request->Control, control);
+
+	NDBG31(("starting message=0x%p, with cmd=0x%p",
+	    (void *)(uintptr_t)mpt->m_req_frame_dma_addr, (void *)cmd));
+
+	(void) ddi_dma_sync(dma_hdl, 0, 0, DDI_DMA_SYNC_FORDEV);
+
+	/*
+	 * Build request descriptor and write it to the request desc post reg.
+	 */
+	request_desc_low = (SMID << 16) + MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO;
+	request_desc_high = ptgt->m_devhdl << 16;
+	MPTSAS_START_CMD(mpt, request_desc_low, request_desc_high);
+
+	/*
+	 * Start timeout.
+	 */
+#ifdef MPTSAS_TEST
+	/*
+	 * Temporarily set timebase = 0;  needed for
+	 * timeout torture test.
+	 */
+	if (mptsas_test_timeouts) {
+		ptgt->m_timebase = 0;
+	}
+#endif
+	n = pkt->pkt_time - ptgt->m_timebase;
+
+	if (n == 0) {
+		(ptgt->m_dups)++;
+		ptgt->m_timeout = ptgt->m_timebase;
+	} else if (n > 0) {
+		ptgt->m_timeout =
+		    ptgt->m_timebase = pkt->pkt_time;
+		ptgt->m_dups = 1;
+	} else if (n < 0) {
+		ptgt->m_timeout = ptgt->m_timebase;
+	}
+#ifdef MPTSAS_TEST
+	/*
+	 * Set back to a number higher than
+	 * mptsas_scsi_watchdog_tick
+	 * so timeouts will happen in mptsas_watchsubr
+	 */
+	if (mptsas_test_timeouts) {
+		ptgt->m_timebase = 60;
+	}
+#endif
+
+	if ((mptsas_check_dma_handle(dma_hdl) != DDI_SUCCESS) ||
+	    (mptsas_check_acc_handle(acc_hdl) != DDI_SUCCESS)) {
+		ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
+		return (DDI_FAILURE);
+	}
+	return (DDI_SUCCESS);
+}
+
+/*
+ * Select a helper thread to handle current doneq
+ */
+static void
+mptsas_deliver_doneq_thread(mptsas_t *mpt)
+{
+	uint64_t			t, i;
+	uint32_t			min = 0xffffffff;
+	mptsas_doneq_thread_list_t	*item;
+
+	for (i = 0; i < mpt->m_doneq_thread_n; i++) {
+		item = &mpt->m_doneq_thread_id[i];
+		/*
+		 * If the completed command on help thread[i] less than
+		 * doneq_thread_threshold, then pick the thread[i]. Otherwise
+		 * pick a thread which has least completed command.
+		 */
+
+		mutex_enter(&item->mutex);
+		if (item->len < mpt->m_doneq_thread_threshold) {
+			t = i;
+			mutex_exit(&item->mutex);
+			break;
+		}
+		if (item->len < min) {
+			min = item->len;
+			t = i;
+		}
+		mutex_exit(&item->mutex);
+	}
+	mutex_enter(&mpt->m_doneq_thread_id[t].mutex);
+	mptsas_doneq_mv(mpt, t);
+	cv_signal(&mpt->m_doneq_thread_id[t].cv);
+	mutex_exit(&mpt->m_doneq_thread_id[t].mutex);
+}
+
+/*
+ * move the current global doneq to the doneq of thead[t]
+ */
+static void
+mptsas_doneq_mv(mptsas_t *mpt, uint64_t t)
+{
+	mptsas_cmd_t			*cmd;
+	mptsas_doneq_thread_list_t	*item = &mpt->m_doneq_thread_id[t];
+
+	ASSERT(mutex_owned(&item->mutex));
+	while ((cmd = mpt->m_doneq) != NULL) {
+		if ((mpt->m_doneq = cmd->cmd_linkp) == NULL) {
+			mpt->m_donetail = &mpt->m_doneq;
+		}
+		cmd->cmd_linkp = NULL;
+		*item->donetail = cmd;
+		item->donetail = &cmd->cmd_linkp;
+		mpt->m_doneq_len--;
+		item->len++;
+	}
+}
+
+void
+mptsas_fma_check(mptsas_t *mpt, mptsas_cmd_t *cmd)
+{
+	struct scsi_pkt	*pkt = CMD2PKT(cmd);
+
+	/* Check all acc and dma handles */
+	if ((mptsas_check_acc_handle(mpt->m_datap) !=
+	    DDI_SUCCESS) ||
+	    (mptsas_check_acc_handle(mpt->m_acc_req_frame_hdl) !=
+	    DDI_SUCCESS) ||
+	    (mptsas_check_acc_handle(mpt->m_acc_reply_frame_hdl) !=
+	    DDI_SUCCESS) ||
+	    (mptsas_check_acc_handle(mpt->m_acc_free_queue_hdl) !=
+	    DDI_SUCCESS) ||
+	    (mptsas_check_acc_handle(mpt->m_acc_post_queue_hdl) !=
+	    DDI_SUCCESS) ||
+	    (mptsas_check_acc_handle(mpt->m_hshk_acc_hdl) !=
+	    DDI_SUCCESS) ||
+	    (mptsas_check_acc_handle(mpt->m_config_handle) !=
+	    DDI_SUCCESS)) {
+		ddi_fm_service_impact(mpt->m_dip,
+		    DDI_SERVICE_UNAFFECTED);
+		ddi_fm_acc_err_clear(mpt->m_config_handle,
+		    DDI_FME_VER0);
+		pkt->pkt_reason = CMD_TRAN_ERR;
+		pkt->pkt_statistics = 0;
+	}
+	if ((mptsas_check_dma_handle(mpt->m_dma_req_frame_hdl) !=
+	    DDI_SUCCESS) ||
+	    (mptsas_check_dma_handle(mpt->m_dma_reply_frame_hdl) !=
+	    DDI_SUCCESS) ||
+	    (mptsas_check_dma_handle(mpt->m_dma_free_queue_hdl) !=
+	    DDI_SUCCESS) ||
+	    (mptsas_check_dma_handle(mpt->m_dma_post_queue_hdl) !=
+	    DDI_SUCCESS) ||
+	    (mptsas_check_dma_handle(mpt->m_hshk_dma_hdl) !=
+	    DDI_SUCCESS)) {
+		ddi_fm_service_impact(mpt->m_dip,
+		    DDI_SERVICE_UNAFFECTED);
+		pkt->pkt_reason = CMD_TRAN_ERR;
+		pkt->pkt_statistics = 0;
+	}
+	if (cmd->cmd_dmahandle &&
+	    (mptsas_check_dma_handle(cmd->cmd_dmahandle) != DDI_SUCCESS)) {
+		ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
+		pkt->pkt_reason = CMD_TRAN_ERR;
+		pkt->pkt_statistics = 0;
+	}
+	if ((cmd->cmd_extra_frames &&
+	    ((mptsas_check_dma_handle(cmd->cmd_extra_frames->m_dma_hdl) !=
+	    DDI_SUCCESS) ||
+	    (mptsas_check_acc_handle(cmd->cmd_extra_frames->m_acc_hdl) !=
+	    DDI_SUCCESS)))) {
+		ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
+		pkt->pkt_reason = CMD_TRAN_ERR;
+		pkt->pkt_statistics = 0;
+	}
+	if (cmd->cmd_arqhandle &&
+	    (mptsas_check_dma_handle(cmd->cmd_arqhandle) != DDI_SUCCESS)) {
+		ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
+		pkt->pkt_reason = CMD_TRAN_ERR;
+		pkt->pkt_statistics = 0;
+	}
+	if (cmd->cmd_ext_arqhandle &&
+	    (mptsas_check_dma_handle(cmd->cmd_ext_arqhandle) != DDI_SUCCESS)) {
+		ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
+		pkt->pkt_reason = CMD_TRAN_ERR;
+		pkt->pkt_statistics = 0;
+	}
+}
+
+/*
+ * These routines manipulate the queue of commands that
+ * are waiting for their completion routines to be called.
+ * The queue is usually in FIFO order but on an MP system
+ * it's possible for the completion routines to get out
+ * of order. If that's a problem you need to add a global
+ * mutex around the code that calls the completion routine
+ * in the interrupt handler.
+ */
+static void
+mptsas_doneq_add(mptsas_t *mpt, mptsas_cmd_t *cmd)
+{
+	struct scsi_pkt	*pkt = CMD2PKT(cmd);
+
+	NDBG31(("mptsas_doneq_add: cmd=0x%p", (void *)cmd));
+
+	ASSERT((cmd->cmd_flags & CFLAG_COMPLETED) == 0);
+	cmd->cmd_linkp = NULL;
+	cmd->cmd_flags |= CFLAG_FINISHED;
+	cmd->cmd_flags &= ~CFLAG_IN_TRANSPORT;
+
+	mptsas_fma_check(mpt, cmd);
+
+	/*
+	 * only add scsi pkts that have completion routines to
+	 * the doneq.  no intr cmds do not have callbacks.
+	 * run the callback on an ARQ pkt immediately.  This
+	 * frees the ARQ for other check conditions.
+	 */
+	if (pkt->pkt_comp && !(cmd->cmd_flags & CFLAG_CMDARQ)) {
+		*mpt->m_donetail = cmd;
+		mpt->m_donetail = &cmd->cmd_linkp;
+		mpt->m_doneq_len++;
+	} else if (pkt->pkt_comp && (cmd->cmd_flags & CFLAG_CMDARQ)) {
+		cmd->cmd_flags |= CFLAG_COMPLETED;
+		mutex_exit(&mpt->m_mutex);
+		mptsas_pkt_comp(pkt, cmd);
+		mutex_enter(&mpt->m_mutex);
+	}
+}
+
+static mptsas_cmd_t *
+mptsas_doneq_thread_rm(mptsas_t *mpt, uint64_t t)
+{
+	mptsas_cmd_t			*cmd;
+	mptsas_doneq_thread_list_t	*item = &mpt->m_doneq_thread_id[t];
+
+	/* pop one off the done queue */
+	if ((cmd = item->doneq) != NULL) {
+		/* if the queue is now empty fix the tail pointer */
+		NDBG31(("mptsas_doneq_thread_rm: cmd=0x%p", (void *)cmd));
+		if ((item->doneq = cmd->cmd_linkp) == NULL) {
+			item->donetail = &item->doneq;
+		}
+		cmd->cmd_linkp = NULL;
+		item->len--;
+	}
+	return (cmd);
+}
+
+static void
+mptsas_doneq_empty(mptsas_t *mpt)
+{
+	if (mpt->m_doneq && !mpt->m_in_callback) {
+		mptsas_cmd_t	*cmd, *next;
+		struct scsi_pkt *pkt;
+
+		mpt->m_in_callback = 1;
+		cmd = mpt->m_doneq;
+		mpt->m_doneq = NULL;
+		mpt->m_donetail = &mpt->m_doneq;
+		mpt->m_doneq_len = 0;
+
+		mutex_exit(&mpt->m_mutex);
+		/*
+		 * run the completion routines of all the
+		 * completed commands
+		 */
+		while (cmd != NULL) {
+			next = cmd->cmd_linkp;
+			cmd->cmd_linkp = NULL;
+			/* run this command's completion routine */
+			cmd->cmd_flags |= CFLAG_COMPLETED;
+			pkt = CMD2PKT(cmd);
+			mptsas_pkt_comp(pkt, cmd);
+			cmd = next;
+		}
+		mutex_enter(&mpt->m_mutex);
+		mpt->m_in_callback = 0;
+	}
+}
+
+/*
+ * These routines manipulate the target's queue of pending requests
+ */
+void
+mptsas_waitq_add(mptsas_t *mpt, mptsas_cmd_t *cmd)
+{
+	NDBG7(("mptsas_waitq_add: cmd=0x%p", (void *)cmd));
+	mptsas_target_t *ptgt = cmd->cmd_tgt_addr;
+	cmd->cmd_queued = TRUE;
+	if (ptgt)
+		ptgt->m_t_nwait++;
+	if (cmd->cmd_pkt_flags & FLAG_HEAD) {
+		if ((cmd->cmd_linkp = mpt->m_waitq) == NULL) {
+			mpt->m_waitqtail = &cmd->cmd_linkp;
+		}
+		mpt->m_waitq = cmd;
+	} else {
+		cmd->cmd_linkp = NULL;
+		*(mpt->m_waitqtail) = cmd;
+		mpt->m_waitqtail = &cmd->cmd_linkp;
+	}
+}
+
+static mptsas_cmd_t *
+mptsas_waitq_rm(mptsas_t *mpt)
+{
+	mptsas_cmd_t	*cmd;
+	mptsas_target_t *ptgt;
+	NDBG7(("mptsas_waitq_rm"));
+
+	MPTSAS_WAITQ_RM(mpt, cmd);
+
+	NDBG7(("mptsas_waitq_rm: cmd=0x%p", (void *)cmd));
+	if (cmd) {
+		ptgt = cmd->cmd_tgt_addr;
+		if (ptgt) {
+			ptgt->m_t_nwait--;
+			ASSERT(ptgt->m_t_nwait >= 0);
+		}
+	}
+	return (cmd);
+}
+
+/*
+ * remove specified cmd from the middle of the wait queue.
+ */
+static void
+mptsas_waitq_delete(mptsas_t *mpt, mptsas_cmd_t *cmd)
+{
+	mptsas_cmd_t	*prevp = mpt->m_waitq;
+	mptsas_target_t *ptgt = cmd->cmd_tgt_addr;
+
+	NDBG7(("mptsas_waitq_delete: mpt=0x%p cmd=0x%p",
+	    (void *)mpt, (void *)cmd));
+	if (ptgt) {
+		ptgt->m_t_nwait--;
+		ASSERT(ptgt->m_t_nwait >= 0);
+	}
+
+	if (prevp == cmd) {
+		if ((mpt->m_waitq = cmd->cmd_linkp) == NULL)
+			mpt->m_waitqtail = &mpt->m_waitq;
+
+		cmd->cmd_linkp = NULL;
+		cmd->cmd_queued = FALSE;
+		NDBG7(("mptsas_waitq_delete: mpt=0x%p cmd=0x%p",
+		    (void *)mpt, (void *)cmd));
+		return;
+	}
+
+	while (prevp != NULL) {
+		if (prevp->cmd_linkp == cmd) {
+			if ((prevp->cmd_linkp = cmd->cmd_linkp) == NULL)
+				mpt->m_waitqtail = &prevp->cmd_linkp;
+
+			cmd->cmd_linkp = NULL;
+			cmd->cmd_queued = FALSE;
+			NDBG7(("mptsas_waitq_delete: mpt=0x%p cmd=0x%p",
+			    (void *)mpt, (void *)cmd));
+			return;
+		}
+		prevp = prevp->cmd_linkp;
+	}
+	cmn_err(CE_PANIC, "mpt: mptsas_waitq_delete: queue botch");
+}
+
+static mptsas_cmd_t *
+mptsas_tx_waitq_rm(mptsas_t *mpt)
+{
+	mptsas_cmd_t *cmd;
+	NDBG7(("mptsas_tx_waitq_rm"));
+
+	MPTSAS_TX_WAITQ_RM(mpt, cmd);
+
+	NDBG7(("mptsas_tx_waitq_rm: cmd=0x%p", (void *)cmd));
+
+	return (cmd);
+}
+
+/*
+ * remove specified cmd from the middle of the tx_waitq.
+ */
+static void
+mptsas_tx_waitq_delete(mptsas_t *mpt, mptsas_cmd_t *cmd)
+{
+	mptsas_cmd_t *prevp = mpt->m_tx_waitq;
+
+	NDBG7(("mptsas_tx_waitq_delete: mpt=0x%p cmd=0x%p",
+	    (void *)mpt, (void *)cmd));
+
+	if (prevp == cmd) {
+		if ((mpt->m_tx_waitq = cmd->cmd_linkp) == NULL)
+			mpt->m_tx_waitqtail = &mpt->m_tx_waitq;
+
+		cmd->cmd_linkp = NULL;
+		cmd->cmd_queued = FALSE;
+		NDBG7(("mptsas_tx_waitq_delete: mpt=0x%p cmd=0x%p",
+		    (void *)mpt, (void *)cmd));
+		return;
+	}
+
+	while (prevp != NULL) {
+		if (prevp->cmd_linkp == cmd) {
+			if ((prevp->cmd_linkp = cmd->cmd_linkp) == NULL)
+				mpt->m_tx_waitqtail = &prevp->cmd_linkp;
+
+			cmd->cmd_linkp = NULL;
+			cmd->cmd_queued = FALSE;
+			NDBG7(("mptsas_tx_waitq_delete: mpt=0x%p cmd=0x%p",
+			    (void *)mpt, (void *)cmd));
+			return;
+		}
+		prevp = prevp->cmd_linkp;
+	}
+	cmn_err(CE_PANIC, "mpt: mptsas_tx_waitq_delete: queue botch");
+}
+
+/*
+ * device and bus reset handling
+ *
+ * Notes:
+ *	- RESET_ALL:	reset the controller
+ *	- RESET_TARGET:	reset the target specified in scsi_address
+ */
+static int
+mptsas_scsi_reset(struct scsi_address *ap, int level)
+{
+	mptsas_t		*mpt = ADDR2MPT(ap);
+	int			rval;
+	mptsas_tgt_private_t	*tgt_private;
+	mptsas_target_t		*ptgt = NULL;
+
+	tgt_private = (mptsas_tgt_private_t *)ap->a_hba_tran->tran_tgt_private;
+	ptgt = tgt_private->t_private;
+	if (ptgt == NULL) {
+		return (FALSE);
+	}
+	NDBG22(("mptsas_scsi_reset: target=%d level=%d", ptgt->m_devhdl,
+	    level));
+
+	mutex_enter(&mpt->m_mutex);
+	/*
+	 * if we are not in panic set up a reset delay for this target
+	 */
+	if (!ddi_in_panic()) {
+		mptsas_setup_bus_reset_delay(mpt);
+	} else {
+		drv_usecwait(mpt->m_scsi_reset_delay * 1000);
+	}
+	rval = mptsas_do_scsi_reset(mpt, ptgt->m_devhdl);
+	mutex_exit(&mpt->m_mutex);
+
+	/*
+	 * The transport layer expect to only see TRUE and
+	 * FALSE. Therefore, we will adjust the return value
+	 * if mptsas_do_scsi_reset returns FAILED.
+	 */
+	if (rval == FAILED)
+		rval = FALSE;
+	return (rval);
+}
+
+static int
+mptsas_do_scsi_reset(mptsas_t *mpt, uint16_t devhdl)
+{
+	int		rval = FALSE;
+	uint8_t		config, disk;
+	mptsas_slots_t	*slots = mpt->m_active;
+
+	ASSERT(mutex_owned(&mpt->m_mutex));
+
+	if (mptsas_debug_resets) {
+		mptsas_log(mpt, CE_WARN, "mptsas_do_scsi_reset: target=%d",
+		    devhdl);
+	}
+
+	/*
+	 * Issue a Target Reset message to the target specified but not to a
+	 * disk making up a raid volume.  Just look through the RAID config
+	 * Phys Disk list of DevHandles.  If the target's DevHandle is in this
+	 * list, then don't reset this target.
+	 */
+	for (config = 0; config < slots->m_num_raid_configs; config++) {
+		for (disk = 0; disk < MPTSAS_MAX_DISKS_IN_CONFIG; disk++) {
+			if (devhdl == slots->m_raidconfig[config].
+			    m_physdisk_devhdl[disk]) {
+				return (TRUE);
+			}
+		}
+	}
+
+	rval = mptsas_ioc_task_management(mpt,
+	    MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, devhdl, 0);
+
+	mptsas_doneq_empty(mpt);
+	return (rval);
+}
+
+static int
+mptsas_scsi_reset_notify(struct scsi_address *ap, int flag,
+	void (*callback)(caddr_t), caddr_t arg)
+{
+	mptsas_t	*mpt = ADDR2MPT(ap);
+
+	NDBG22(("mptsas_scsi_reset_notify: tgt=%d", ap->a_target));
+
+	return (scsi_hba_reset_notify_setup(ap, flag, callback, arg,
+	    &mpt->m_mutex, &mpt->m_reset_notify_listf));
+}
+
+static int
+mptsas_get_name(struct scsi_device *sd, char *name, int len)
+{
+	dev_info_t	*lun_dip = NULL;
+
+	ASSERT(sd != NULL);
+	ASSERT(name != NULL);
+	lun_dip = sd->sd_dev;
+	ASSERT(lun_dip != NULL);
+
+	if (mptsas_name_child(lun_dip, name, len) == DDI_SUCCESS) {
+		return (1);
+	} else {
+		return (0);
+	}
+}
+
+static int
+mptsas_get_bus_addr(struct scsi_device *sd, char *name, int len)
+{
+	return (mptsas_get_name(sd, name, len));
+}
+
+void
+mptsas_set_throttle(mptsas_t *mpt, mptsas_target_t *ptgt, int what)
+{
+
+	NDBG25(("mptsas_set_throttle: throttle=%x", what));
+
+	/*
+	 * if the bus is draining/quiesced, no changes to the throttles
+	 * are allowed. Not allowing change of throttles during draining
+	 * limits error recovery but will reduce draining time
+	 *
+	 * all throttles should have been set to HOLD_THROTTLE
+	 */
+	if (mpt->m_softstate & (MPTSAS_SS_QUIESCED | MPTSAS_SS_DRAINING)) {
+		return;
+	}
+
+	if (what == HOLD_THROTTLE) {
+		ptgt->m_t_throttle = HOLD_THROTTLE;
+	} else if (ptgt->m_reset_delay == 0) {
+		ptgt->m_t_throttle = what;
+	}
+}
+
+/*
+ * Clean up from a device reset.
+ * For the case of target reset, this function clears the waitq of all
+ * commands for a particular target.   For the case of abort task set, this
+ * function clears the waitq of all commonds for a particular target/lun.
+ */
+static void
+mptsas_flush_target(mptsas_t *mpt, ushort_t target, int lun, uint8_t tasktype)
+{
+	mptsas_slots_t	*slots = mpt->m_active;
+	mptsas_cmd_t	*cmd, *next_cmd;
+	int		slot;
+	uchar_t		reason;
+	uint_t		stat;
+
+	NDBG25(("mptsas_flush_target: target=%d lun=%d", target, lun));
+
+	/*
+	 * Make sure the I/O Controller has flushed all cmds
+	 * that are associated with this target for a target reset
+	 * and target/lun for abort task set.
+	 * Account for TM requests, which use the last SMID.
+	 */
+	for (slot = 0; slot <= mpt->m_active->m_n_slots; slot++) {
+		if ((cmd = slots->m_slot[slot]) == NULL)
+			continue;
+		reason = CMD_RESET;
+		stat = STAT_DEV_RESET;
+		switch (tasktype) {
+		case MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET:
+			if (Tgt(cmd) == target) {
+				mptsas_log(mpt, CE_NOTE, "mptsas_flush_target "
+				    "discovered non-NULL cmd in slot %d, "
+				    "tasktype 0x%x", slot, tasktype);
+				mptsas_dump_cmd(mpt, cmd);
+				mptsas_remove_cmd(mpt, cmd);
+				mptsas_set_pkt_reason(mpt, cmd, reason, stat);
+				mptsas_doneq_add(mpt, cmd);
+			}
+			break;
+		case MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET:
+			reason = CMD_ABORTED;
+			stat = STAT_ABORTED;
+			/*FALLTHROUGH*/
+		case MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET:
+			if ((Tgt(cmd) == target) && (Lun(cmd) == lun)) {
+
+				mptsas_log(mpt, CE_NOTE, "mptsas_flush_target "
+				    "discovered non-NULL cmd in slot %d, "
+				    "tasktype 0x%x", slot, tasktype);
+				mptsas_dump_cmd(mpt, cmd);
+				mptsas_remove_cmd(mpt, cmd);
+				mptsas_set_pkt_reason(mpt, cmd, reason,
+				    stat);
+				mptsas_doneq_add(mpt, cmd);
+			}
+			break;
+		default:
+			break;
+		}
+	}
+
+	/*
+	 * Flush the waitq and tx_waitq of this target's cmds
+	 */
+	cmd = mpt->m_waitq;
+
+	reason = CMD_RESET;
+	stat = STAT_DEV_RESET;
+
+	switch (tasktype) {
+	case MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET:
+		while (cmd != NULL) {
+			next_cmd = cmd->cmd_linkp;
+			if (Tgt(cmd) == target) {
+				mptsas_waitq_delete(mpt, cmd);
+				mptsas_set_pkt_reason(mpt, cmd,
+				    reason, stat);
+				mptsas_doneq_add(mpt, cmd);
+			}
+			cmd = next_cmd;
+		}
+		mutex_enter(&mpt->m_tx_waitq_mutex);
+		cmd = mpt->m_tx_waitq;
+		while (cmd != NULL) {
+			next_cmd = cmd->cmd_linkp;
+			if (Tgt(cmd) == target) {
+				mptsas_tx_waitq_delete(mpt, cmd);
+				mutex_exit(&mpt->m_tx_waitq_mutex);
+				mptsas_set_pkt_reason(mpt, cmd,
+				    reason, stat);
+				mptsas_doneq_add(mpt, cmd);
+				mutex_enter(&mpt->m_tx_waitq_mutex);
+			}
+			cmd = next_cmd;
+		}
+		mutex_exit(&mpt->m_tx_waitq_mutex);
+		break;
+	case MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET:
+		reason = CMD_ABORTED;
+		stat =  STAT_ABORTED;
+		/*FALLTHROUGH*/
+	case MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET:
+		while (cmd != NULL) {
+			next_cmd = cmd->cmd_linkp;
+			if ((Tgt(cmd) == target) && (Lun(cmd) == lun)) {
+				mptsas_waitq_delete(mpt, cmd);
+				mptsas_set_pkt_reason(mpt, cmd,
+				    reason, stat);
+				mptsas_doneq_add(mpt, cmd);
+			}
+			cmd = next_cmd;
+		}
+		mutex_enter(&mpt->m_tx_waitq_mutex);
+		cmd = mpt->m_tx_waitq;
+		while (cmd != NULL) {
+			next_cmd = cmd->cmd_linkp;
+			if ((Tgt(cmd) == target) && (Lun(cmd) == lun)) {
+				mptsas_tx_waitq_delete(mpt, cmd);
+				mutex_exit(&mpt->m_tx_waitq_mutex);
+				mptsas_set_pkt_reason(mpt, cmd,
+				    reason, stat);
+				mptsas_doneq_add(mpt, cmd);
+				mutex_enter(&mpt->m_tx_waitq_mutex);
+			}
+			cmd = next_cmd;
+		}
+		mutex_exit(&mpt->m_tx_waitq_mutex);
+		break;
+	default:
+		mptsas_log(mpt, CE_WARN, "Unknown task management type %d.",
+		    tasktype);
+		break;
+	}
+}
+
+/*
+ * Clean up hba state, abort all outstanding command and commands in waitq
+ * reset timeout of all targets.
+ */
+static void
+mptsas_flush_hba(mptsas_t *mpt)
+{
+	mptsas_slots_t	*slots = mpt->m_active;
+	mptsas_cmd_t	*cmd;
+	int		slot;
+
+	NDBG25(("mptsas_flush_hba"));
+
+	/*
+	 * The I/O Controller should have already sent back
+	 * all commands via the scsi I/O reply frame.  Make
+	 * sure all commands have been flushed.
+	 * Account for TM request, which use the last SMID.
+	 */
+	for (slot = 0; slot <= mpt->m_active->m_n_slots; slot++) {
+		if ((cmd = slots->m_slot[slot]) == NULL)
+			continue;
+
+		if (cmd->cmd_flags & CFLAG_CMDIOC)
+			continue;
+
+		mptsas_log(mpt, CE_NOTE, "mptsas_flush_hba discovered non-NULL "
+		    "cmd in slot %d", slot);
+		mptsas_dump_cmd(mpt, cmd);
+
+		mptsas_remove_cmd(mpt, cmd);
+		mptsas_set_pkt_reason(mpt, cmd, CMD_RESET, STAT_BUS_RESET);
+		mptsas_doneq_add(mpt, cmd);
+	}
+
+	/*
+	 * Flush the waitq.
+	 */
+	while ((cmd = mptsas_waitq_rm(mpt)) != NULL) {
+		mptsas_set_pkt_reason(mpt, cmd, CMD_RESET, STAT_BUS_RESET);
+		if ((cmd->cmd_flags & CFLAG_PASSTHRU) ||
+		    (cmd->cmd_flags & CFLAG_CONFIG)) {
+			cmd->cmd_flags |= CFLAG_FINISHED;
+			cv_broadcast(&mpt->m_passthru_cv);
+			cv_broadcast(&mpt->m_config_cv);
+		} else {
+			mptsas_doneq_add(mpt, cmd);
+		}
+	}
+
+	/*
+	 * Flush the tx_waitq
+	 */
+	mutex_enter(&mpt->m_tx_waitq_mutex);
+	while ((cmd = mptsas_tx_waitq_rm(mpt)) != NULL) {
+		mutex_exit(&mpt->m_tx_waitq_mutex);
+		mptsas_set_pkt_reason(mpt, cmd, CMD_RESET, STAT_BUS_RESET);
+		mptsas_doneq_add(mpt, cmd);
+		mutex_enter(&mpt->m_tx_waitq_mutex);
+	}
+	mutex_exit(&mpt->m_tx_waitq_mutex);
+}
+
+/*
+ * set pkt_reason and OR in pkt_statistics flag
+ */
+static void
+mptsas_set_pkt_reason(mptsas_t *mpt, mptsas_cmd_t *cmd, uchar_t reason,
+    uint_t stat)
+{
+#ifndef __lock_lint
+	_NOTE(ARGUNUSED(mpt))
+#endif
+
+	NDBG25(("mptsas_set_pkt_reason: cmd=0x%p reason=%x stat=%x",
+	    (void *)cmd, reason, stat));
+
+	if (cmd) {
+		if (cmd->cmd_pkt->pkt_reason == CMD_CMPLT) {
+			cmd->cmd_pkt->pkt_reason = reason;
+		}
+		cmd->cmd_pkt->pkt_statistics |= stat;
+	}
+}
+
+static void
+mptsas_start_watch_reset_delay()
+{
+	NDBG22(("mptsas_start_watch_reset_delay"));
+
+	mutex_enter(&mptsas_global_mutex);
+	if (mptsas_reset_watch == NULL && mptsas_timeouts_enabled) {
+		mptsas_reset_watch = timeout(mptsas_watch_reset_delay, NULL,
+		    drv_usectohz((clock_t)
+		    MPTSAS_WATCH_RESET_DELAY_TICK * 1000));
+		ASSERT(mptsas_reset_watch != NULL);
+	}
+	mutex_exit(&mptsas_global_mutex);
+}
+
+static void
+mptsas_setup_bus_reset_delay(mptsas_t *mpt)
+{
+	mptsas_target_t	*ptgt = NULL;
+
+	NDBG22(("mptsas_setup_bus_reset_delay"));
+	ptgt = (mptsas_target_t *)mptsas_hash_traverse(&mpt->m_active->m_tgttbl,
+	    MPTSAS_HASH_FIRST);
+	while (ptgt != NULL) {
+		mptsas_set_throttle(mpt, ptgt, HOLD_THROTTLE);
+		ptgt->m_reset_delay = mpt->m_scsi_reset_delay;
+
+		ptgt = (mptsas_target_t *)mptsas_hash_traverse(
+		    &mpt->m_active->m_tgttbl, MPTSAS_HASH_NEXT);
+	}
+
+	mptsas_start_watch_reset_delay();
+}
+
+/*
+ * mptsas_watch_reset_delay(_subr) is invoked by timeout() and checks every
+ * mpt instance for active reset delays
+ */
+static void
+mptsas_watch_reset_delay(void *arg)
+{
+#ifndef __lock_lint
+	_NOTE(ARGUNUSED(arg))
+#endif
+
+	mptsas_t	*mpt;
+	int		not_done = 0;
+
+	NDBG22(("mptsas_watch_reset_delay"));
+
+	mutex_enter(&mptsas_global_mutex);
+	mptsas_reset_watch = 0;
+	mutex_exit(&mptsas_global_mutex);
+	rw_enter(&mptsas_global_rwlock, RW_READER);
+	for (mpt = mptsas_head; mpt != NULL; mpt = mpt->m_next) {
+		if (mpt->m_tran == 0) {
+			continue;
+		}
+		mutex_enter(&mpt->m_mutex);
+		not_done += mptsas_watch_reset_delay_subr(mpt);
+		mutex_exit(&mpt->m_mutex);
+	}
+	rw_exit(&mptsas_global_rwlock);
+
+	if (not_done) {
+		mptsas_start_watch_reset_delay();
+	}
+}
+
+static int
+mptsas_watch_reset_delay_subr(mptsas_t *mpt)
+{
+	int		done = 0;
+	int		restart = 0;
+	mptsas_target_t	*ptgt = NULL;
+
+	NDBG22(("mptsas_watch_reset_delay_subr: mpt=0x%p", (void *)mpt));
+
+	ASSERT(mutex_owned(&mpt->m_mutex));
+
+	ptgt = (mptsas_target_t *)mptsas_hash_traverse(&mpt->m_active->m_tgttbl,
+	    MPTSAS_HASH_FIRST);
+	while (ptgt != NULL) {
+		if (ptgt->m_reset_delay != 0) {
+			ptgt->m_reset_delay -=
+			    MPTSAS_WATCH_RESET_DELAY_TICK;
+			if (ptgt->m_reset_delay <= 0) {
+				ptgt->m_reset_delay = 0;
+				mptsas_set_throttle(mpt, ptgt,
+				    MAX_THROTTLE);
+				restart++;
+			} else {
+				done = -1;
+			}
+		}
+
+		ptgt = (mptsas_target_t *)mptsas_hash_traverse(
+		    &mpt->m_active->m_tgttbl, MPTSAS_HASH_NEXT);
+	}
+
+	if (restart > 0) {
+		mptsas_restart_hba(mpt);
+	}
+	return (done);
+}
+
+#ifdef MPTSAS_TEST
+static void
+mptsas_test_reset(mptsas_t *mpt, int target)
+{
+	mptsas_target_t    *ptgt = NULL;
+
+	if (mptsas_rtest == target) {
+		if (mptsas_do_scsi_reset(mpt, target) == TRUE) {
+			mptsas_rtest = -1;
+		}
+		if (mptsas_rtest == -1) {
+			NDBG22(("mptsas_test_reset success"));
+		}
+	}
+}
+#endif
+
+/*
+ * abort handling:
+ *
+ * Notes:
+ *	- if pkt is not NULL, abort just that command
+ *	- if pkt is NULL, abort all outstanding commands for target
+ */
+static int
+mptsas_scsi_abort(struct scsi_address *ap, struct scsi_pkt *pkt)
+{
+	mptsas_t		*mpt = ADDR2MPT(ap);
+	int			rval;
+	mptsas_tgt_private_t	*tgt_private;
+	int			target, lun;
+
+	tgt_private = (mptsas_tgt_private_t *)ap->a_hba_tran->
+	    tran_tgt_private;
+	ASSERT(tgt_private != NULL);
+	target = tgt_private->t_private->m_devhdl;
+	lun = tgt_private->t_lun;
+
+	NDBG23(("mptsas_scsi_abort: target=%d.%d", target, lun));
+
+	mutex_enter(&mpt->m_mutex);
+	rval = mptsas_do_scsi_abort(mpt, target, lun, pkt);
+	mutex_exit(&mpt->m_mutex);
+	return (rval);
+}
+
+static int
+mptsas_do_scsi_abort(mptsas_t *mpt, int target, int lun, struct scsi_pkt *pkt)
+{
+	mptsas_cmd_t	*sp = NULL;
+	mptsas_slots_t	*slots = mpt->m_active;
+	int		rval = FALSE;
+
+	ASSERT(mutex_owned(&mpt->m_mutex));
+
+	/*
+	 * Abort the command pkt on the target/lun in ap.  If pkt is
+	 * NULL, abort all outstanding commands on that target/lun.
+	 * If you can abort them, return 1, else return 0.
+	 * Each packet that's aborted should be sent back to the target
+	 * driver through the callback routine, with pkt_reason set to
+	 * CMD_ABORTED.
+	 *
+	 * abort cmd pkt on HBA hardware; clean out of outstanding
+	 * command lists, etc.
+	 */
+	if (pkt != NULL) {
+		/* abort the specified packet */
+		sp = PKT2CMD(pkt);
+
+		if (sp->cmd_queued) {
+			NDBG23(("mptsas_do_scsi_abort: queued sp=0x%p aborted",
+			    (void *)sp));
+			mptsas_waitq_delete(mpt, sp);
+			mptsas_set_pkt_reason(mpt, sp, CMD_ABORTED,
+			    STAT_ABORTED);
+			mptsas_doneq_add(mpt, sp);
+			rval = TRUE;
+			goto done;
+		}
+
+		/*
+		 * Have mpt firmware abort this command
+		 */
+
+		if (slots->m_slot[sp->cmd_slot] != NULL) {
+			rval = mptsas_ioc_task_management(mpt,
+			    MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK, target,
+			    lun);
+
+			/*
+			 * The transport layer expects only TRUE and FALSE.
+			 * Therefore, if mptsas_ioc_task_management returns
+			 * FAILED we will return FALSE.
+			 */
+			if (rval == FAILED)
+				rval = FALSE;
+			goto done;
+		}
+	}
+
+	/*
+	 * If pkt is NULL then abort task set
+	 */
+	rval = mptsas_ioc_task_management(mpt,
+	    MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET, target, lun);
+
+	/*
+	 * The transport layer expects only TRUE and FALSE.
+	 * Therefore, if mptsas_ioc_task_management returns
+	 * FAILED we will return FALSE.
+	 */
+	if (rval == FAILED)
+		rval = FALSE;
+
+#ifdef MPTSAS_TEST
+	if (rval && mptsas_test_stop) {
+		debug_enter("mptsas_do_scsi_abort");
+	}
+#endif
+
+done:
+	mptsas_doneq_empty(mpt);
+	return (rval);
+}
+
+/*
+ * capability handling:
+ * (*tran_getcap).  Get the capability named, and return its value.
+ */
+static int
+mptsas_scsi_getcap(struct scsi_address *ap, char *cap, int tgtonly)
+{
+	mptsas_t	*mpt = ADDR2MPT(ap);
+	int		ckey;
+	int		rval = FALSE;
+
+	NDBG24(("mptsas_scsi_getcap: target=%d, cap=%s tgtonly=%x",
+	    ap->a_target, cap, tgtonly));
+
+	mutex_enter(&mpt->m_mutex);
+
+	if ((mptsas_capchk(cap, tgtonly, &ckey)) != TRUE) {
+		mutex_exit(&mpt->m_mutex);
+		return (UNDEFINED);
+	}
+
+	switch (ckey) {
+	case SCSI_CAP_DMA_MAX:
+		rval = (int)mpt->m_msg_dma_attr.dma_attr_maxxfer;
+		break;
+	case SCSI_CAP_ARQ:
+		rval = TRUE;
+		break;
+	case SCSI_CAP_MSG_OUT:
+	case SCSI_CAP_PARITY:
+	case SCSI_CAP_UNTAGGED_QING:
+		rval = TRUE;
+		break;
+	case SCSI_CAP_TAGGED_QING:
+		rval = TRUE;
+		break;
+	case SCSI_CAP_RESET_NOTIFICATION:
+		rval = TRUE;
+		break;
+	case SCSI_CAP_LINKED_CMDS:
+		rval = FALSE;
+		break;
+	case SCSI_CAP_QFULL_RETRIES:
+		rval = ((mptsas_tgt_private_t *)(ap->a_hba_tran->
+		    tran_tgt_private))->t_private->m_qfull_retries;
+		break;
+	case SCSI_CAP_QFULL_RETRY_INTERVAL:
+		rval = drv_hztousec(((mptsas_tgt_private_t *)
+		    (ap->a_hba_tran->tran_tgt_private))->
+		    t_private->m_qfull_retry_interval) / 1000;
+		break;
+	case SCSI_CAP_CDB_LEN:
+		rval = CDB_GROUP4;
+		break;
+	case SCSI_CAP_INTERCONNECT_TYPE:
+		rval = INTERCONNECT_SAS;
+		break;
+	default:
+		rval = UNDEFINED;
+		break;
+	}
+
+	NDBG24(("mptsas_scsi_getcap: %s, rval=%x", cap, rval));
+
+	mutex_exit(&mpt->m_mutex);
+	return (rval);
+}
+
+/*
+ * (*tran_setcap).  Set the capability named to the value given.
+ */
+static int
+mptsas_scsi_setcap(struct scsi_address *ap, char *cap, int value, int tgtonly)
+{
+	mptsas_t	*mpt = ADDR2MPT(ap);
+	int		ckey;
+	int		rval = FALSE;
+
+	NDBG24(("mptsas_scsi_setcap: target=%d, cap=%s value=%x tgtonly=%x",
+	    ap->a_target, cap, value, tgtonly));
+
+	if (!tgtonly) {
+		return (rval);
+	}
+
+	mutex_enter(&mpt->m_mutex);
+
+	if ((mptsas_capchk(cap, tgtonly, &ckey)) != TRUE) {
+		mutex_exit(&mpt->m_mutex);
+		return (UNDEFINED);
+	}
+
+	switch (ckey) {
+	case SCSI_CAP_DMA_MAX:
+	case SCSI_CAP_MSG_OUT:
+	case SCSI_CAP_PARITY:
+	case SCSI_CAP_INITIATOR_ID:
+	case SCSI_CAP_LINKED_CMDS:
+	case SCSI_CAP_UNTAGGED_QING:
+	case SCSI_CAP_RESET_NOTIFICATION:
+		/*
+		 * None of these are settable via
+		 * the capability interface.
+		 */
+		break;
+	case SCSI_CAP_ARQ:
+		/*
+		 * We cannot turn off arq so return false if asked to
+		 */
+		if (value) {
+			rval = TRUE;
+		} else {
+			rval = FALSE;
+		}
+		break;
+	case SCSI_CAP_TAGGED_QING:
+		mptsas_set_throttle(mpt, ((mptsas_tgt_private_t *)
+		    (ap->a_hba_tran->tran_tgt_private))->t_private,
+		    MAX_THROTTLE);
+		rval = TRUE;
+		break;
+	case SCSI_CAP_QFULL_RETRIES:
+		((mptsas_tgt_private_t *)(ap->a_hba_tran->tran_tgt_private))->
+		    t_private->m_qfull_retries = (uchar_t)value;
+		rval = TRUE;
+		break;
+	case SCSI_CAP_QFULL_RETRY_INTERVAL:
+		((mptsas_tgt_private_t *)(ap->a_hba_tran->tran_tgt_private))->
+		    t_private->m_qfull_retry_interval =
+		    drv_usectohz(value * 1000);
+		rval = TRUE;
+		break;
+	default:
+		rval = UNDEFINED;
+		break;
+	}
+	mutex_exit(&mpt->m_mutex);
+	return (rval);
+}
+
+/*
+ * Utility routine for mptsas_ifsetcap/ifgetcap
+ */
+/*ARGSUSED*/
+static int
+mptsas_capchk(char *cap, int tgtonly, int *cidxp)
+{
+	NDBG24(("mptsas_capchk: cap=%s", cap));
+
+	if (!cap)
+		return (FALSE);
+
+	*cidxp = scsi_hba_lookup_capstr(cap);
+	return (TRUE);
+}
+
+static int
+mptsas_alloc_active_slots(mptsas_t *mpt, int flag)
+{
+	mptsas_slots_t	*old_active = mpt->m_active;
+	mptsas_slots_t	*new_active;
+	size_t		size;
+	int		rval = -1;
+
+	if (mpt->m_ncmds) {
+		NDBG9(("cannot change size of active slots array"));
+		return (rval);
+	}
+
+	size = MPTSAS_SLOTS_SIZE(mpt);
+	new_active = kmem_zalloc(size, flag);
+	if (new_active == NULL) {
+		NDBG1(("new active alloc failed"));
+	} else {
+		/*
+		 * Since SMID 0 is reserved and the TM slot is reserved, the
+		 * number of slots that can be used at any one time is
+		 * m_max_requests - 2.
+		 */
+		mpt->m_active = new_active;
+		mpt->m_active->m_n_slots = (mpt->m_max_requests - 2);
+		mpt->m_active->m_size = size;
+		mpt->m_active->m_tags = 1;
+		if (old_active) {
+			kmem_free(old_active, old_active->m_size);
+		}
+		rval = 0;
+	}
+
+	return (rval);
+}
+
+/*
+ * Error logging, printing, and debug print routines.
+ */
+static char *mptsas_label = "mpt_sas";
+
+/*PRINTFLIKE3*/
+void
+mptsas_log(mptsas_t *mpt, int level, char *fmt, ...)
+{
+	dev_info_t	*dev;
+	va_list		ap;
+
+	if (mpt) {
+		dev = mpt->m_dip;
+	} else {
+		dev = 0;
+	}
+
+	mutex_enter(&mptsas_log_mutex);
+
+	va_start(ap, fmt);
+	(void) vsprintf(mptsas_log_buf, fmt, ap);
+	va_end(ap);
+
+	if (level == CE_CONT) {
+		scsi_log(dev, mptsas_label, level, "%s\n", mptsas_log_buf);
+	} else {
+		scsi_log(dev, mptsas_label, level, "%s", mptsas_log_buf);
+	}
+
+	mutex_exit(&mptsas_log_mutex);
+}
+
+#ifdef MPTSAS_DEBUG
+/*PRINTFLIKE1*/
+void
+mptsas_printf(char *fmt, ...)
+{
+	dev_info_t	*dev = 0;
+	va_list		ap;
+
+	mutex_enter(&mptsas_log_mutex);
+
+	va_start(ap, fmt);
+	(void) vsprintf(mptsas_log_buf, fmt, ap);
+	va_end(ap);
+
+#ifdef PROM_PRINTF
+	prom_printf("%s:\t%s\n", mptsas_label, mptsas_log_buf);
+#else
+	scsi_log(dev, mptsas_label, SCSI_DEBUG, "%s\n", mptsas_log_buf);
+#endif
+	mutex_exit(&mptsas_log_mutex);
+}
+#endif
+
+/*
+ * timeout handling
+ */
+static void
+mptsas_watch(void *arg)
+{
+#ifndef __lock_lint
+	_NOTE(ARGUNUSED(arg))
+#endif
+
+	mptsas_t	*mpt;
+
+	NDBG30(("mptsas_watch"));
+
+	rw_enter(&mptsas_global_rwlock, RW_READER);
+	for (mpt = mptsas_head; mpt != (mptsas_t *)NULL; mpt = mpt->m_next) {
+
+		mutex_enter(&mpt->m_mutex);
+
+		/* Skip device if not powered on */
+		if (mpt->m_options & MPTSAS_OPT_PM) {
+			if (mpt->m_power_level == PM_LEVEL_D0) {
+				(void) pm_busy_component(mpt->m_dip, 0);
+				mpt->m_busy = 1;
+			} else {
+				mutex_exit(&mpt->m_mutex);
+				continue;
+			}
+		}
+
+		/*
+		 * For now, always call mptsas_watchsubr.
+		 */
+		mptsas_watchsubr(mpt);
+
+		if (mpt->m_options & MPTSAS_OPT_PM) {
+			mpt->m_busy = 0;
+			(void) pm_idle_component(mpt->m_dip, 0);
+		}
+
+		mutex_exit(&mpt->m_mutex);
+	}
+	rw_exit(&mptsas_global_rwlock);
+
+	mutex_enter(&mptsas_global_mutex);
+	if (mptsas_timeouts_enabled)
+		mptsas_timeout_id = timeout(mptsas_watch, NULL, mptsas_tick);
+	mutex_exit(&mptsas_global_mutex);
+}
+
+static void
+mptsas_watchsubr(mptsas_t *mpt)
+{
+	int		i;
+	mptsas_cmd_t	*cmd;
+	mptsas_target_t	*ptgt = NULL;
+
+	NDBG30(("mptsas_watchsubr: mpt=0x%p", (void *)mpt));
+
+#ifdef MPTSAS_TEST
+	if (mptsas_enable_untagged) {
+		mptsas_test_untagged++;
+	}
+#endif
+
+	/*
+	 * Check for commands stuck in active slot
+	 * Account for TM requests, which use the last SMID.
+	 */
+	for (i = 0; i <= mpt->m_active->m_n_slots; i++) {
+		if ((cmd = mpt->m_active->m_slot[i]) != NULL) {
+			if ((cmd->cmd_flags & CFLAG_CMDIOC) == 0) {
+				cmd->cmd_active_timeout -=
+				    mptsas_scsi_watchdog_tick;
+				if (cmd->cmd_active_timeout <= 0) {
+					/*
+					 * There seems to be a command stuck
+					 * in the active slot.  Drain throttle.
+					 */
+					mptsas_set_throttle(mpt,
+					    cmd->cmd_tgt_addr,
+					    DRAIN_THROTTLE);
+				}
+			}
+			if ((cmd->cmd_flags & CFLAG_PASSTHRU) ||
+			    (cmd->cmd_flags & CFLAG_CONFIG)) {
+				cmd->cmd_active_timeout -=
+				    mptsas_scsi_watchdog_tick;
+				if (cmd->cmd_active_timeout <= 0) {
+					/*
+					 * passthrough command timeout
+					 */
+					cmd->cmd_flags |= (CFLAG_FINISHED |
+					    CFLAG_TIMEOUT);
+					cv_broadcast(&mpt->m_passthru_cv);
+					cv_broadcast(&mpt->m_config_cv);
+				}
+			}
+		}
+	}
+
+	ptgt = (mptsas_target_t *)mptsas_hash_traverse(&mpt->m_active->m_tgttbl,
+	    MPTSAS_HASH_FIRST);
+	while (ptgt != NULL) {
+		/*
+		 * If we were draining due to a qfull condition,
+		 * go back to full throttle.
+		 */
+		if ((ptgt->m_t_throttle < MAX_THROTTLE) &&
+		    (ptgt->m_t_throttle > HOLD_THROTTLE) &&
+		    (ptgt->m_t_ncmds < ptgt->m_t_throttle)) {
+			mptsas_set_throttle(mpt, ptgt, MAX_THROTTLE);
+			mptsas_restart_hba(mpt);
+		}
+
+		if ((ptgt->m_t_ncmds > 0) &&
+		    (ptgt->m_timebase)) {
+
+			if (ptgt->m_timebase <=
+			    mptsas_scsi_watchdog_tick) {
+				ptgt->m_timebase +=
+				    mptsas_scsi_watchdog_tick;
+				ptgt = (mptsas_target_t *)mptsas_hash_traverse(
+				    &mpt->m_active->m_tgttbl, MPTSAS_HASH_NEXT);
+				continue;
+			}
+
+			ptgt->m_timeout -= mptsas_scsi_watchdog_tick;
+
+			if (ptgt->m_timeout < 0) {
+				mptsas_cmd_timeout(mpt, ptgt->m_devhdl);
+				ptgt = (mptsas_target_t *)mptsas_hash_traverse(
+				    &mpt->m_active->m_tgttbl, MPTSAS_HASH_NEXT);
+				continue;
+			}
+
+			if ((ptgt->m_timeout) <=
+			    mptsas_scsi_watchdog_tick) {
+				NDBG23(("pending timeout"));
+				mptsas_set_throttle(mpt, ptgt,
+				    DRAIN_THROTTLE);
+			}
+		}
+
+		ptgt = (mptsas_target_t *)mptsas_hash_traverse(
+		    &mpt->m_active->m_tgttbl, MPTSAS_HASH_NEXT);
+	}
+}
+
+/*
+ * timeout recovery
+ */
+static void
+mptsas_cmd_timeout(mptsas_t *mpt, uint16_t devhdl)
+{
+
+	NDBG29(("mptsas_cmd_timeout: target=%d", devhdl));
+	mptsas_log(mpt, CE_WARN, "Disconnected command timeout for "
+	    "Target %d", devhdl);
+
+	/*
+	 * If the current target is not the target passed in,
+	 * try to reset that target.
+	 */
+	NDBG29(("mptsas_cmd_timeout: device reset"));
+	if (mptsas_do_scsi_reset(mpt, devhdl) != TRUE) {
+		mptsas_log(mpt, CE_WARN, "Target %d reset for command timeout "
+		    "recovery failed!", devhdl);
+	}
+}
+
+/*
+ * Device / Hotplug control
+ */
+static int
+mptsas_scsi_quiesce(dev_info_t *dip)
+{
+	mptsas_t	*mpt;
+	scsi_hba_tran_t	*tran;
+
+	tran = ddi_get_driver_private(dip);
+	if (tran == NULL || (mpt = TRAN2MPT(tran)) == NULL)
+		return (-1);
+
+	return (mptsas_quiesce_bus(mpt));
+}
+
+static int
+mptsas_scsi_unquiesce(dev_info_t *dip)
+{
+	mptsas_t		*mpt;
+	scsi_hba_tran_t	*tran;
+
+	tran = ddi_get_driver_private(dip);
+	if (tran == NULL || (mpt = TRAN2MPT(tran)) == NULL)
+		return (-1);
+
+	return (mptsas_unquiesce_bus(mpt));
+}
+
+static int
+mptsas_quiesce_bus(mptsas_t *mpt)
+{
+	mptsas_target_t	*ptgt = NULL;
+
+	NDBG28(("mptsas_quiesce_bus"));
+	mutex_enter(&mpt->m_mutex);
+
+	/* Set all the throttles to zero */
+	ptgt = (mptsas_target_t *)mptsas_hash_traverse(&mpt->m_active->m_tgttbl,
+	    MPTSAS_HASH_FIRST);
+	while (ptgt != NULL) {
+		mptsas_set_throttle(mpt, ptgt, HOLD_THROTTLE);
+
+		ptgt = (mptsas_target_t *)mptsas_hash_traverse(
+		    &mpt->m_active->m_tgttbl, MPTSAS_HASH_NEXT);
+	}
+
+	/* If there are any outstanding commands in the queue */
+	if (mpt->m_ncmds) {
+		mpt->m_softstate |= MPTSAS_SS_DRAINING;
+		mpt->m_quiesce_timeid = timeout(mptsas_ncmds_checkdrain,
+		    mpt, (MPTSAS_QUIESCE_TIMEOUT * drv_usectohz(1000000)));
+		if (cv_wait_sig(&mpt->m_cv, &mpt->m_mutex) == 0) {
+			/*
+			 * Quiesce has been interrupted
+			 */
+			mpt->m_softstate &= ~MPTSAS_SS_DRAINING;
+			ptgt = (mptsas_target_t *)mptsas_hash_traverse(
+			    &mpt->m_active->m_tgttbl, MPTSAS_HASH_FIRST);
+			while (ptgt != NULL) {
+				mptsas_set_throttle(mpt, ptgt, MAX_THROTTLE);
+
+				ptgt = (mptsas_target_t *)mptsas_hash_traverse(
+				    &mpt->m_active->m_tgttbl, MPTSAS_HASH_NEXT);
+			}
+			mptsas_restart_hba(mpt);
+			if (mpt->m_quiesce_timeid != 0) {
+				timeout_id_t tid = mpt->m_quiesce_timeid;
+				mpt->m_quiesce_timeid = 0;
+				mutex_exit(&mpt->m_mutex);
+				(void) untimeout(tid);
+				return (-1);
+			}
+			mutex_exit(&mpt->m_mutex);
+			return (-1);
+		} else {
+			/* Bus has been quiesced */
+			ASSERT(mpt->m_quiesce_timeid == 0);
+			mpt->m_softstate &= ~MPTSAS_SS_DRAINING;
+			mpt->m_softstate |= MPTSAS_SS_QUIESCED;
+			mutex_exit(&mpt->m_mutex);
+			return (0);
+		}
+	}
+	/* Bus was not busy - QUIESCED */
+	mutex_exit(&mpt->m_mutex);
+
+	return (0);
+}
+
+static int
+mptsas_unquiesce_bus(mptsas_t *mpt)
+{
+	mptsas_target_t	*ptgt = NULL;
+
+	NDBG28(("mptsas_unquiesce_bus"));
+	mutex_enter(&mpt->m_mutex);
+	mpt->m_softstate &= ~MPTSAS_SS_QUIESCED;
+	ptgt = (mptsas_target_t *)mptsas_hash_traverse(&mpt->m_active->m_tgttbl,
+	    MPTSAS_HASH_FIRST);
+	while (ptgt != NULL) {
+		mptsas_set_throttle(mpt, ptgt, MAX_THROTTLE);
+
+		ptgt = (mptsas_target_t *)mptsas_hash_traverse(
+		    &mpt->m_active->m_tgttbl, MPTSAS_HASH_NEXT);
+	}
+	mptsas_restart_hba(mpt);
+	mutex_exit(&mpt->m_mutex);
+	return (0);
+}
+
+static void
+mptsas_ncmds_checkdrain(void *arg)
+{
+	mptsas_t	*mpt = arg;
+	mptsas_target_t	*ptgt = NULL;
+
+	mutex_enter(&mpt->m_mutex);
+	if (mpt->m_softstate & MPTSAS_SS_DRAINING) {
+		mpt->m_quiesce_timeid = 0;
+		if (mpt->m_ncmds == 0) {
+			/* Command queue has been drained */
+			cv_signal(&mpt->m_cv);
+		} else {
+			/*
+			 * The throttle may have been reset because
+			 * of a SCSI bus reset
+			 */
+			ptgt = (mptsas_target_t *)mptsas_hash_traverse(
+			    &mpt->m_active->m_tgttbl, MPTSAS_HASH_FIRST);
+			while (ptgt != NULL) {
+				mptsas_set_throttle(mpt, ptgt, HOLD_THROTTLE);
+
+				ptgt = (mptsas_target_t *)mptsas_hash_traverse(
+				    &mpt->m_active->m_tgttbl, MPTSAS_HASH_NEXT);
+			}
+
+			mpt->m_quiesce_timeid = timeout(mptsas_ncmds_checkdrain,
+			    mpt, (MPTSAS_QUIESCE_TIMEOUT *
+			    drv_usectohz(1000000)));
+		}
+	}
+	mutex_exit(&mpt->m_mutex);
+}
+
+static void
+mptsas_dump_cmd(mptsas_t *mpt, mptsas_cmd_t *cmd)
+{
+	int	i;
+	uint8_t	*cp = (uchar_t *)cmd->cmd_pkt->pkt_cdbp;
+	char	buf[128];
+
+	buf[0] = '\0';
+	mptsas_log(mpt, CE_NOTE, "?Cmd (0x%p) dump for Target %d Lun %d:\n",
+	    (void *)cmd, Tgt(cmd), Lun(cmd));
+	(void) sprintf(&buf[0], "\tcdb=[");
+	for (i = 0; i < (int)cmd->cmd_cdblen; i++) {
+		(void) sprintf(&buf[strlen(buf)], " 0x%x", *cp++);
+	}
+	(void) sprintf(&buf[strlen(buf)], " ]");
+	mptsas_log(mpt, CE_NOTE, "?%s\n", buf);
+	mptsas_log(mpt, CE_NOTE,
+	    "?pkt_flags=0x%x pkt_statistics=0x%x pkt_state=0x%x\n",
+	    cmd->cmd_pkt->pkt_flags, cmd->cmd_pkt->pkt_statistics,
+	    cmd->cmd_pkt->pkt_state);
+	mptsas_log(mpt, CE_NOTE, "?pkt_scbp=0x%x cmd_flags=0x%x\n",
+	    *(cmd->cmd_pkt->pkt_scbp), cmd->cmd_flags);
+}
+
+static void
+mptsas_start_passthru(mptsas_t *mpt, mptsas_cmd_t *cmd)
+{
+	caddr_t			memp;
+	pMPI2RequestHeader_t	request_hdrp;
+	struct scsi_pkt		*pkt = cmd->cmd_pkt;
+	mptsas_pt_request_t	*pt = pkt->pkt_ha_private;
+	uint32_t		request_size, data_size, dataout_size;
+	uint32_t		direction;
+	ddi_dma_cookie_t	data_cookie;
+	ddi_dma_cookie_t	dataout_cookie;
+	uint32_t		request_desc_low, request_desc_high = 0;
+	uint32_t		i, sense_bufp;
+	uint8_t			desc_type;
+	uint8_t			*request, function;
+	ddi_dma_handle_t	dma_hdl = mpt->m_dma_req_frame_hdl;
+	ddi_acc_handle_t	acc_hdl = mpt->m_acc_req_frame_hdl;
+
+	desc_type = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
+
+	request = pt->request;
+	direction = pt->direction;
+	request_size = pt->request_size;
+	data_size = pt->data_size;
+	dataout_size = pt->dataout_size;
+	data_cookie = pt->data_cookie;
+	dataout_cookie = pt->dataout_cookie;
+
+	/*
+	 * Store the passthrough message in memory location
+	 * corresponding to our slot number
+	 */
+	memp = mpt->m_req_frame + (mpt->m_req_frame_size * cmd->cmd_slot);
+	request_hdrp = (pMPI2RequestHeader_t)memp;
+	bzero(memp, mpt->m_req_frame_size);
+
+	for (i = 0; i < request_size; i++) {
+		bcopy(request + i, memp + i, 1);
+	}
+
+	if (data_size || dataout_size) {
+		pMpi2SGESimple64_t	sgep;
+		uint32_t		sge_flags;
+
+		sgep = (pMpi2SGESimple64_t)((uint8_t *)request_hdrp +
+		    request_size);
+		if (dataout_size) {
+
+			sge_flags = dataout_size |
+			    ((uint32_t)(MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
+			    MPI2_SGE_FLAGS_END_OF_BUFFER |
+			    MPI2_SGE_FLAGS_HOST_TO_IOC |
+			    MPI2_SGE_FLAGS_64_BIT_ADDRESSING) <<
+			    MPI2_SGE_FLAGS_SHIFT);
+			ddi_put32(acc_hdl, &sgep->FlagsLength, sge_flags);
+			ddi_put32(acc_hdl, &sgep->Address.Low,
+			    (uint32_t)(dataout_cookie.dmac_laddress &
+			    0xffffffffull));
+			ddi_put32(acc_hdl, &sgep->Address.High,
+			    (uint32_t)(dataout_cookie.dmac_laddress
+			    >> 32));
+			sgep++;
+		}
+		sge_flags = data_size;
+		sge_flags |= ((uint32_t)(MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
+		    MPI2_SGE_FLAGS_LAST_ELEMENT |
+		    MPI2_SGE_FLAGS_END_OF_BUFFER |
+		    MPI2_SGE_FLAGS_END_OF_LIST |
+		    MPI2_SGE_FLAGS_64_BIT_ADDRESSING) <<
+		    MPI2_SGE_FLAGS_SHIFT);
+		if (direction == MPTSAS_PASS_THRU_DIRECTION_WRITE) {
+			sge_flags |= ((uint32_t)(MPI2_SGE_FLAGS_HOST_TO_IOC) <<
+			    MPI2_SGE_FLAGS_SHIFT);
+		} else {
+			sge_flags |= ((uint32_t)(MPI2_SGE_FLAGS_IOC_TO_HOST) <<
+			    MPI2_SGE_FLAGS_SHIFT);
+		}
+		ddi_put32(acc_hdl, &sgep->FlagsLength,
+		    sge_flags);
+		ddi_put32(acc_hdl, &sgep->Address.Low,
+		    (uint32_t)(data_cookie.dmac_laddress &
+		    0xffffffffull));
+		ddi_put32(acc_hdl, &sgep->Address.High,
+		    (uint32_t)(data_cookie.dmac_laddress >> 32));
+	}
+
+	function = request_hdrp->Function;
+	if ((function == MPI2_FUNCTION_SCSI_IO_REQUEST) ||
+	    (function == MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) {
+		pMpi2SCSIIORequest_t	scsi_io_req;
+
+		scsi_io_req = (pMpi2SCSIIORequest_t)request_hdrp;
+		/*
+		 * Put SGE for data and data_out buffer at the end of
+		 * scsi_io_request message header.(64 bytes in total)
+		 * Following above SGEs, the residual space will be
+		 * used by sense data.
+		 */
+		ddi_put8(acc_hdl,
+		    &scsi_io_req->SenseBufferLength,
+		    (uint8_t)(request_size - 64));
+
+		sense_bufp = mpt->m_req_frame_dma_addr +
+		    (mpt->m_req_frame_size * cmd->cmd_slot);
+		sense_bufp += 64;
+		ddi_put32(acc_hdl,
+		    &scsi_io_req->SenseBufferLowAddress, sense_bufp);
+
+		/*
+		 * Set SGLOffset0 value
+		 */
+		ddi_put8(acc_hdl, &scsi_io_req->SGLOffset0,
+		    offsetof(MPI2_SCSI_IO_REQUEST, SGL) / 4);
+
+		/*
+		 * Setup descriptor info
+		 */
+		desc_type = MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO;
+		request_desc_high = (ddi_get16(acc_hdl,
+		    &scsi_io_req->DevHandle) << 16);
+	}
+
+	/*
+	 * We must wait till the message has been completed before
+	 * beginning the next message so we wait for this one to
+	 * finish.
+	 */
+	(void) ddi_dma_sync(dma_hdl, 0, 0, DDI_DMA_SYNC_FORDEV);
+	request_desc_low = (cmd->cmd_slot << 16) + desc_type;
+	cmd->cmd_rfm = NULL;
+	MPTSAS_START_CMD(mpt, request_desc_low, request_desc_high);
+	if ((mptsas_check_dma_handle(dma_hdl) != DDI_SUCCESS) ||
+	    (mptsas_check_acc_handle(acc_hdl) != DDI_SUCCESS)) {
+		ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
+	}
+}
+
+
+
+static int
+mptsas_do_passthru(mptsas_t *mpt, uint8_t *request, uint8_t *reply,
+    uint8_t *data, uint32_t request_size, uint32_t reply_size,
+    uint32_t data_size, uint32_t direction, uint8_t *dataout,
+    uint32_t dataout_size, short timeout, int mode)
+{
+	mptsas_pt_request_t		pt;
+	mptsas_dma_alloc_state_t	data_dma_state;
+	mptsas_dma_alloc_state_t	dataout_dma_state;
+	caddr_t				memp;
+	mptsas_cmd_t			*cmd = NULL;
+	struct scsi_pkt			*pkt;
+	uint32_t			reply_len = 0, sense_len = 0;
+	pMPI2RequestHeader_t		request_hdrp;
+	pMPI2RequestHeader_t		request_msg;
+	pMPI2DefaultReply_t		reply_msg;
+	Mpi2SCSIIOReply_t		rep_msg;
+	int				i, status = 0, pt_flags = 0, rv = 0;
+	int				rvalue;
+	uint32_t			reply_index;
+	uint8_t				function;
+
+	ASSERT(mutex_owned(&mpt->m_mutex));
+
+	reply_msg = (pMPI2DefaultReply_t)(&rep_msg);
+	bzero(reply_msg, sizeof (MPI2_DEFAULT_REPLY));
+	request_msg = kmem_zalloc(request_size, KM_SLEEP);
+
+	mutex_exit(&mpt->m_mutex);
+	/*
+	 * copy in the request buffer since it could be used by
+	 * another thread when the pt request into waitq
+	 */
+	if (ddi_copyin(request, request_msg, request_size, mode)) {
+		mutex_enter(&mpt->m_mutex);
+		status = EFAULT;
+		mptsas_log(mpt, CE_WARN, "failed to copy request data");
+		goto out;
+	}
+	mutex_enter(&mpt->m_mutex);
+
+	function = request_msg->Function;
+	if (function == MPI2_FUNCTION_SCSI_TASK_MGMT) {
+		pMpi2SCSITaskManagementRequest_t	task;
+		task = (pMpi2SCSITaskManagementRequest_t)request_msg;
+		mptsas_setup_bus_reset_delay(mpt);
+		rv = mptsas_ioc_task_management(mpt, task->TaskType,
+		    task->DevHandle, (int)task->LUN[1]);
+
+		if (rv != TRUE) {
+			status = EIO;
+			mptsas_log(mpt, CE_WARN, "task management failed");
+		}
+		goto out;
+	}
+
+	if (data_size != 0) {
+		data_dma_state.size = data_size;
+		if (mptsas_passthru_dma_alloc(mpt, &data_dma_state) !=
+		    DDI_SUCCESS) {
+			status = ENOMEM;
+			mptsas_log(mpt, CE_WARN, "failed to alloc DMA "
+			    "resource");
+			goto out;
+		}
+		pt_flags |= MPTSAS_DATA_ALLOCATED;
+		if (direction == MPTSAS_PASS_THRU_DIRECTION_WRITE) {
+			mutex_exit(&mpt->m_mutex);
+			for (i = 0; i < data_size; i++) {
+				if (ddi_copyin(data + i, (uint8_t *)
+				    data_dma_state.memp + i, 1, mode)) {
+					mutex_enter(&mpt->m_mutex);
+					status = EFAULT;
+					mptsas_log(mpt, CE_WARN, "failed to "
+					    "copy read data");
+					goto out;
+				}
+			}
+			mutex_enter(&mpt->m_mutex);
+		}
+	}
+
+	if (dataout_size != 0) {
+		dataout_dma_state.size = dataout_size;
+		if (mptsas_passthru_dma_alloc(mpt, &dataout_dma_state) !=
+		    DDI_SUCCESS) {
+			status = ENOMEM;
+			mptsas_log(mpt, CE_WARN, "failed to alloc DMA "
+			    "resource");
+			goto out;
+		}
+		pt_flags |= MPTSAS_DATAOUT_ALLOCATED;
+		mutex_exit(&mpt->m_mutex);
+		for (i = 0; i < dataout_size; i++) {
+			if (ddi_copyin(dataout + i, (uint8_t *)
+			    dataout_dma_state.memp + i, 1, mode)) {
+				mutex_enter(&mpt->m_mutex);
+				mptsas_log(mpt, CE_WARN, "failed to copy out"
+				    " data");
+				status = EFAULT;
+				goto out;
+			}
+		}
+		mutex_enter(&mpt->m_mutex);
+	}
+
+	if ((rvalue = (mptsas_request_from_pool(mpt, &cmd, &pkt))) == -1) {
+		status = EAGAIN;
+		mptsas_log(mpt, CE_NOTE, "event ack command pool is full");
+		goto out;
+	}
+	pt_flags |= MPTSAS_REQUEST_POOL_CMD;
+
+	bzero((caddr_t)cmd, sizeof (*cmd));
+	bzero((caddr_t)pkt, scsi_pkt_size());
+	bzero((caddr_t)&pt, sizeof (pt));
+
+	cmd->ioc_cmd_slot = (uint32_t)(rvalue);
+
+	pt.request = (uint8_t *)request_msg;
+	pt.direction = direction;
+	pt.request_size = request_size;
+	pt.data_size = data_size;
+	pt.dataout_size = dataout_size;
+	pt.data_cookie = data_dma_state.cookie;
+	pt.dataout_cookie = dataout_dma_state.cookie;
+
+	/*
+	 * Form a blank cmd/pkt to store the acknowledgement message
+	 */
+	pkt->pkt_cdbp		= (opaque_t)&cmd->cmd_cdb[0];
+	pkt->pkt_scbp		= (opaque_t)&cmd->cmd_scb;
+	pkt->pkt_ha_private	= (opaque_t)&pt;
+	pkt->pkt_flags		= FLAG_HEAD;
+	pkt->pkt_time		= timeout;
+	cmd->cmd_pkt		= pkt;
+	cmd->cmd_flags		= CFLAG_CMDIOC | CFLAG_PASSTHRU;
+
+	/*
+	 * Save the command in a slot
+	 */
+	if (mptsas_save_cmd(mpt, cmd) == TRUE) {
+		/*
+		 * Once passthru command get slot, set cmd_flags
+		 * CFLAG_PREPARED.
+		 */
+		cmd->cmd_flags |= CFLAG_PREPARED;
+		mptsas_start_passthru(mpt, cmd);
+	} else {
+		mptsas_waitq_add(mpt, cmd);
+	}
+
+	while ((cmd->cmd_flags & CFLAG_FINISHED) == 0) {
+		cv_wait(&mpt->m_passthru_cv, &mpt->m_mutex);
+	}
+
+	if (cmd->cmd_flags & CFLAG_PREPARED) {
+		memp = mpt->m_req_frame + (mpt->m_req_frame_size *
+		    cmd->cmd_slot);
+		request_hdrp = (pMPI2RequestHeader_t)memp;
+	}
+
+	if (cmd->cmd_flags & CFLAG_TIMEOUT) {
+		status = ETIMEDOUT;
+		mptsas_log(mpt, CE_WARN, "passthrough command timeout");
+		pt_flags |= MPTSAS_CMD_TIMEOUT;
+		goto out;
+	}
+
+	if (cmd->cmd_rfm) {
+		/*
+		 * cmd_rfm is zero means the command reply is a CONTEXT
+		 * reply and no PCI Write to post the free reply SMFA
+		 * because no reply message frame is used.
+		 * cmd_rfm is non-zero means the reply is a ADDRESS
+		 * reply and reply message frame is used.
+		 */
+		pt_flags |= MPTSAS_ADDRESS_REPLY;
+		(void) ddi_dma_sync(mpt->m_dma_reply_frame_hdl, 0, 0,
+		    DDI_DMA_SYNC_FORCPU);
+		reply_msg = (pMPI2DefaultReply_t)
+		    (mpt->m_reply_frame + (cmd->cmd_rfm -
+		    mpt->m_reply_frame_dma_addr));
+	}
+
+	mptsas_fma_check(mpt, cmd);
+	if (pkt->pkt_reason == CMD_TRAN_ERR) {
+		status = EAGAIN;
+		mptsas_log(mpt, CE_WARN, "passthru fma error");
+		goto out;
+	}
+	if (pkt->pkt_reason == CMD_RESET) {
+		status = EAGAIN;
+		mptsas_log(mpt, CE_WARN, "ioc reset abort passthru");
+		goto out;
+	}
+
+	if (pkt->pkt_reason == CMD_INCOMPLETE) {
+		status = EIO;
+		mptsas_log(mpt, CE_WARN, "passthrough command incomplete");
+		goto out;
+	}
+
+	mutex_exit(&mpt->m_mutex);
+	if (cmd->cmd_flags & CFLAG_PREPARED) {
+		function = request_hdrp->Function;
+		if ((function == MPI2_FUNCTION_SCSI_IO_REQUEST) ||
+		    (function == MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) {
+			reply_len = sizeof (MPI2_SCSI_IO_REPLY);
+			sense_len = reply_size - reply_len;
+		} else {
+			reply_len = reply_size;
+			sense_len = 0;
+		}
+
+		for (i = 0; i < reply_len; i++) {
+			if (ddi_copyout((uint8_t *)reply_msg + i, reply + i, 1,
+			    mode)) {
+				mutex_enter(&mpt->m_mutex);
+				status = EFAULT;
+				mptsas_log(mpt, CE_WARN, "failed to copy out "
+				    "reply data");
+				goto out;
+			}
+		}
+		for (i = 0; i < sense_len; i++) {
+			if (ddi_copyout((uint8_t *)request_hdrp + 64 + i,
+			    reply + reply_len + i, 1, mode)) {
+				mutex_enter(&mpt->m_mutex);
+				status = EFAULT;
+				mptsas_log(mpt, CE_WARN, "failed to copy out "
+				    "sense data");
+				goto out;
+			}
+		}
+	}
+
+	if (data_size) {
+		if (direction != MPTSAS_PASS_THRU_DIRECTION_WRITE) {
+			(void) ddi_dma_sync(data_dma_state.handle, 0, 0,
+			    DDI_DMA_SYNC_FORCPU);
+			for (i = 0; i < data_size; i++) {
+				if (ddi_copyout((uint8_t *)(
+				    data_dma_state.memp + i), data + i,  1,
+				    mode)) {
+					mutex_enter(&mpt->m_mutex);
+					status = EFAULT;
+					mptsas_log(mpt, CE_WARN, "failed to "
+					    "copy out the reply data");
+					goto out;
+				}
+			}
+		}
+	}
+	mutex_enter(&mpt->m_mutex);
+out:
+	/*
+	 * Put the reply frame back on the free queue, increment the free
+	 * index, and write the new index to the free index register.  But only
+	 * if this reply is an ADDRESS reply.
+	 */
+	if (pt_flags & MPTSAS_ADDRESS_REPLY) {
+		reply_index = mpt->m_free_index;
+		ddi_put32(mpt->m_acc_free_queue_hdl,
+		    &((uint32_t *)(void *)mpt->m_free_queue)[reply_index],
+		    cmd->cmd_rfm);
+		(void) ddi_dma_sync(mpt->m_dma_free_queue_hdl, 0, 0,
+		    DDI_DMA_SYNC_FORDEV);
+		if (++reply_index == mpt->m_free_queue_depth) {
+			reply_index = 0;
+		}
+		mpt->m_free_index = reply_index;
+		ddi_put32(mpt->m_datap, &mpt->m_reg->ReplyFreeHostIndex,
+		    reply_index);
+	}
+	if (cmd && (cmd->cmd_flags & CFLAG_PREPARED)) {
+		mptsas_remove_cmd(mpt, cmd);
+		pt_flags &= (~MPTSAS_REQUEST_POOL_CMD);
+	}
+	if (pt_flags & MPTSAS_REQUEST_POOL_CMD)
+		mptsas_return_to_pool(mpt, cmd);
+	if (pt_flags & MPTSAS_DATA_ALLOCATED) {
+		if (mptsas_check_dma_handle(data_dma_state.handle) !=
+		    DDI_SUCCESS) {
+			ddi_fm_service_impact(mpt->m_dip,
+			    DDI_SERVICE_UNAFFECTED);
+			status = EFAULT;
+		}
+		mptsas_passthru_dma_free(&data_dma_state);
+	}
+	if (pt_flags & MPTSAS_DATAOUT_ALLOCATED) {
+		if (mptsas_check_dma_handle(dataout_dma_state.handle) !=
+		    DDI_SUCCESS) {
+			ddi_fm_service_impact(mpt->m_dip,
+			    DDI_SERVICE_UNAFFECTED);
+			status = EFAULT;
+		}
+		mptsas_passthru_dma_free(&dataout_dma_state);
+	}
+	if (pt_flags & MPTSAS_CMD_TIMEOUT) {
+		if ((mptsas_restart_ioc(mpt)) == DDI_FAILURE) {
+			mptsas_log(mpt, CE_WARN, "mptsas_restart_ioc failed");
+		}
+	}
+	if (request_msg)
+		kmem_free(request_msg, request_size);
+
+	return (status);
+}
+
+static int
+mptsas_pass_thru(mptsas_t *mpt, mptsas_pass_thru_t *data, int mode)
+{
+	/*
+	 * If timeout is 0, set timeout to default of 60 seconds.
+	 */
+	if (data->Timeout == 0) {
+		data->Timeout = MPTSAS_PASS_THRU_TIME_DEFAULT;
+	}
+
+	if (((data->DataSize == 0) &&
+	    (data->DataDirection == MPTSAS_PASS_THRU_DIRECTION_NONE)) ||
+	    ((data->DataSize != 0) &&
+	    ((data->DataDirection == MPTSAS_PASS_THRU_DIRECTION_READ) ||
+	    (data->DataDirection == MPTSAS_PASS_THRU_DIRECTION_WRITE) ||
+	    ((data->DataDirection == MPTSAS_PASS_THRU_DIRECTION_BOTH) &&
+	    (data->DataOutSize != 0))))) {
+		if (data->DataDirection == MPTSAS_PASS_THRU_DIRECTION_BOTH) {
+			data->DataDirection = MPTSAS_PASS_THRU_DIRECTION_READ;
+		} else {
+			data->DataOutSize = 0;
+		}
+		/*
+		 * Send passthru request messages
+		 */
+		return (mptsas_do_passthru(mpt,
+		    (uint8_t *)((uintptr_t)data->PtrRequest),
+		    (uint8_t *)((uintptr_t)data->PtrReply),
+		    (uint8_t *)((uintptr_t)data->PtrData),
+		    data->RequestSize, data->ReplySize,
+		    data->DataSize, data->DataDirection,
+		    (uint8_t *)((uintptr_t)data->PtrDataOut),
+		    data->DataOutSize, data->Timeout, mode));
+	} else {
+		return (EINVAL);
+	}
+}
+
+/*
+ * This routine handles the "event query" ioctl.
+ */
+static int
+mptsas_event_query(mptsas_t *mpt, mptsas_event_query_t *data, int mode,
+    int *rval)
+{
+	int			status;
+	mptsas_event_query_t	driverdata;
+	uint8_t			i;
+
+	driverdata.Entries = MPTSAS_EVENT_QUEUE_SIZE;
+
+	mutex_enter(&mpt->m_mutex);
+	for (i = 0; i < 4; i++) {
+		driverdata.Types[i] = mpt->m_event_mask[i];
+	}
+	mutex_exit(&mpt->m_mutex);
+
+	if (ddi_copyout(&driverdata, data, sizeof (driverdata), mode) != 0) {
+		status = EFAULT;
+	} else {
+		*rval = MPTIOCTL_STATUS_GOOD;
+		status = 0;
+	}
+
+	return (status);
+}
+
+/*
+ * This routine handles the "event enable" ioctl.
+ */
+static int
+mptsas_event_enable(mptsas_t *mpt, mptsas_event_enable_t *data, int mode,
+    int *rval)
+{
+	int			status;
+	mptsas_event_enable_t	driverdata;
+	uint8_t			i;
+
+	if (ddi_copyin(data, &driverdata, sizeof (driverdata), mode) == 0) {
+		mutex_enter(&mpt->m_mutex);
+		for (i = 0; i < 4; i++) {
+			mpt->m_event_mask[i] = driverdata.Types[i];
+		}
+		mutex_exit(&mpt->m_mutex);
+
+		*rval = MPTIOCTL_STATUS_GOOD;
+		status = 0;
+	} else {
+		status = EFAULT;
+	}
+	return (status);
+}
+
+/*
+ * This routine handles the "event report" ioctl.
+ */
+static int
+mptsas_event_report(mptsas_t *mpt, mptsas_event_report_t *data, int mode,
+    int *rval)
+{
+	int			status;
+	mptsas_event_report_t	driverdata;
+
+	mutex_enter(&mpt->m_mutex);
+
+	if (ddi_copyin(&data->Size, &driverdata.Size, sizeof (driverdata.Size),
+	    mode) == 0) {
+		if (driverdata.Size >= sizeof (mpt->m_events)) {
+			if (ddi_copyout(mpt->m_events, data->Events,
+			    sizeof (mpt->m_events), mode) != 0) {
+				status = EFAULT;
+			} else {
+				if (driverdata.Size > sizeof (mpt->m_events)) {
+					driverdata.Size =
+					    sizeof (mpt->m_events);
+					if (ddi_copyout(&driverdata.Size,
+					    &data->Size,
+					    sizeof (driverdata.Size),
+					    mode) != 0) {
+						status = EFAULT;
+					} else {
+						*rval = MPTIOCTL_STATUS_GOOD;
+						status = 0;
+					}
+				} else {
+					*rval = MPTIOCTL_STATUS_GOOD;
+					status = 0;
+				}
+			}
+		} else {
+			*rval = MPTIOCTL_STATUS_LEN_TOO_SHORT;
+			status = 0;
+		}
+	} else {
+		status = EFAULT;
+	}
+
+	mutex_exit(&mpt->m_mutex);
+	return (status);
+}
+
+static void
+mptsas_lookup_pci_data(mptsas_t *mpt, mptsas_adapter_data_t *adapter_data)
+{
+	int	*reg_data;
+	uint_t	reglen;
+	char	*fw_rev;
+
+	/*
+	 * Lookup the 'reg' property and extract the other data
+	 */
+	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, mpt->m_dip,
+	    DDI_PROP_DONTPASS, "reg", &reg_data, &reglen) ==
+	    DDI_PROP_SUCCESS) {
+		/*
+		 * Extract the PCI data from the 'reg' property first DWORD.
+		 * The entry looks like the following:
+		 * First DWORD:
+		 * Bits 0 - 7 8-bit Register number
+		 * Bits 8 - 10 3-bit Function number
+		 * Bits 11 - 15 5-bit Device number
+		 * Bits 16 - 23 8-bit Bus number
+		 * Bits 24 - 25 2-bit Address Space type identifier
+		 *
+		 * Store the device number in PCIDeviceHwId.
+		 * Store the function number in MpiPortNumber.
+		 * PciInformation stores bus, device, and function together
+		 */
+		adapter_data->PCIDeviceHwId = (reg_data[0] & 0x0000F800) >> 11;
+		adapter_data->MpiPortNumber = (reg_data[0] & 0x00000700) >> 8;
+		adapter_data->PciInformation = (reg_data[0] & 0x00FFFF00) >> 8;
+		ddi_prop_free((void *)reg_data);
+	} else {
+		/*
+		 * If we can't determine the PCI data then we fill in FF's for
+		 * the data to indicate this.
+		 */
+		adapter_data->PCIDeviceHwId = 0xFFFFFFFF;
+		adapter_data->MpiPortNumber = 0xFFFFFFFF;
+		adapter_data->PciInformation = 0xFFFFFFFF;
+	}
+
+	/*
+	 * Lookup the 'firmware-version' property and extract the data
+	 */
+	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, mpt->m_dip,
+	    DDI_PROP_DONTPASS, "firmware-version", &fw_rev) ==
+	    DDI_PROP_SUCCESS) {
+		/*
+		 * Version is a string of 4 bytes which fits into the DWORD
+		 */
+		(void) strcpy((char *)&adapter_data->MpiFirmwareVersion,
+		    fw_rev);
+		ddi_prop_free(fw_rev);
+	} else {
+		/*
+		 * If we can't determine the PCI data then we fill in FF's for
+		 * the data to indicate this.
+		 */
+		adapter_data->MpiFirmwareVersion = 0xFFFFFFFF;
+	}
+}
+
+static void
+mptsas_read_adapter_data(mptsas_t *mpt, mptsas_adapter_data_t *adapter_data)
+{
+	char	*driver_verstr = MPTSAS_MOD_STRING;
+
+	mptsas_lookup_pci_data(mpt, adapter_data);
+	adapter_data->AdapterType = MPTIOCTL_ADAPTER_TYPE_SAS2;
+	adapter_data->PCIDeviceHwId = (uint32_t)mpt->m_devid;
+	adapter_data->SubSystemId = (uint32_t)mpt->m_ssid;
+	adapter_data->SubsystemVendorId = (uint32_t)mpt->m_svid;
+	(void) strcpy((char *)&adapter_data->DriverVersion[0], driver_verstr);
+}
+
+static void
+mptsas_read_pci_info(mptsas_t *mpt, mptsas_pci_info_t *pci_info)
+{
+	int	*reg_data, i;
+	uint_t	reglen;
+
+	/*
+	 * Lookup the 'reg' property and extract the other data
+	 */
+	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, mpt->m_dip,
+	    DDI_PROP_DONTPASS, "reg", &reg_data, &reglen) ==
+	    DDI_PROP_SUCCESS) {
+		/*
+		 * Extract the PCI data from the 'reg' property first DWORD.
+		 * The entry looks like the following:
+		 * First DWORD:
+		 * Bits 8 - 10 3-bit Function number
+		 * Bits 11 - 15 5-bit Device number
+		 * Bits 16 - 23 8-bit Bus number
+		 */
+		pci_info->BusNumber = (reg_data[0] & 0x00FF0000) >> 16;
+		pci_info->DeviceNumber = (reg_data[0] & 0x0000F800) >> 11;
+		pci_info->FunctionNumber = (reg_data[0] & 0x00000700) >> 8;
+		ddi_prop_free((void *)reg_data);
+	} else {
+		/*
+		 * If we can't determine the PCI info then we fill in FF's for
+		 * the data to indicate this.
+		 */
+		pci_info->BusNumber = 0xFFFFFFFF;
+		pci_info->DeviceNumber = 0xFF;
+		pci_info->FunctionNumber = 0xFF;
+	}
+
+	/*
+	 * Now get the interrupt vector and the pci header.  The vector can
+	 * only be 0 right now.  The header is the first 256 bytes of config
+	 * space.
+	 */
+	pci_info->InterruptVector = 0;
+	for (i = 0; i < sizeof (pci_info->PciHeader); i++) {
+		pci_info->PciHeader[i] = pci_config_get8(mpt->m_config_handle,
+		    i);
+	}
+}
+
+static int
+mptsas_ioctl(dev_t dev, int cmd, intptr_t data, int mode, cred_t *credp,
+    int *rval)
+{
+	int			status = 0;
+	mptsas_t		*mpt;
+	mptsas_update_flash_t	flashdata;
+	mptsas_pass_thru_t	passthru_data;
+	mptsas_adapter_data_t   adapter_data;
+	mptsas_pci_info_t	pci_info;
+	int			copylen;
+
+	*rval = MPTIOCTL_STATUS_GOOD;
+	mpt = ddi_get_soft_state(mptsas_state, MINOR2INST(getminor(dev)));
+	if (mpt == NULL) {
+		return (scsi_hba_ioctl(dev, cmd, data, mode, credp, rval));
+	}
+	if (secpolicy_sys_config(credp, B_FALSE) != 0) {
+		return (EPERM);
+	}
+
+	/* Make sure power level is D0 before accessing registers */
+	mutex_enter(&mpt->m_mutex);
+	if (mpt->m_options & MPTSAS_OPT_PM) {
+		(void) pm_busy_component(mpt->m_dip, 0);
+		if (mpt->m_power_level != PM_LEVEL_D0) {
+			mutex_exit(&mpt->m_mutex);
+			if (pm_raise_power(mpt->m_dip, 0, PM_LEVEL_D0) !=
+			    DDI_SUCCESS) {
+				mptsas_log(mpt, CE_WARN,
+				    "mptsas%d: mptsas_ioctl: Raise power "
+				    "request failed.", mpt->m_instance);
+				(void) pm_idle_component(mpt->m_dip, 0);
+				return (ENXIO);
+			}
+		} else {
+			mutex_exit(&mpt->m_mutex);
+		}
+	} else {
+		mutex_exit(&mpt->m_mutex);
+	}
+
+	switch (cmd) {
+		case MPTIOCTL_UPDATE_FLASH:
+			if (ddi_copyin((void *)data, &flashdata,
+				sizeof (struct mptsas_update_flash), mode)) {
+				status = EFAULT;
+				break;
+			}
+
+			mutex_enter(&mpt->m_mutex);
+			if (mptsas_update_flash(mpt,
+			    (caddr_t)(long)flashdata.PtrBuffer,
+			    flashdata.ImageSize, flashdata.ImageType, mode)) {
+				status = EFAULT;
+			}
+
+			/*
+			 * Reset the chip to start using the new
+			 * firmware.  Reset if failed also.
+			 */
+			if (mptsas_restart_ioc(mpt) == DDI_FAILURE) {
+				status = EFAULT;
+			}
+			mutex_exit(&mpt->m_mutex);
+			break;
+		case MPTIOCTL_PASS_THRU:
+			/*
+			 * The user has requested to pass through a command to
+			 * be executed by the MPT firmware.  Call our routine
+			 * which does this.  Only allow one passthru IOCTL at
+			 * one time.
+			 */
+			if (ddi_copyin((void *)data, &passthru_data,
+			    sizeof (mptsas_pass_thru_t), mode)) {
+				status = EFAULT;
+				break;
+			}
+			mutex_enter(&mpt->m_mutex);
+			if (mpt->m_passthru_in_progress)
+				return (EBUSY);
+			mpt->m_passthru_in_progress = 1;
+			status = mptsas_pass_thru(mpt, &passthru_data, mode);
+			mpt->m_passthru_in_progress = 0;
+			mutex_exit(&mpt->m_mutex);
+
+			break;
+		case MPTIOCTL_GET_ADAPTER_DATA:
+			/*
+			 * The user has requested to read adapter data.  Call
+			 * our routine which does this.
+			 */
+			bzero(&adapter_data, sizeof (mptsas_adapter_data_t));
+			if (ddi_copyin((void *)data, (void *)&adapter_data,
+			    sizeof (mptsas_adapter_data_t), mode)) {
+				status = EFAULT;
+				break;
+			}
+			if (adapter_data.StructureLength >=
+			    sizeof (mptsas_adapter_data_t)) {
+				adapter_data.StructureLength = (uint32_t)
+				    sizeof (mptsas_adapter_data_t);
+				copylen = sizeof (mptsas_adapter_data_t);
+				mutex_enter(&mpt->m_mutex);
+				mptsas_read_adapter_data(mpt, &adapter_data);
+				mutex_exit(&mpt->m_mutex);
+			} else {
+				adapter_data.StructureLength = (uint32_t)
+				    sizeof (mptsas_adapter_data_t);
+				copylen = sizeof (adapter_data.StructureLength);
+				*rval = MPTIOCTL_STATUS_LEN_TOO_SHORT;
+			}
+			if (ddi_copyout((void *)(&adapter_data), (void *)data,
+			    copylen, mode) != 0) {
+				status = EFAULT;
+			}
+			break;
+		case MPTIOCTL_GET_PCI_INFO:
+			/*
+			 * The user has requested to read pci info.  Call
+			 * our routine which does this.
+			 */
+			bzero(&pci_info, sizeof (mptsas_pci_info_t));
+			mutex_enter(&mpt->m_mutex);
+			mptsas_read_pci_info(mpt, &pci_info);
+			mutex_exit(&mpt->m_mutex);
+			if (ddi_copyout((void *)(&pci_info), (void *)data,
+			    sizeof (mptsas_pci_info_t), mode) != 0) {
+				status = EFAULT;
+			}
+			break;
+		case MPTIOCTL_RESET_ADAPTER:
+			mutex_enter(&mpt->m_mutex);
+			if ((mptsas_restart_ioc(mpt)) == DDI_FAILURE) {
+				mptsas_log(mpt, CE_WARN, "reset adapter IOCTL "
+				    "failed");
+				status = EFAULT;
+			}
+			mutex_exit(&mpt->m_mutex);
+			break;
+		case MPTIOCTL_EVENT_QUERY:
+			/*
+			 * The user has done an event query. Call our routine
+			 * which does this.
+			 */
+			status = mptsas_event_query(mpt,
+			    (mptsas_event_query_t *)data, mode, rval);
+			break;
+		case MPTIOCTL_EVENT_ENABLE:
+			/*
+			 * The user has done an event enable. Call our routine
+			 * which does this.
+			 */
+			status = mptsas_event_enable(mpt,
+			    (mptsas_event_enable_t *)data, mode, rval);
+			break;
+		case MPTIOCTL_EVENT_REPORT:
+			/*
+			 * The user has done an event report. Call our routine
+			 * which does this.
+			 */
+			status = mptsas_event_report(mpt,
+			    (mptsas_event_report_t *)data, mode, rval);
+			break;
+		default:
+			status = scsi_hba_ioctl(dev, cmd, data, mode, credp,
+			    rval);
+			break;
+	}
+
+	/*
+	 * Report idle status to pm after grace period because
+	 * multiple ioctls may be queued and raising power
+	 * for every ioctl is time consuming.  If a timeout is
+	 * pending for the previous ioctl, cancel the timeout and
+	 * report idle status to pm because calls to pm_busy_component(9F)
+	 * are stacked.
+	 */
+	mutex_enter(&mpt->m_mutex);
+	if (mpt->m_options & MPTSAS_OPT_PM) {
+		if (mpt->m_pm_timeid != 0) {
+			timeout_id_t tid = mpt->m_pm_timeid;
+			mpt->m_pm_timeid = 0;
+			mutex_exit(&mpt->m_mutex);
+			(void) untimeout(tid);
+			/*
+			 * Report idle status for previous ioctl since
+			 * calls to pm_busy_component(9F) are stacked.
+			 */
+			(void) pm_idle_component(mpt->m_dip, 0);
+			mutex_enter(&mpt->m_mutex);
+		}
+		mpt->m_pm_timeid = timeout(mptsas_idle_pm, mpt,
+		    drv_usectohz((clock_t)mpt->m_pm_idle_delay * 1000000));
+	}
+	mutex_exit(&mpt->m_mutex);
+
+	return (status);
+}
+
+int
+mptsas_restart_ioc(mptsas_t *mpt) {
+	int		rval = DDI_SUCCESS;
+	mptsas_target_t	*ptgt = NULL;
+
+	ASSERT(mutex_owned(&mpt->m_mutex));
+
+	/*
+	 * Set all throttles to HOLD
+	 */
+	ptgt = (mptsas_target_t *)mptsas_hash_traverse(&mpt->m_active->m_tgttbl,
+	    MPTSAS_HASH_FIRST);
+	while (ptgt != NULL) {
+		mptsas_set_throttle(mpt, ptgt, HOLD_THROTTLE);
+
+		ptgt = (mptsas_target_t *)mptsas_hash_traverse(
+		    &mpt->m_active->m_tgttbl, MPTSAS_HASH_NEXT);
+	}
+
+	/*
+	 * Disable interrupts
+	 */
+	MPTSAS_DISABLE_INTR(mpt);
+
+	/*
+	 * Abort all commands: outstanding commands, commands in waitq and
+	 * tx_waitq.
+	 */
+	mptsas_flush_hba(mpt);
+
+	/*
+	 * Reinitialize the chip.
+	 */
+	if (mptsas_init_chip(mpt, FALSE) == DDI_FAILURE) {
+		rval = DDI_FAILURE;
+	}
+
+	/*
+	 * Enable interrupts again
+	 */
+	MPTSAS_ENABLE_INTR(mpt);
+
+	/*
+	 * If mptsas_init_chip was successful, update the driver data.
+	 */
+	if (rval == DDI_SUCCESS) {
+		mptsas_update_driver_data(mpt);
+	}
+
+	/*
+	 * Reset the throttles
+	 */
+	ptgt = (mptsas_target_t *)mptsas_hash_traverse(&mpt->m_active->m_tgttbl,
+	    MPTSAS_HASH_FIRST);
+	while (ptgt != NULL) {
+		mptsas_set_throttle(mpt, ptgt, MAX_THROTTLE);
+
+		ptgt = (mptsas_target_t *)mptsas_hash_traverse(
+		    &mpt->m_active->m_tgttbl, MPTSAS_HASH_NEXT);
+	}
+
+	mptsas_doneq_empty(mpt);
+
+	if (rval != DDI_SUCCESS) {
+		mptsas_fm_ereport(mpt, DDI_FM_DEVICE_NO_RESPONSE);
+		ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_LOST);
+	}
+	return (rval);
+}
+
+int
+mptsas_init_chip(mptsas_t *mpt, int first_time)
+{
+	ddi_dma_cookie_t	cookie;
+	uint32_t		i;
+
+	if (first_time == FALSE) {
+		/*
+		 * Setup configuration space
+		 */
+		if (mptsas_config_space_init(mpt) == FALSE) {
+			mptsas_log(mpt, CE_WARN, "mptsas_config_space_init "
+			    "failed!");
+			goto fail;
+		}
+	}
+
+	/*
+	 * Check to see if the firmware image is valid
+	 */
+	if (ddi_get32(mpt->m_datap, &mpt->m_reg->HostDiagnostic) &
+	    MPI2_DIAG_FLASH_BAD_SIG) {
+		mptsas_log(mpt, CE_WARN, "mptsas bad flash signature!");
+		goto fail;
+	}
+
+	/*
+	 * Reset the chip
+	 */
+	if (mptsas_ioc_reset(mpt) == MPTSAS_RESET_FAIL) {
+		mptsas_log(mpt, CE_WARN, "hard reset failed!");
+		return (DDI_FAILURE);
+	}
+	/*
+	 * Do some initilization only needed during attach
+	 */
+	if (first_time) {
+		/*
+		 * Get ioc facts from adapter
+		 */
+		if (mptsas_ioc_get_facts(mpt) == DDI_FAILURE) {
+			mptsas_log(mpt, CE_WARN, "mptsas_ioc_get_facts "
+			    "failed");
+			goto fail;
+		}
+
+		/*
+		 * Allocate request message frames
+		 */
+		if (mptsas_alloc_request_frames(mpt) == DDI_FAILURE) {
+			mptsas_log(mpt, CE_WARN, "mptsas_alloc_request_frames "
+			    "failed");
+			goto fail;
+		}
+		/*
+		 * Allocate reply free queue
+		 */
+		if (mptsas_alloc_free_queue(mpt) == DDI_FAILURE) {
+			mptsas_log(mpt, CE_WARN, "mptsas_alloc_free_queue "
+			    "failed!");
+			goto fail;
+		}
+		/*
+		 * Allocate reply descriptor post queue
+		 */
+		if (mptsas_alloc_post_queue(mpt) == DDI_FAILURE) {
+			mptsas_log(mpt, CE_WARN, "mptsas_alloc_post_queue "
+			    "failed!");
+			goto fail;
+		}
+		/*
+		 * Allocate reply message frames
+		 */
+		if (mptsas_alloc_reply_frames(mpt) == DDI_FAILURE) {
+			mptsas_log(mpt, CE_WARN, "mptsas_alloc_reply_frames "
+			    "failed!");
+			goto fail;
+		}
+	}
+
+	/*
+	 * Re-Initialize ioc to operational state
+	 */
+	if (mptsas_ioc_init(mpt) == DDI_FAILURE) {
+		mptsas_log(mpt, CE_WARN, "mptsas_ioc_init failed");
+		goto fail;
+	}
+
+	mpt->m_replyh_args = kmem_zalloc(sizeof (m_replyh_arg_t) *
+	    mpt->m_max_replies, KM_SLEEP);
+
+	/*
+	 * Initialize reply post index and request index.  Reply free index is
+	 * initialized after the next loop.  m_tags must only be initialized if
+	 * this is not the first time because m_active is not allocated if this
+	 * is the first time.
+	 */
+	mpt->m_post_index = 0;
+	if (!first_time) {
+		mpt->m_active->m_tags = 1;
+	}
+
+	/*
+	 * Initialize the Reply Free Queue with the physical addresses of our
+	 * reply frames.
+	 */
+	cookie.dmac_address = mpt->m_reply_frame_dma_addr;
+	for (i = 0; i < mpt->m_free_queue_depth - 1; i++) {
+		ddi_put32(mpt->m_acc_free_queue_hdl,
+		    &((uint32_t *)(void *)mpt->m_free_queue)[i],
+		    cookie.dmac_address);
+		cookie.dmac_address += mpt->m_reply_frame_size;
+	}
+	(void) ddi_dma_sync(mpt->m_dma_free_queue_hdl, 0, 0,
+	    DDI_DMA_SYNC_FORDEV);
+
+	/*
+	 * Initialize the reply free index to one past the last frame on the
+	 * queue.  This will signify that the queue is empty to start with.
+	 */
+	mpt->m_free_index = i;
+	ddi_put32(mpt->m_datap, &mpt->m_reg->ReplyFreeHostIndex, i);
+
+	/*
+	 * Initialize the reply post queue to 0xFFFFFFFF,0xFFFFFFFF's.
+	 */
+	for (i = 0; i < mpt->m_post_queue_depth; i++) {
+		ddi_put64(mpt->m_acc_post_queue_hdl,
+		    &((uint64_t *)(void *)mpt->m_post_queue)[i],
+		    0xFFFFFFFFFFFFFFFF);
+	}
+	(void) ddi_dma_sync(mpt->m_dma_post_queue_hdl, 0, 0,
+	    DDI_DMA_SYNC_FORDEV);
+
+	/*
+	 * Enable ports
+	 */
+	if (mptsas_ioc_enable_port(mpt) == DDI_FAILURE) {
+		mptsas_log(mpt, CE_WARN, "mptsas_ioc_enable_port failed");
+		goto fail;
+	}
+
+	/*
+	 * First, make sure the HBA is set in "initiator" mode.  Once that
+	 * is complete, get the base WWID.
+	 */
+
+	if (first_time) {
+		if (mptsas_set_initiator_mode(mpt)) {
+			mptsas_log(mpt, CE_WARN, "mptsas_set_initiator_mode "
+			    "failed!");
+			goto fail;
+		}
+
+		if (mptsas_get_manufacture_page5(mpt) == DDI_FAILURE) {
+			mptsas_log(mpt, CE_WARN,
+			    "mptsas_get_manufacture_page5 failed!");
+			goto fail;
+		}
+	}
+
+	/*
+	 * enable events
+	 */
+	if (first_time != TRUE) {
+		if (mptsas_ioc_enable_event_notification(mpt)) {
+			goto fail;
+		}
+	}
+
+	/*
+	 * We need checks in attach and these.
+	 * chip_init is called in mult. places
+	 */
+
+	if ((mptsas_check_dma_handle(mpt->m_dma_req_frame_hdl) !=
+	    DDI_SUCCESS) ||
+	    (mptsas_check_dma_handle(mpt->m_dma_reply_frame_hdl) !=
+	    DDI_SUCCESS) ||
+	    (mptsas_check_dma_handle(mpt->m_dma_free_queue_hdl) !=
+	    DDI_SUCCESS) ||
+	    (mptsas_check_dma_handle(mpt->m_dma_post_queue_hdl) !=
+	    DDI_SUCCESS) ||
+	    (mptsas_check_dma_handle(mpt->m_hshk_dma_hdl) !=
+	    DDI_SUCCESS)) {
+		ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
+		goto fail;
+	}
+
+	/* Check all acc handles */
+	if ((mptsas_check_acc_handle(mpt->m_datap) != DDI_SUCCESS) ||
+	    (mptsas_check_acc_handle(mpt->m_acc_req_frame_hdl) !=
+	    DDI_SUCCESS) ||
+	    (mptsas_check_acc_handle(mpt->m_acc_reply_frame_hdl) !=
+	    DDI_SUCCESS) ||
+	    (mptsas_check_acc_handle(mpt->m_acc_free_queue_hdl) !=
+	    DDI_SUCCESS) ||
+	    (mptsas_check_acc_handle(mpt->m_acc_post_queue_hdl) !=
+	    DDI_SUCCESS) ||
+	    (mptsas_check_acc_handle(mpt->m_hshk_acc_hdl) !=
+	    DDI_SUCCESS) ||
+	    (mptsas_check_acc_handle(mpt->m_config_handle) !=
+	    DDI_SUCCESS)) {
+		ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
+		goto fail;
+	}
+
+	return (DDI_SUCCESS);
+
+fail:
+	return (DDI_FAILURE);
+}
+
+static int
+mptsas_init_pm(mptsas_t *mpt)
+{
+	char		pmc_name[16];
+	char		*pmc[] = {
+				NULL,
+				"0=Off (PCI D3 State)",
+				"3=On (PCI D0 State)",
+				NULL
+			};
+	uint16_t	pmcsr_stat;
+
+	/*
+	 * If power management is supported by this chip, create
+	 * pm-components property for the power management framework
+	 */
+	(void) sprintf(pmc_name, "NAME=mptsas%d", mpt->m_instance);
+	pmc[0] = pmc_name;
+	if (ddi_prop_update_string_array(DDI_DEV_T_NONE, mpt->m_dip,
+	    "pm-components", pmc, 3) != DDI_PROP_SUCCESS) {
+		mpt->m_options &= ~MPTSAS_OPT_PM;
+		mptsas_log(mpt, CE_WARN,
+		    "mptsas%d: pm-component property creation failed.",
+		    mpt->m_instance);
+		return (DDI_FAILURE);
+	}
+
+	/*
+	 * Power on device.
+	 */
+	(void) pm_busy_component(mpt->m_dip, 0);
+	pmcsr_stat = pci_config_get16(mpt->m_config_handle,
+	    mpt->m_pmcsr_offset);
+	if ((pmcsr_stat & PCI_PMCSR_STATE_MASK) != PCI_PMCSR_D0) {
+		mptsas_log(mpt, CE_WARN, "mptsas%d: Power up the device",
+		    mpt->m_instance);
+		pci_config_put16(mpt->m_config_handle, mpt->m_pmcsr_offset,
+		    PCI_PMCSR_D0);
+	}
+	if (pm_power_has_changed(mpt->m_dip, 0, PM_LEVEL_D0) != DDI_SUCCESS) {
+		mptsas_log(mpt, CE_WARN, "pm_power_has_changed failed");
+		return (DDI_FAILURE);
+	}
+	mpt->m_power_level = PM_LEVEL_D0;
+	/*
+	 * Set pm idle delay.
+	 */
+	mpt->m_pm_idle_delay = ddi_prop_get_int(DDI_DEV_T_ANY,
+	    mpt->m_dip, 0, "mptsas-pm-idle-delay", MPTSAS_PM_IDLE_TIMEOUT);
+
+	return (DDI_SUCCESS);
+}
+
+/*
+ * mptsas_add_intrs:
+ *
+ * Register FIXED or MSI interrupts.
+ */
+static int
+mptsas_add_intrs(mptsas_t *mpt, int intr_type)
+{
+	dev_info_t	*dip = mpt->m_dip;
+	int		avail, actual, count = 0;
+	int		i, flag, ret;
+
+	NDBG6(("mptsas_add_intrs:interrupt type 0x%x", intr_type));
+
+	/* Get number of interrupts */
+	ret = ddi_intr_get_nintrs(dip, intr_type, &count);
+	if ((ret != DDI_SUCCESS) || (count <= 0)) {
+		mptsas_log(mpt, CE_WARN, "ddi_intr_get_nintrs() failed, "
+		    "ret %d count %d\n", ret, count);
+
+		return (DDI_FAILURE);
+	}
+
+	/* Get number of available interrupts */
+	ret = ddi_intr_get_navail(dip, intr_type, &avail);
+	if ((ret != DDI_SUCCESS) || (avail == 0)) {
+		mptsas_log(mpt, CE_WARN, "ddi_intr_get_navail() failed, "
+		    "ret %d avail %d\n", ret, avail);
+
+		return (DDI_FAILURE);
+	}
+
+	if (avail < count) {
+		mptsas_log(mpt, CE_NOTE, "ddi_intr_get_nvail returned %d, "
+		    "navail() returned %d", count, avail);
+	}
+
+	/* Mpt only have one interrupt routine */
+	if ((intr_type == DDI_INTR_TYPE_MSI) && (count > 1)) {
+		count = 1;
+	}
+
+	/* Allocate an array of interrupt handles */
+	mpt->m_intr_size = count * sizeof (ddi_intr_handle_t);
+	mpt->m_htable = kmem_alloc(mpt->m_intr_size, KM_SLEEP);
+
+	flag = DDI_INTR_ALLOC_NORMAL;
+
+	/* call ddi_intr_alloc() */
+	ret = ddi_intr_alloc(dip, mpt->m_htable, intr_type, 0,
+	    count, &actual, flag);
+
+	if ((ret != DDI_SUCCESS) || (actual == 0)) {
+		mptsas_log(mpt, CE_WARN, "ddi_intr_alloc() failed, ret %d\n",
+		    ret);
+		kmem_free(mpt->m_htable, mpt->m_intr_size);
+		return (DDI_FAILURE);
+	}
+
+	/* use interrupt count returned or abort? */
+	if (actual < count) {
+		mptsas_log(mpt, CE_NOTE, "Requested: %d, Received: %d\n",
+		    count, actual);
+	}
+
+	mpt->m_intr_cnt = actual;
+
+	/*
+	 * Get priority for first msi, assume remaining are all the same
+	 */
+	if ((ret = ddi_intr_get_pri(mpt->m_htable[0],
+	    &mpt->m_intr_pri)) != DDI_SUCCESS) {
+		mptsas_log(mpt, CE_WARN, "ddi_intr_get_pri() failed %d\n", ret);
+
+		/* Free already allocated intr */
+		for (i = 0; i < actual; i++) {
+			(void) ddi_intr_free(mpt->m_htable[i]);
+		}
+
+		kmem_free(mpt->m_htable, mpt->m_intr_size);
+		return (DDI_FAILURE);
+	}
+
+	/* Test for high level mutex */
+	if (mpt->m_intr_pri >= ddi_intr_get_hilevel_pri()) {
+		mptsas_log(mpt, CE_WARN, "mptsas_add_intrs: "
+		    "Hi level interrupt not supported\n");
+
+		/* Free already allocated intr */
+		for (i = 0; i < actual; i++) {
+			(void) ddi_intr_free(mpt->m_htable[i]);
+		}
+
+		kmem_free(mpt->m_htable, mpt->m_intr_size);
+		return (DDI_FAILURE);
+	}
+
+	/* Call ddi_intr_add_handler() */
+	for (i = 0; i < actual; i++) {
+		if ((ret = ddi_intr_add_handler(mpt->m_htable[i], mptsas_intr,
+		    (caddr_t)mpt, (caddr_t)(uintptr_t)i)) != DDI_SUCCESS) {
+			mptsas_log(mpt, CE_WARN, "ddi_intr_add_handler() "
+			    "failed %d\n", ret);
+
+			/* Free already allocated intr */
+			for (i = 0; i < actual; i++) {
+				(void) ddi_intr_free(mpt->m_htable[i]);
+			}
+
+			kmem_free(mpt->m_htable, mpt->m_intr_size);
+			return (DDI_FAILURE);
+		}
+	}
+
+	if ((ret = ddi_intr_get_cap(mpt->m_htable[0], &mpt->m_intr_cap))
+	    != DDI_SUCCESS) {
+		mptsas_log(mpt, CE_WARN, "ddi_intr_get_cap() failed %d\n", ret);
+
+		/* Free already allocated intr */
+		for (i = 0; i < actual; i++) {
+			(void) ddi_intr_free(mpt->m_htable[i]);
+		}
+
+		kmem_free(mpt->m_htable, mpt->m_intr_size);
+		return (DDI_FAILURE);
+	}
+
+	return (DDI_SUCCESS);
+}
+
+/*
+ * mptsas_rem_intrs:
+ *
+ * Unregister FIXED or MSI interrupts
+ */
+static void
+mptsas_rem_intrs(mptsas_t *mpt)
+{
+	int	i;
+
+	NDBG6(("mptsas_rem_intrs"));
+
+	/* Disable all interrupts */
+	if (mpt->m_intr_cap & DDI_INTR_FLAG_BLOCK) {
+		/* Call ddi_intr_block_disable() */
+		(void) ddi_intr_block_disable(mpt->m_htable, mpt->m_intr_cnt);
+	} else {
+		for (i = 0; i < mpt->m_intr_cnt; i++) {
+			(void) ddi_intr_disable(mpt->m_htable[i]);
+		}
+	}
+
+	/* Call ddi_intr_remove_handler() */
+	for (i = 0; i < mpt->m_intr_cnt; i++) {
+		(void) ddi_intr_remove_handler(mpt->m_htable[i]);
+		(void) ddi_intr_free(mpt->m_htable[i]);
+	}
+
+	kmem_free(mpt->m_htable, mpt->m_intr_size);
+}
+
+/*
+ * The IO fault service error handling callback function
+ */
+/*ARGSUSED*/
+static int
+mptsas_fm_error_cb(dev_info_t *dip, ddi_fm_error_t *err, const void *impl_data)
+{
+	/*
+	 * as the driver can always deal with an error in any dma or
+	 * access handle, we can just return the fme_status value.
+	 */
+	pci_ereport_post(dip, err, NULL);
+	return (err->fme_status);
+}
+
+/*
+ * mptsas_fm_init - initialize fma capabilities and register with IO
+ *               fault services.
+ */
+static void
+mptsas_fm_init(mptsas_t *mpt)
+{
+	/*
+	 * Need to change iblock to priority for new MSI intr
+	 */
+	ddi_iblock_cookie_t	fm_ibc;
+
+	/* Only register with IO Fault Services if we have some capability */
+	if (mpt->m_fm_capabilities) {
+		/* Adjust access and dma attributes for FMA */
+		mpt->m_dev_acc_attr.devacc_attr_access |= DDI_FLAGERR_ACC;
+		mpt->m_msg_dma_attr.dma_attr_flags |= DDI_DMA_FLAGERR;
+		mpt->m_io_dma_attr.dma_attr_flags |= DDI_DMA_FLAGERR;
+
+		/*
+		 * Register capabilities with IO Fault Services.
+		 * mpt->m_fm_capabilities will be updated to indicate
+		 * capabilities actually supported (not requested.)
+		 */
+		ddi_fm_init(mpt->m_dip, &mpt->m_fm_capabilities, &fm_ibc);
+
+		/*
+		 * Initialize pci ereport capabilities if ereport
+		 * capable (should always be.)
+		 */
+		if (DDI_FM_EREPORT_CAP(mpt->m_fm_capabilities) ||
+		    DDI_FM_ERRCB_CAP(mpt->m_fm_capabilities)) {
+			pci_ereport_setup(mpt->m_dip);
+		}
+
+		/*
+		 * Register error callback if error callback capable.
+		 */
+		if (DDI_FM_ERRCB_CAP(mpt->m_fm_capabilities)) {
+			ddi_fm_handler_register(mpt->m_dip,
+			    mptsas_fm_error_cb, (void *) mpt);
+		}
+	}
+}
+
+/*
+ * mptsas_fm_fini - Releases fma capabilities and un-registers with IO
+ *               fault services.
+ *
+ */
+static void
+mptsas_fm_fini(mptsas_t *mpt)
+{
+	/* Only unregister FMA capabilities if registered */
+	if (mpt->m_fm_capabilities) {
+
+		/*
+		 * Un-register error callback if error callback capable.
+		 */
+
+		if (DDI_FM_ERRCB_CAP(mpt->m_fm_capabilities)) {
+			ddi_fm_handler_unregister(mpt->m_dip);
+		}
+
+		/*
+		 * Release any resources allocated by pci_ereport_setup()
+		 */
+
+		if (DDI_FM_EREPORT_CAP(mpt->m_fm_capabilities) ||
+		    DDI_FM_ERRCB_CAP(mpt->m_fm_capabilities)) {
+			pci_ereport_teardown(mpt->m_dip);
+		}
+
+		/* Unregister from IO Fault Services */
+		ddi_fm_fini(mpt->m_dip);
+
+		/* Adjust access and dma attributes for FMA */
+		mpt->m_dev_acc_attr.devacc_attr_access &= ~DDI_FLAGERR_ACC;
+		mpt->m_msg_dma_attr.dma_attr_flags &= ~DDI_DMA_FLAGERR;
+		mpt->m_io_dma_attr.dma_attr_flags &= ~DDI_DMA_FLAGERR;
+
+	}
+}
+
+int
+mptsas_check_acc_handle(ddi_acc_handle_t handle)
+{
+	ddi_fm_error_t	de;
+
+	if (handle == NULL)
+		return (DDI_FAILURE);
+	ddi_fm_acc_err_get(handle, &de, DDI_FME_VER0);
+	return (de.fme_status);
+}
+
+int
+mptsas_check_dma_handle(ddi_dma_handle_t handle)
+{
+	ddi_fm_error_t	de;
+
+	if (handle == NULL)
+		return (DDI_FAILURE);
+	ddi_fm_dma_err_get(handle, &de, DDI_FME_VER0);
+	return (de.fme_status);
+}
+
+void
+mptsas_fm_ereport(mptsas_t *mpt, char *detail)
+{
+	uint64_t	ena;
+	char		buf[FM_MAX_CLASS];
+
+	(void) snprintf(buf, FM_MAX_CLASS, "%s.%s", DDI_FM_DEVICE, detail);
+	ena = fm_ena_generate(0, FM_ENA_FMT1);
+	if (DDI_FM_EREPORT_CAP(mpt->m_fm_capabilities)) {
+		ddi_fm_ereport_post(mpt->m_dip, buf, ena, DDI_NOSLEEP,
+		    FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERS0, NULL);
+	}
+}
+
+static int
+mptsas_get_target_device_info(mptsas_t *mpt, uint32_t page_address,
+    uint16_t *dev_handle, mptsas_target_t **pptgt)
+{
+	int		rval;
+	uint32_t	dev_info;
+	uint64_t	sas_wwn;
+	uint8_t		physport, phymask;
+	uint8_t		phynum, config, disk;
+	mptsas_slots_t	*slots = mpt->m_active;
+	uint64_t		devicename;
+	mptsas_target_t		*tmp_tgt = NULL;
+
+	ASSERT(*pptgt == NULL);
+
+	rval = mptsas_get_sas_device_page0(mpt, page_address, dev_handle,
+	    &sas_wwn, &dev_info, &physport, &phynum);
+	if (rval != DDI_SUCCESS) {
+		rval = DEV_INFO_FAIL_PAGE0;
+		return (rval);
+	}
+
+	if ((dev_info & (MPI2_SAS_DEVICE_INFO_SSP_TARGET |
+	    MPI2_SAS_DEVICE_INFO_SATA_DEVICE |
+	    MPI2_SAS_DEVICE_INFO_ATAPI_DEVICE)) == NULL) {
+		rval = DEV_INFO_WRONG_DEVICE_TYPE;
+		return (rval);
+	}
+
+	/*
+	 * Get SATA Device Name from SAS device page0 for
+	 * sata device, if device name doesn't exist, set m_sas_wwn to
+	 * 0 for direct attached SATA. For the device behind the expander
+	 * we still can use STP address assigned by expander.
+	 */
+	if (dev_info & (MPI2_SAS_DEVICE_INFO_SATA_DEVICE |
+	    MPI2_SAS_DEVICE_INFO_ATAPI_DEVICE)) {
+		mutex_exit(&mpt->m_mutex);
+		/* alloc a tmp_tgt to send the cmd */
+		tmp_tgt = kmem_zalloc(sizeof (struct mptsas_target),
+		    KM_SLEEP);
+		tmp_tgt->m_devhdl = *dev_handle;
+		tmp_tgt->m_deviceinfo = dev_info;
+		tmp_tgt->m_qfull_retries = QFULL_RETRIES;
+		tmp_tgt->m_qfull_retry_interval =
+		    drv_usectohz(QFULL_RETRY_INTERVAL * 1000);
+		tmp_tgt->m_t_throttle = MAX_THROTTLE;
+		devicename = mptsas_get_sata_guid(mpt, tmp_tgt, 0);
+		kmem_free(tmp_tgt, sizeof (struct mptsas_target));
+		mutex_enter(&mpt->m_mutex);
+		if (devicename != 0 && (((devicename >> 56) & 0xf0) == 0x50)) {
+			sas_wwn = devicename;
+		} else if (dev_info & MPI2_SAS_DEVICE_INFO_DIRECT_ATTACH) {
+			sas_wwn = 0;
+		}
+	}
+
+	/*
+	 * Check if the dev handle is for a Phys Disk. If so, set return value
+	 * and exit.  Don't add Phys Disks to hash.
+	 */
+	for (config = 0; config < slots->m_num_raid_configs; config++) {
+		for (disk = 0; disk < MPTSAS_MAX_DISKS_IN_CONFIG; disk++) {
+			if (*dev_handle == slots->m_raidconfig[config].
+			    m_physdisk_devhdl[disk]) {
+				rval = DEV_INFO_PHYS_DISK;
+				return (rval);
+			}
+		}
+	}
+
+	phymask = mptsas_physport_to_phymask(mpt, physport);
+	*pptgt = mptsas_tgt_alloc(&slots->m_tgttbl, *dev_handle, sas_wwn,
+	    dev_info, phymask, phynum);
+	if (*pptgt == NULL) {
+		mptsas_log(mpt, CE_WARN, "Failed to allocated target"
+		    "structure!");
+		rval = DEV_INFO_FAIL_ALLOC;
+		return (rval);
+	}
+	return (DEV_INFO_SUCCESS);
+}
+
+uint64_t
+mptsas_get_sata_guid(mptsas_t *mpt, mptsas_target_t *ptgt, int lun)
+{
+	uint64_t	sata_guid = 0, *pwwn = NULL;
+	int		target = ptgt->m_devhdl;
+	uchar_t		*inq83 = NULL;
+	int		inq83_len = 0xFF;
+	uchar_t		*dblk = NULL;
+	int		inq83_retry = 3;
+	int		rval = DDI_FAILURE;
+
+	inq83	= kmem_zalloc(inq83_len, KM_SLEEP);
+
+inq83_retry:
+	rval = mptsas_inquiry(mpt, ptgt, lun, 0x83, inq83,
+	    inq83_len, NULL, 1);
+	if (rval != DDI_SUCCESS) {
+		mptsas_log(mpt, CE_WARN, "!mptsas request inquiry page "
+		    "0x83 for target:%x, lun:%x failed!", target, lun);
+		goto out;
+	}
+	/* According to SAT2, the first descriptor is logic unit name */
+	dblk = &inq83[4];
+	if ((dblk[1] & 0x30) != 0) {
+		mptsas_log(mpt, CE_WARN, "!Descriptor is not lun associated.");
+		goto out;
+	}
+	pwwn = (uint64_t *)(void *)(&dblk[4]);
+	if ((dblk[4] & 0xf0) == 0x50) {
+		sata_guid = BE_64(*pwwn);
+		goto out;
+	} else if (dblk[4] == 'A') {
+		NDBG20(("SATA drive has no NAA format GUID."));
+		goto out;
+	} else {
+		/* The data is not ready, wait and retry */
+		inq83_retry--;
+		if (inq83_retry <= 0) {
+			goto out;
+		}
+		NDBG20(("The GUID is not ready, retry..."));
+		delay(1 * drv_usectohz(1000000));
+		goto inq83_retry;
+	}
+out:
+	kmem_free(inq83, inq83_len);
+	return (sata_guid);
+}
+static int
+mptsas_inquiry(mptsas_t *mpt, mptsas_target_t *ptgt, int lun, uchar_t page,
+    unsigned char *buf, int len, int *reallen, uchar_t evpd)
+{
+	uchar_t			cdb[CDB_GROUP0];
+	struct scsi_address	ap;
+	struct buf		*data_bp = NULL;
+	int			resid = 0;
+	int			ret = DDI_FAILURE;
+
+	ASSERT(len <= 0xffff);
+
+	ap.a_target = MPTSAS_INVALID_DEVHDL;
+	ap.a_lun = (uchar_t)(lun);
+	ap.a_hba_tran = mpt->m_tran;
+
+	data_bp = scsi_alloc_consistent_buf(&ap,
+	    (struct buf *)NULL, len, B_READ, NULL_FUNC, NULL);
+	if (data_bp == NULL) {
+		return (ret);
+	}
+	bzero(cdb, CDB_GROUP0);
+	cdb[0] = SCMD_INQUIRY;
+	cdb[1] = evpd;
+	cdb[2] = page;
+	cdb[3] = (len & 0xff00) >> 8;
+	cdb[4] = (len & 0x00ff);
+	cdb[5] = 0;
+
+	ret = mptsas_send_scsi_cmd(mpt, &ap, ptgt, &cdb[0], CDB_GROUP0, data_bp,
+	    &resid);
+	if (ret == DDI_SUCCESS) {
+		if (reallen) {
+			*reallen = len - resid;
+		}
+		bcopy((caddr_t)data_bp->b_un.b_addr, buf, len);
+	}
+	if (data_bp) {
+		scsi_free_consistent_buf(data_bp);
+	}
+	return (ret);
+}
+
+static int
+mptsas_send_scsi_cmd(mptsas_t *mpt, struct scsi_address *ap,
+    mptsas_target_t *ptgt, uchar_t *cdb, int cdblen, struct buf *data_bp,
+    int *resid)
+{
+	struct scsi_pkt		*pktp = NULL;
+	scsi_hba_tran_t		*tran_clone = NULL;
+	mptsas_tgt_private_t	*tgt_private = NULL;
+	int			ret = DDI_FAILURE;
+
+	/*
+	 * scsi_hba_tran_t->tran_tgt_private is used to pass the address
+	 * information to scsi_init_pkt, allocate a scsi_hba_tran structure
+	 * to simulate the cmds from sd
+	 */
+	tran_clone = kmem_alloc(
+	    sizeof (scsi_hba_tran_t), KM_SLEEP);
+	if (tran_clone == NULL) {
+		goto out;
+	}
+	bcopy((caddr_t)mpt->m_tran,
+	    (caddr_t)tran_clone, sizeof (scsi_hba_tran_t));
+	tgt_private = kmem_alloc(
+	    sizeof (mptsas_tgt_private_t), KM_SLEEP);
+	if (tgt_private == NULL) {
+		goto out;
+	}
+	tgt_private->t_lun = ap->a_lun;
+	tgt_private->t_private = ptgt;
+	tran_clone->tran_tgt_private = tgt_private;
+	ap->a_hba_tran = tran_clone;
+
+	pktp = scsi_init_pkt(ap, (struct scsi_pkt *)NULL,
+	    data_bp, cdblen, sizeof (struct scsi_arq_status),
+	    0, PKT_CONSISTENT, NULL, NULL);
+	if (pktp == NULL) {
+		goto out;
+	}
+	bcopy(cdb, pktp->pkt_cdbp, cdblen);
+	pktp->pkt_flags = FLAG_NOPARITY;
+	if (scsi_poll(pktp) < 0) {
+		goto out;
+	}
+	if (((struct scsi_status *)pktp->pkt_scbp)->sts_chk) {
+		goto out;
+	}
+	if (resid != NULL) {
+		*resid = pktp->pkt_resid;
+	}
+
+	ret = DDI_SUCCESS;
+out:
+	if (pktp) {
+		scsi_destroy_pkt(pktp);
+	}
+	if (tran_clone) {
+		kmem_free(tran_clone, sizeof (scsi_hba_tran_t));
+	}
+	if (tgt_private) {
+		kmem_free(tgt_private, sizeof (mptsas_tgt_private_t));
+	}
+	return (ret);
+}
+static int
+mptsas_parse_address(char *name, uint64_t *wwid, uint8_t *phy, int *lun)
+{
+	char	*cp = NULL;
+	char	*ptr = NULL;
+	size_t	s = 0;
+	char	*wwid_str = NULL;
+	char	*lun_str = NULL;
+	long	lunnum;
+	long	phyid = -1;
+	int	rc = DDI_FAILURE;
+
+	ptr = name;
+	ASSERT(ptr[0] == 'w' || ptr[0] == 'p');
+	ptr++;
+	if ((cp = strchr(ptr, ',')) == NULL) {
+		return (DDI_FAILURE);
+	}
+
+	wwid_str = kmem_zalloc(SCSI_MAXNAMELEN, KM_SLEEP);
+	s = (uintptr_t)cp - (uintptr_t)ptr;
+
+	bcopy(ptr, wwid_str, s);
+	wwid_str[s] = '\0';
+
+	ptr = ++cp;
+
+	if ((cp = strchr(ptr, '\0')) == NULL) {
+		goto out;
+	}
+	lun_str =  kmem_zalloc(SCSI_MAXNAMELEN, KM_SLEEP);
+	s = (uintptr_t)cp - (uintptr_t)ptr;
+
+	bcopy(ptr, lun_str, s);
+	lun_str[s] = '\0';
+
+	if (name[0] == 'p') {
+		rc = ddi_strtol(wwid_str, NULL, 0x10, &phyid);
+	} else {
+		rc = scsi_wwnstr_to_wwn(wwid_str, wwid);
+	}
+	if (rc != DDI_SUCCESS)
+		goto out;
+
+	if (phyid != -1) {
+		ASSERT(phyid < 8);
+		*phy = (uint8_t)phyid;
+	}
+	rc = ddi_strtol(lun_str, NULL, 0x10, &lunnum);
+	if (rc != 0)
+		goto out;
+
+	*lun = (int)lunnum;
+	rc = DDI_SUCCESS;
+out:
+	if (wwid_str)
+		kmem_free(wwid_str, SCSI_MAXNAMELEN);
+	if (lun_str)
+		kmem_free(lun_str, SCSI_MAXNAMELEN);
+
+	return (rc);
+}
+
+/*
+ * mptsas_parse_smp_name() is to parse sas wwn string
+ * which format is "wWWN"
+ */
+static int
+mptsas_parse_smp_name(char *name, uint64_t *wwn)
+{
+	char	*ptr = name;
+
+	if (*ptr != 'w') {
+		return (DDI_FAILURE);
+	}
+
+	ptr++;
+	if (scsi_wwnstr_to_wwn(ptr, wwn)) {
+		return (DDI_FAILURE);
+	}
+	return (DDI_SUCCESS);
+}
+
+static int
+mptsas_bus_config(dev_info_t *pdip, uint_t flag,
+    ddi_bus_config_op_t op, void *arg, dev_info_t **childp)
+{
+	int		ret = NDI_FAILURE;
+	int		circ = 0;
+	int		circ1 = 0;
+	mptsas_t	*mpt;
+	char		*ptr = NULL;
+	char		*devnm = NULL;
+	uint64_t	wwid = 0;
+	uint8_t		phy = 0xFF;
+	int		lun = 0;
+	uint_t		mflags = flag;
+
+	if (scsi_hba_iport_unit_address(pdip) == 0) {
+		return (DDI_FAILURE);
+	}
+
+	mpt = DIP2MPT(pdip);
+	if (!mpt) {
+		return (DDI_FAILURE);
+	}
+
+	/*
+	 * Hold the nexus across the bus_config
+	 */
+	ndi_devi_enter(scsi_vhci_dip, &circ);
+	ndi_devi_enter(pdip, &circ1);
+	switch (op) {
+	case BUS_CONFIG_ONE:
+		/* parse wwid/target name out of name given */
+		if ((ptr = strchr((char *)arg, '@')) == NULL) {
+			ret = NDI_FAILURE;
+			break;
+		}
+		ptr++;
+		if (strncmp((char *)arg, "smp", 3) == 0) {
+			/*
+			 * This is a SMP target device
+			 */
+			ret = mptsas_parse_smp_name(ptr, &wwid);
+			if (ret != DDI_SUCCESS) {
+				ret = NDI_FAILURE;
+				break;
+			}
+			ret = mptsas_config_smp(pdip, wwid, childp);
+		} else if ((ptr[0] == 'w') || (ptr[0] == 'p')) {
+			/*
+			 * OBP could pass down a non-canonical form
+			 * bootpath without LUN part when LUN is 0.
+			 * So driver need adjust the string.
+			 */
+			if (strchr(ptr, ',') == NULL) {
+				devnm = kmem_zalloc(SCSI_MAXNAMELEN, KM_SLEEP);
+				(void) sprintf(devnm, "%s,0", (char *)arg);
+				ptr = strchr(devnm, '@');
+				ptr++;
+			}
+
+			/*
+			 * The device path is wWWID format and the device
+			 * is not SMP target device.
+			 */
+			ret = mptsas_parse_address(ptr, &wwid, &phy, &lun);
+			if (ret != DDI_SUCCESS) {
+				ret = NDI_FAILURE;
+				break;
+			}
+			if (ptr[0] == 'w') {
+				ret = mptsas_config_one_addr(pdip, wwid,
+				    lun, childp);
+			} else if (ptr[0] == 'p') {
+				ret = mptsas_config_one_phy(pdip, phy, lun,
+				    childp);
+			}
+		} else {
+			ret = NDI_FAILURE;
+			break;
+		}
+
+		/*
+		 * DDI group instructed us to use this flag.
+		 */
+		mflags |= NDI_MDI_FALLBACK;
+		break;
+	case BUS_CONFIG_DRIVER:
+	case BUS_CONFIG_ALL:
+		mptsas_config_all(pdip);
+		ret = NDI_SUCCESS;
+		break;
+	}
+
+	if (ret == NDI_SUCCESS) {
+		ret = ndi_busop_bus_config(pdip, mflags, op,
+		    (devnm == NULL) ? arg : devnm, childp, 0);
+	}
+
+	ndi_devi_exit(pdip, circ1);
+	ndi_devi_exit(scsi_vhci_dip, circ);
+	if (devnm != NULL)
+		kmem_free(devnm, SCSI_MAXNAMELEN);
+	return (ret);
+}
+
+static int
+mptsas_probe_lun(dev_info_t *pdip, int lun, dev_info_t **dip,
+    mptsas_target_t *ptgt)
+{
+	int			rval = DDI_FAILURE;
+	struct scsi_inquiry	*sd_inq = NULL;
+	mptsas_t		*mpt = DIP2MPT(pdip);
+
+	sd_inq = (struct scsi_inquiry *)kmem_alloc(SUN_INQSIZE, KM_SLEEP);
+
+	rval = mptsas_inquiry(mpt, ptgt, lun, 0, (uchar_t *)sd_inq,
+	    SUN_INQSIZE, 0, (uchar_t)0);
+
+	if ((rval == DDI_SUCCESS) && MPTSAS_VALID_LUN(sd_inq)) {
+		rval = mptsas_create_lun(pdip, sd_inq, dip, ptgt, lun);
+	} else {
+		rval = DDI_FAILURE;
+	}
+out:
+	kmem_free(sd_inq, SUN_INQSIZE);
+	return (rval);
+}
+
+static int
+mptsas_config_one_addr(dev_info_t *pdip, uint64_t sasaddr, int lun,
+    dev_info_t **lundip)
+{
+	int		rval;
+	mptsas_t		*mpt = DIP2MPT(pdip);
+	int		phymask;
+	mptsas_target_t	*ptgt = NULL;
+
+	/*
+	 * Get the physical port associated to the iport
+	 */
+	phymask = ddi_prop_get_int(DDI_DEV_T_ANY, pdip, 0,
+	    "phymask", 0);
+
+	ptgt = mptsas_wwid_to_ptgt(mpt, phymask, sasaddr);
+	if (ptgt == NULL) {
+		/*
+		 * didn't match any device by searching
+		 */
+		return (DDI_FAILURE);
+	}
+	/*
+	 * If the LUN already exists and the status is online,
+	 * we just return the pointer to dev_info_t directly.
+	 * For the mdi_pathinfo node, we'll handle it in
+	 * mptsas_create_virt_lun()
+	 * TODO should be also in mptsas_handle_dr
+	 */
+
+	*lundip = mptsas_find_child_addr(pdip, sasaddr, lun);
+	if (*lundip != NULL) {
+		/*
+		 * TODO Another senario is, we hotplug the same disk
+		 * on the same slot, the devhdl changed, is this
+		 * possible?
+		 * tgt_private->t_private != ptgt
+		 */
+		if (sasaddr != ptgt->m_sas_wwn) {
+			/*
+			 * The device has changed although the devhdl is the
+			 * same (Enclosure mapping mode, change drive on the
+			 * same slot)
+			 */
+			return (DDI_FAILURE);
+		}
+		return (DDI_SUCCESS);
+	}
+
+	if (phymask == 0) {
+		/*
+		 * Configure IR volume
+		 */
+		rval =  mptsas_config_raid(pdip, ptgt->m_devhdl, lundip);
+		return (rval);
+	}
+	rval = mptsas_probe_lun(pdip, lun, lundip, ptgt);
+
+	return (rval);
+}
+
+static int
+mptsas_config_one_phy(dev_info_t *pdip, uint8_t phy, int lun,
+    dev_info_t **lundip)
+{
+	int		rval;
+	mptsas_target_t	*ptgt = NULL;
+
+	ptgt = mptsas_phy_to_tgt(pdip, phy);
+	if (ptgt == NULL) {
+		/*
+		 * didn't match any device by searching
+		 */
+		return (DDI_FAILURE);
+	}
+
+	/*
+	 * If the LUN already exists and the status is online,
+	 * we just return the pointer to dev_info_t directly.
+	 * For the mdi_pathinfo node, we'll handle it in
+	 * mptsas_create_virt_lun().
+	 */
+
+	*lundip = mptsas_find_child_phy(pdip, phy);
+	if (*lundip != NULL) {
+		return (DDI_SUCCESS);
+	}
+
+	rval = mptsas_probe_lun(pdip, lun, lundip, ptgt);
+
+	return (rval);
+}
+
+static int
+mptsas_retrieve_lundata(int lun_cnt, uint8_t *buf, uint16_t *lun_num,
+    uint8_t *lun_addr_type)
+{
+	uint32_t	lun_idx = 0;
+
+	ASSERT(lun_num != NULL);
+	ASSERT(lun_addr_type != NULL);
+
+	lun_idx = (lun_cnt + 1) * MPTSAS_SCSI_REPORTLUNS_ADDRESS_SIZE;
+	/* determine report luns addressing type */
+	switch (buf[lun_idx] & MPTSAS_SCSI_REPORTLUNS_ADDRESS_MASK) {
+		/*
+		 * Vendors in the field have been found to be concatenating
+		 * bus/target/lun to equal the complete lun value instead
+		 * of switching to flat space addressing
+		 */
+		/* 00b - peripheral device addressing method */
+	case MPTSAS_SCSI_REPORTLUNS_ADDRESS_PERIPHERAL:
+		/* FALLTHRU */
+		/* 10b - logical unit addressing method */
+	case MPTSAS_SCSI_REPORTLUNS_ADDRESS_LOGICAL_UNIT:
+		/* FALLTHRU */
+		/* 01b - flat space addressing method */
+	case MPTSAS_SCSI_REPORTLUNS_ADDRESS_FLAT_SPACE:
+		/* byte0 bit0-5=msb lun byte1 bit0-7=lsb lun */
+		*lun_addr_type = (buf[lun_idx] &
+		    MPTSAS_SCSI_REPORTLUNS_ADDRESS_MASK) >> 6;
+		*lun_num = (buf[lun_idx] & 0x3F) << 8;
+		*lun_num |= buf[lun_idx + 1];
+		return (DDI_SUCCESS);
+	default:
+		return (DDI_FAILURE);
+	}
+}
+
+static int
+mptsas_config_luns(dev_info_t *pdip, mptsas_target_t *ptgt)
+{
+	struct buf		*repluns_bp = NULL;
+	struct scsi_address	ap;
+	uchar_t			cdb[CDB_GROUP5];
+	int			ret = DDI_FAILURE;
+	int			retry = 0;
+	int			lun_list_len = 0;
+	uint16_t		lun_num = 0;
+	uint8_t			lun_addr_type = 0;
+	uint32_t		lun_cnt = 0;
+	uint32_t		lun_total = 0;
+	dev_info_t		*cdip = NULL;
+	uint16_t		*saved_repluns = NULL;
+	char			*buffer = NULL;
+	int			buf_len = 128;
+	mptsas_t		*mpt = DIP2MPT(pdip);
+	uint64_t		sas_wwn = 0;
+	uint8_t			phy = 0xFF;
+	uint32_t		dev_info = 0;
+
+	mutex_enter(&mpt->m_mutex);
+	sas_wwn = ptgt->m_sas_wwn;
+	phy = ptgt->m_phynum;
+	dev_info = ptgt->m_deviceinfo;
+	mutex_exit(&mpt->m_mutex);
+
+	if (sas_wwn == 0) {
+		/*
+		 * It's a SATA without Device Name
+		 * So don't try multi-LUNs
+		 */
+		if (mptsas_find_child_phy(pdip, phy)) {
+			return (DDI_SUCCESS);
+		} else {
+			/*
+			 * need configure and create node
+			 */
+			return (DDI_FAILURE);
+		}
+	}
+
+	/*
+	 * WWN (SAS address or Device Name exist)
+	 */
+	if (dev_info & (MPI2_SAS_DEVICE_INFO_SATA_DEVICE |
+	    MPI2_SAS_DEVICE_INFO_ATAPI_DEVICE)) {
+		/*
+		 * SATA device with Device Name
+		 * So don't try multi-LUNs
+		 */
+		if (mptsas_find_child_addr(pdip, sas_wwn, 0)) {
+			return (DDI_SUCCESS);
+		} else {
+			return (DDI_FAILURE);
+		}
+	}
+
+	do {
+		ap.a_target = MPTSAS_INVALID_DEVHDL;
+		ap.a_lun = 0;
+		ap.a_hba_tran = mpt->m_tran;
+		repluns_bp = scsi_alloc_consistent_buf(&ap,
+		    (struct buf *)NULL, buf_len, B_READ, NULL_FUNC, NULL);
+		if (repluns_bp == NULL) {
+			retry++;
+			continue;
+		}
+		bzero(cdb, CDB_GROUP5);
+		cdb[0] = SCMD_REPORT_LUNS;
+		cdb[6] = (buf_len & 0xff000000) >> 24;
+		cdb[7] = (buf_len & 0x00ff0000) >> 16;
+		cdb[8] = (buf_len & 0x0000ff00) >> 8;
+		cdb[9] = (buf_len & 0x000000ff);
+
+		ret = mptsas_send_scsi_cmd(mpt, &ap, ptgt, &cdb[0], CDB_GROUP5,
+		    repluns_bp, NULL);
+		if (ret != DDI_SUCCESS) {
+			scsi_free_consistent_buf(repluns_bp);
+			retry++;
+			continue;
+		}
+		lun_list_len = BE_32(*(int *)((void *)(
+		    repluns_bp->b_un.b_addr)));
+		if (buf_len >= lun_list_len + 8) {
+			ret = DDI_SUCCESS;
+			break;
+		}
+		scsi_free_consistent_buf(repluns_bp);
+		buf_len = lun_list_len + 8;
+
+	} while (retry < 3);
+
+	if (ret != DDI_SUCCESS)
+		return (ret);
+	buffer = (char *)repluns_bp->b_un.b_addr;
+	/*
+	 * find out the number of luns returned by the SCSI ReportLun call
+	 * and allocate buffer space
+	 */
+	lun_total = lun_list_len / MPTSAS_SCSI_REPORTLUNS_ADDRESS_SIZE;
+	saved_repluns = kmem_zalloc(sizeof (uint16_t) * lun_total, KM_SLEEP);
+	if (saved_repluns == NULL) {
+		scsi_free_consistent_buf(repluns_bp);
+		return (DDI_FAILURE);
+	}
+	for (lun_cnt = 0; lun_cnt < lun_total; lun_cnt++) {
+		if (mptsas_retrieve_lundata(lun_cnt, (uint8_t *)(buffer),
+		    &lun_num, &lun_addr_type) != DDI_SUCCESS) {
+			continue;
+		}
+		saved_repluns[lun_cnt] = lun_num;
+		if (cdip = mptsas_find_child_addr(pdip, sas_wwn, lun_num))
+			ret = DDI_SUCCESS;
+		else
+			ret = mptsas_probe_lun(pdip, lun_num, &cdip,
+			    ptgt);
+		if ((ret == DDI_SUCCESS) && (cdip != NULL)) {
+			(void) ndi_prop_remove(DDI_DEV_T_NONE, cdip,
+			    MPTSAS_DEV_GONE);
+		}
+	}
+	mptsas_offline_missed_luns(pdip, saved_repluns, lun_total, ptgt);
+	kmem_free(saved_repluns, sizeof (uint16_t) * lun_total);
+	scsi_free_consistent_buf(repluns_bp);
+	return (DDI_SUCCESS);
+}
+
+static int
+mptsas_config_raid(dev_info_t *pdip, uint16_t target, dev_info_t **dip)
+{
+	int			rval = DDI_FAILURE;
+	struct scsi_inquiry	*sd_inq = NULL;
+	mptsas_t		*mpt = DIP2MPT(pdip);
+	mptsas_target_t		*ptgt = NULL;
+
+	mutex_enter(&mpt->m_mutex);
+	ptgt = mptsas_search_by_devhdl(&mpt->m_active->m_tgttbl, target);
+	mutex_exit(&mpt->m_mutex);
+	if (ptgt == NULL) {
+		mptsas_log(mpt, CE_WARN, "Volume with VolDevHandle of 0x%x "
+		    "not found.", target);
+		return (rval);
+	}
+
+	sd_inq = (struct scsi_inquiry *)kmem_alloc(SUN_INQSIZE, KM_SLEEP);
+	rval = mptsas_inquiry(mpt, ptgt, 0, 0, (uchar_t *)sd_inq,
+	    SUN_INQSIZE, 0, (uchar_t)0);
+
+	if ((rval == DDI_SUCCESS) && MPTSAS_VALID_LUN(sd_inq)) {
+		rval = mptsas_create_phys_lun(pdip, sd_inq, NULL, dip, ptgt,
+		    0);
+	} else {
+		rval = DDI_FAILURE;
+	}
+
+out:
+	kmem_free(sd_inq, SUN_INQSIZE);
+	return (rval);
+}
+
+/*
+ * configure all RAID volumes for virtual iport
+ */
+static void
+mptsas_config_all_viport(dev_info_t *pdip)
+{
+	mptsas_t	*mpt = DIP2MPT(pdip);
+	int		config, vol;
+	int		target;
+	dev_info_t	*lundip = NULL;
+	mptsas_slots_t	*slots = mpt->m_active;
+
+	/*
+	 * Get latest RAID info and search for any Volume DevHandles.  If any
+	 * are found, configure the volume.
+	 */
+	mutex_enter(&mpt->m_mutex);
+	for (config = 0; config < slots->m_num_raid_configs; config++) {
+		for (vol = 0; vol < MPTSAS_MAX_RAIDVOLS; vol++) {
+			if (slots->m_raidconfig[config].m_raidvol[vol].m_israid
+			    == 1) {
+				target = slots->m_raidconfig[config].
+				    m_raidvol[vol].m_raidhandle;
+				mutex_exit(&mpt->m_mutex);
+				(void) mptsas_config_raid(pdip, target,
+				    &lundip);
+				mutex_enter(&mpt->m_mutex);
+			}
+		}
+	}
+	mutex_exit(&mpt->m_mutex);
+}
+
+static void
+mptsas_offline_missed_luns(dev_info_t *pdip, uint16_t *repluns,
+    int lun_cnt, mptsas_target_t *ptgt)
+{
+	dev_info_t	*child = NULL, *savechild = NULL;
+	mdi_pathinfo_t	*pip = NULL, *savepip = NULL;
+	uint64_t	sas_wwn, wwid;
+	uint8_t		phy;
+	int		lun;
+	int		i;
+	int		find;
+	char		*addr;
+	char		*nodename;
+	mptsas_t	*mpt = DIP2MPT(pdip);
+
+	mutex_enter(&mpt->m_mutex);
+	wwid = ptgt->m_sas_wwn;
+	mutex_exit(&mpt->m_mutex);
+
+	child = ddi_get_child(pdip);
+	while (child) {
+		find = 0;
+		savechild = child;
+		child = ddi_get_next_sibling(child);
+
+		nodename = ddi_node_name(savechild);
+		if (strcmp(nodename, "smp") == 0) {
+			continue;
+		}
+
+		addr = ddi_get_name_addr(savechild);
+		if (addr == NULL) {
+			continue;
+		}
+
+		if (mptsas_parse_address(addr, &sas_wwn, &phy, &lun) !=
+		    DDI_SUCCESS) {
+			continue;
+		}
+
+		if (wwid == sas_wwn) {
+			for (i = 0; i < lun_cnt; i++) {
+				if (repluns[i] == lun) {
+					find = 1;
+					break;
+				}
+			}
+		} else {
+			continue;
+		}
+		if (find == 0) {
+			/*
+			 * The lun has not been there already
+			 */
+			(void) mptsas_offline_lun(pdip, savechild, NULL,
+			    NDI_DEVI_REMOVE);
+		}
+	}
+
+	pip = mdi_get_next_client_path(pdip, NULL);
+	while (pip) {
+		find = 0;
+		savepip = pip;
+		addr = MDI_PI(pip)->pi_addr;
+
+		pip = mdi_get_next_client_path(pdip, pip);
+
+		if (addr == NULL) {
+			continue;
+		}
+
+		if (mptsas_parse_address(addr, &sas_wwn, &phy,
+		    &lun) != DDI_SUCCESS) {
+			continue;
+		}
+
+		if (sas_wwn == wwid) {
+			for (i = 0; i < lun_cnt; i++) {
+				if (repluns[i] == lun) {
+					find = 1;
+					break;
+				}
+			}
+		} else {
+			continue;
+		}
+
+		if (find == 0) {
+			/*
+			 * The lun has not been there already
+			 */
+			(void) mptsas_offline_lun(pdip, NULL, savepip,
+			    NDI_DEVI_REMOVE);
+		}
+	}
+}
+
+void
+mptsas_update_hashtab(struct mptsas *mpt)
+{
+	uint32_t	page_address;
+	int		rval = 0;
+	uint16_t	dev_handle;
+	mptsas_target_t	*ptgt = NULL;
+	mptsas_smp_t	smp_node;
+
+	/*
+	 * Get latest RAID info.
+	 */
+	(void) mptsas_get_raid_info(mpt);
+
+	dev_handle = mpt->m_smp_devhdl;
+	for (; mpt->m_done_traverse_smp == 0; ) {
+		page_address = (MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL &
+		    MPI2_SAS_EXPAND_PGAD_FORM_MASK) | (uint32_t)dev_handle;
+		if (mptsas_get_sas_expander_page0(mpt, page_address, &smp_node)
+		    != DDI_SUCCESS) {
+			break;
+		}
+		mpt->m_smp_devhdl = dev_handle = smp_node.m_devhdl;
+		(void) mptsas_smp_alloc(&mpt->m_active->m_smptbl, &smp_node);
+	}
+
+	/*
+	 * Config target devices
+	 */
+	dev_handle = mpt->m_dev_handle;
+
+	/*
+	 * Do loop to get sas device page 0 by GetNextHandle till the
+	 * the last handle. If the sas device is a SATA/SSP target,
+	 * we try to config it.
+	 */
+	for (; mpt->m_done_traverse_dev == 0; ) {
+		ptgt = NULL;
+		page_address =
+		    (MPI2_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE &
+		    MPI2_SAS_DEVICE_PGAD_FORM_MASK) |
+		    (uint32_t)dev_handle;
+		rval = mptsas_get_target_device_info(mpt, page_address,
+		    &dev_handle, &ptgt);
+		if ((rval == DEV_INFO_FAIL_PAGE0) ||
+		    (rval == DEV_INFO_FAIL_ALLOC)) {
+			break;
+		}
+
+		mpt->m_dev_handle = dev_handle;
+	}
+
+}
+
+void
+mptsas_invalid_hashtab(mptsas_hash_table_t *hashtab)
+{
+	mptsas_hash_data_t *data;
+	data = mptsas_hash_traverse(hashtab, MPTSAS_HASH_FIRST);
+	while (data != NULL) {
+		data->devhdl = MPTSAS_INVALID_DEVHDL;
+		data->device_info = 0;
+		/*
+		 * For tgttbl, clear dr_flag.
+		 */
+		data->dr_flag = MPTSAS_DR_INACTIVE;
+		data = mptsas_hash_traverse(hashtab, MPTSAS_HASH_NEXT);
+	}
+}
+
+void
+mptsas_update_driver_data(struct mptsas *mpt)
+{
+	/*
+	 * TODO after hard reset, update the driver data structures
+	 * 1. update port/phymask mapping table mpt->m_phy_info
+	 * 2. invalid all the entries in hash table
+	 *    m_devhdl = 0xffff and m_deviceinfo = 0
+	 * 3. call sas_device_page/expander_page to update hash table
+	 */
+	mptsas_update_phymask(mpt);
+	/*
+	 * Invalid the existing entries
+	 */
+	mptsas_invalid_hashtab(&mpt->m_active->m_tgttbl);
+	mptsas_invalid_hashtab(&mpt->m_active->m_smptbl);
+	mpt->m_done_traverse_dev = 0;
+	mpt->m_done_traverse_smp = 0;
+	mpt->m_dev_handle = mpt->m_smp_devhdl = MPTSAS_INVALID_DEVHDL;
+	mptsas_update_hashtab(mpt);
+}
+
+static void
+mptsas_config_all(dev_info_t *pdip)
+{
+	dev_info_t	*smpdip = NULL;
+	mptsas_t	*mpt = DIP2MPT(pdip);
+	int		phymask = 0;
+	uint8_t		phy_mask;
+	mptsas_target_t	*ptgt = NULL;
+	mptsas_smp_t	*psmp;
+
+	/*
+	 * Get the phymask associated to the iport
+	 */
+	phymask = ddi_prop_get_int(DDI_DEV_T_ANY, pdip, 0,
+	    "phymask", 0);
+
+	/*
+	 * Enumerate RAID volumes here (phymask == 0).
+	 */
+	if (phymask == 0) {
+		mptsas_config_all_viport(pdip);
+		return;
+	}
+
+	mutex_enter(&mpt->m_mutex);
+
+	if (!mpt->m_done_traverse_dev || !mpt->m_done_traverse_smp) {
+		mptsas_update_hashtab(mpt);
+	}
+
+	psmp = (mptsas_smp_t *)mptsas_hash_traverse(&mpt->m_active->m_smptbl,
+	    MPTSAS_HASH_FIRST);
+	while (psmp != NULL) {
+		phy_mask = psmp->m_phymask;
+		if (phy_mask == phymask) {
+			smpdip = NULL;
+			mutex_exit(&mpt->m_mutex);
+			(void) mptsas_online_smp(pdip, psmp, &smpdip);
+			mutex_enter(&mpt->m_mutex);
+		}
+		psmp = (mptsas_smp_t *)mptsas_hash_traverse(
+		    &mpt->m_active->m_smptbl, MPTSAS_HASH_NEXT);
+	}
+
+	ptgt = (mptsas_target_t *)mptsas_hash_traverse(&mpt->m_active->m_tgttbl,
+	    MPTSAS_HASH_FIRST);
+	while (ptgt != NULL) {
+		phy_mask = ptgt->m_phymask;
+		if (phy_mask == phymask) {
+			mutex_exit(&mpt->m_mutex);
+			(void) mptsas_config_target(pdip, ptgt);
+			mutex_enter(&mpt->m_mutex);
+		}
+
+		ptgt = (mptsas_target_t *)mptsas_hash_traverse(
+		    &mpt->m_active->m_tgttbl, MPTSAS_HASH_NEXT);
+	}
+	mutex_exit(&mpt->m_mutex);
+}
+
+static int
+mptsas_config_target(dev_info_t *pdip, mptsas_target_t *ptgt)
+{
+	int		rval = DDI_FAILURE;
+	dev_info_t	*tdip;
+
+	rval = mptsas_config_luns(pdip, ptgt);
+	if (rval != DDI_SUCCESS) {
+		/*
+		 * The return value means the SCMD_REPORT_LUNS
+		 * did not execute successfully. The target maybe
+		 * doesn't support such command.
+		 */
+		rval = mptsas_probe_lun(pdip, 0, &tdip, ptgt);
+	}
+	return (rval);
+}
+
+/*
+ * Return fail if not all the childs/paths are freed.
+ * if there is any path under the HBA, the return value will be always fail
+ * because we didn't call mdi_pi_free for path
+ */
+static int
+mptsas_offline_target(dev_info_t *pdip, char *name)
+{
+	dev_info_t		*child = NULL, *prechild = NULL;
+	mdi_pathinfo_t		*pip = NULL, *savepip = NULL;
+	int			tmp_rval, rval = DDI_SUCCESS;
+	char			*addr, *cp;
+	size_t			s;
+	mptsas_t		*mpt = DIP2MPT(pdip);
+
+	child = ddi_get_child(pdip);
+	while (child) {
+		addr = ddi_get_name_addr(child);
+		prechild = child;
+		child = ddi_get_next_sibling(child);
+
+		if (addr == NULL) {
+			continue;
+		}
+		if ((cp = strchr(addr, ',')) == NULL) {
+			continue;
+		}
+
+		s = (uintptr_t)cp - (uintptr_t)addr;
+
+		if (strncmp(addr, name, s) != 0) {
+			continue;
+		}
+
+		tmp_rval = mptsas_offline_lun(pdip, prechild, NULL,
+		    NDI_DEVI_REMOVE);
+		if (tmp_rval != DDI_SUCCESS) {
+			rval = DDI_FAILURE;
+			if (ndi_prop_create_boolean(DDI_DEV_T_NONE,
+			    prechild, MPTSAS_DEV_GONE) !=
+			    DDI_PROP_SUCCESS) {
+				mptsas_log(mpt, CE_WARN, "mptsas driver "
+				    "unable to create property for "
+				    "SAS %s (MPTSAS_DEV_GONE)", addr);
+			}
+		}
+	}
+
+	pip = mdi_get_next_client_path(pdip, NULL);
+	while (pip) {
+		addr = MDI_PI(pip)->pi_addr;
+		savepip = pip;
+		pip = mdi_get_next_client_path(pdip, pip);
+		if (addr == NULL) {
+			continue;
+		}
+
+		if ((cp = strchr(addr, ',')) == NULL) {
+			continue;
+		}
+
+		s = (uintptr_t)cp - (uintptr_t)addr;
+
+		if (strncmp(addr, name, s) != 0) {
+			continue;
+		}
+
+		(void) mptsas_offline_lun(pdip, NULL, savepip,
+		    NDI_DEVI_REMOVE);
+		/*
+		 * driver will not invoke mdi_pi_free, so path will not
+		 * be freed forever, return DDI_FAILURE.
+		 */
+		rval = DDI_FAILURE;
+	}
+	return (rval);
+}
+
+static int
+mptsas_offline_lun(dev_info_t *pdip, dev_info_t *rdip,
+    mdi_pathinfo_t *rpip, uint_t flags)
+{
+	int		rval = DDI_FAILURE;
+	char		*devname;
+	dev_info_t	*cdip, *parent;
+
+	if (rpip != NULL) {
+		parent = scsi_vhci_dip;
+		cdip = mdi_pi_get_client(rpip);
+	} else if (rdip != NULL) {
+		parent = pdip;
+		cdip = rdip;
+	} else {
+		return (DDI_FAILURE);
+	}
+
+	/*
+	 * Make sure node is attached otherwise
+	 * it won't have related cache nodes to
+	 * clean up.  i_ddi_devi_attached is
+	 * similiar to i_ddi_node_state(cdip) >=
+	 * DS_ATTACHED.
+	 */
+	if (i_ddi_devi_attached(cdip)) {
+
+		/* Get full devname */
+		devname = kmem_alloc(MAXNAMELEN + 1, KM_SLEEP);
+		(void) ddi_deviname(cdip, devname);
+		/* Clean cache */
+		(void) devfs_clean(parent, devname + 1,
+		    DV_CLEAN_FORCE);
+		kmem_free(devname, MAXNAMELEN + 1);
+	}
+	if (rpip != NULL) {
+		if (MDI_PI_IS_OFFLINE(rpip)) {
+			rval = DDI_SUCCESS;
+		} else {
+			rval = mdi_pi_offline(rpip, 0);
+		}
+	} else {
+		rval = ndi_devi_offline(cdip, flags);
+	}
+
+	return (rval);
+}
+
+static dev_info_t *
+mptsas_find_smp_child(dev_info_t *parent, char *str_wwn)
+{
+	dev_info_t	*child = NULL;
+	char		*smp_wwn = NULL;
+
+	child = ddi_get_child(parent);
+	while (child) {
+		if (ddi_prop_lookup_string(DDI_DEV_T_ANY, child,
+		    DDI_PROP_DONTPASS, SMP_WWN, &smp_wwn)
+		    != DDI_SUCCESS) {
+			child = ddi_get_next_sibling(child);
+			continue;
+		}
+
+		if (strcmp(smp_wwn, str_wwn) == 0) {
+			ddi_prop_free(smp_wwn);
+			break;
+		}
+		child = ddi_get_next_sibling(child);
+		ddi_prop_free(smp_wwn);
+	}
+	return (child);
+}
+
+static int
+mptsas_offline_smp(dev_info_t *pdip, mptsas_smp_t *smp_node, uint_t flags)
+{
+	int		rval = DDI_FAILURE;
+	char		*devname;
+	char		wwn_str[MPTSAS_WWN_STRLEN];
+	dev_info_t	*cdip;
+
+	(void) sprintf(wwn_str, "%"PRIx64, smp_node->m_sasaddr);
+
+	cdip = mptsas_find_smp_child(pdip, wwn_str);
+
+	if (cdip == NULL)
+		return (DDI_SUCCESS);
+
+	/*
+	 * Make sure node is attached otherwise
+	 * it won't have related cache nodes to
+	 * clean up.  i_ddi_devi_attached is
+	 * similiar to i_ddi_node_state(cdip) >=
+	 * DS_ATTACHED.
+	 */
+	if (i_ddi_devi_attached(cdip)) {
+
+		/* Get full devname */
+		devname = kmem_alloc(MAXNAMELEN + 1, KM_SLEEP);
+		(void) ddi_deviname(cdip, devname);
+		/* Clean cache */
+		(void) devfs_clean(pdip, devname + 1,
+		    DV_CLEAN_FORCE);
+		kmem_free(devname, MAXNAMELEN + 1);
+	}
+
+	rval = ndi_devi_offline(cdip, flags);
+
+	return (rval);
+}
+
+static dev_info_t *
+mptsas_find_child(dev_info_t *pdip, char *name)
+{
+	dev_info_t	*child = NULL;
+	char		*rname = NULL;
+	int		rval = DDI_FAILURE;
+
+	rname = kmem_zalloc(SCSI_MAXNAMELEN, KM_SLEEP);
+
+	child = ddi_get_child(pdip);
+	while (child) {
+		rval = mptsas_name_child(child, rname, SCSI_MAXNAMELEN);
+		if (rval != DDI_SUCCESS) {
+			child = ddi_get_next_sibling(child);
+			bzero(rname, SCSI_MAXNAMELEN);
+			continue;
+		}
+
+		if (strcmp(rname, name) == 0) {
+			break;
+		}
+		child = ddi_get_next_sibling(child);
+		bzero(rname, SCSI_MAXNAMELEN);
+	}
+
+	kmem_free(rname, SCSI_MAXNAMELEN);
+
+	return (child);
+}
+
+
+static dev_info_t *
+mptsas_find_child_addr(dev_info_t *pdip, uint64_t sasaddr, int lun)
+{
+	dev_info_t	*child = NULL;
+	char		*name = NULL;
+	char		*addr = NULL;
+
+	name = kmem_zalloc(SCSI_MAXNAMELEN, KM_SLEEP);
+	addr = kmem_zalloc(SCSI_MAXNAMELEN, KM_SLEEP);
+	(void) sprintf(name, "%016"PRIx64, sasaddr);
+	(void) sprintf(addr, "w%s,%x", name, lun);
+	child = mptsas_find_child(pdip, addr);
+	kmem_free(name, SCSI_MAXNAMELEN);
+	kmem_free(addr, SCSI_MAXNAMELEN);
+	return (child);
+}
+
+static dev_info_t *
+mptsas_find_child_phy(dev_info_t *pdip, uint8_t phy)
+{
+	dev_info_t	*child;
+	char		*addr;
+
+	addr = kmem_zalloc(SCSI_MAXNAMELEN, KM_SLEEP);
+	(void) sprintf(addr, "p%x,0", phy);
+	child = mptsas_find_child(pdip, addr);
+	kmem_free(addr, SCSI_MAXNAMELEN);
+	return (child);
+}
+
+static mdi_pathinfo_t *
+mptsas_find_path_phy(dev_info_t *pdip, uint8_t phy)
+{
+	mdi_pathinfo_t	*path;
+	char		*addr = NULL;
+
+	addr = kmem_zalloc(SCSI_MAXNAMELEN, KM_SLEEP);
+	(void) sprintf(addr, "p%x,0", phy);
+	path = mdi_pi_find(pdip, NULL, addr);
+	kmem_free(addr, SCSI_MAXNAMELEN);
+	return (path);
+}
+
+static mdi_pathinfo_t *
+mptsas_find_path_addr(dev_info_t *parent, uint64_t sasaddr, int lun)
+{
+	mdi_pathinfo_t	*path;
+	char		*name = NULL;
+	char		*addr = NULL;
+
+	name = kmem_zalloc(SCSI_MAXNAMELEN, KM_SLEEP);
+	addr = kmem_zalloc(SCSI_MAXNAMELEN, KM_SLEEP);
+	(void) sprintf(name, "%016"PRIx64, sasaddr);
+	(void) sprintf(addr, "w%s,%x", name, lun);
+	path = mdi_pi_find(parent, NULL, addr);
+	kmem_free(name, SCSI_MAXNAMELEN);
+	kmem_free(addr, SCSI_MAXNAMELEN);
+
+	return (path);
+}
+
+static int
+mptsas_create_lun(dev_info_t *pdip, struct scsi_inquiry *sd_inq,
+    dev_info_t **lun_dip, mptsas_target_t *ptgt, int lun)
+{
+	int			i = 0;
+	uchar_t			*inq83 = NULL;
+	int			inq83_len1 = 0xFF;
+	int			inq83_len = 0;
+	int			rval = DDI_FAILURE;
+	ddi_devid_t		devid;
+	char			*guid = NULL;
+	int			target = ptgt->m_devhdl;
+	mdi_pathinfo_t		*pip = NULL;
+	mptsas_t		*mpt = DIP2MPT(pdip);
+
+	/*
+	 * For DVD/CD ROM and tape devices and optical
+	 * devices, we won't try to enumerate them under
+	 * scsi_vhci, so no need to try page83
+	 */
+	if (sd_inq && (sd_inq->inq_dtype == DTYPE_RODIRECT ||
+	    sd_inq->inq_dtype == DTYPE_OPTICAL))
+		goto create_lun;
+
+	/*
+	 * The LCA returns good SCSI status, but corrupt page 83 data the first
+	 * time it is queried. The solution is to keep trying to request page83
+	 * and verify the GUID is not (DDI_NOT_WELL_FORMED) in
+	 * mptsas_inq83_retry_timeout seconds. If the timeout expires, driver
+	 * give up to get VPD page at this stage and fail the enumeration.
+	 */
+
+	inq83	= kmem_zalloc(inq83_len1, KM_SLEEP);
+
+	for (i = 0; i < mptsas_inq83_retry_timeout; i++) {
+		rval = mptsas_inquiry(mpt, ptgt, lun, 0x83, inq83,
+		    inq83_len1, &inq83_len, 1);
+		if (rval != 0) {
+			mptsas_log(mpt, CE_WARN, "!mptsas request inquiry page "
+			    "0x83 for target:%x, lun:%x failed!", target, lun);
+			goto out;
+		}
+		/*
+		 * create DEVID from inquiry data
+		 */
+		if ((rval = ddi_devid_scsi_encode(
+		    DEVID_SCSI_ENCODE_VERSION_LATEST, NULL, (uchar_t *)sd_inq,
+		    sizeof (struct scsi_inquiry), NULL, 0, inq83,
+		    (size_t)inq83_len, &devid)) == DDI_SUCCESS) {
+			/*
+			 * extract GUID from DEVID
+			 */
+			guid = ddi_devid_to_guid(devid);
+
+			/*
+			 * Do not enable MPXIO if the strlen(guid) is greater
+			 * than MPTSAS_MAX_GUID_LEN, this constrain would be
+			 * handled by framework later.
+			 */
+			if (guid && (strlen(guid) > MPTSAS_MAX_GUID_LEN)) {
+				ddi_devid_free_guid(guid);
+				guid = NULL;
+				if (mpt->m_mpxio_enable == TRUE) {
+					mptsas_log(mpt, CE_NOTE, "!Target:%x, "
+					    "lun:%x doesn't have a valid GUID, "
+					    "multipathing for this drive is "
+					    "not enabled", target, lun);
+				}
+			}
+
+			/*
+			 * devid no longer needed
+			 */
+			ddi_devid_free(devid);
+			break;
+		} else if (rval == DDI_NOT_WELL_FORMED) {
+			/*
+			 * return value of ddi_devid_scsi_encode equal to
+			 * DDI_NOT_WELL_FORMED means DEVID_RETRY, it worth
+			 * to retry inquiry page 0x83 and get GUID.
+			 */
+			NDBG20(("Not well formed devid, retry..."));
+			delay(1 * drv_usectohz(1000000));
+			continue;
+		} else {
+			mptsas_log(mpt, CE_WARN, "!Encode devid failed for "
+			    "path target:%x, lun:%x", target, lun);
+			rval = DDI_FAILURE;
+			goto create_lun;
+		}
+	}
+
+	if (i == mptsas_inq83_retry_timeout) {
+		mptsas_log(mpt, CE_WARN, "!Repeated page83 requests timeout "
+		    "for path target:%x, lun:%x", target, lun);
+	}
+
+	rval = DDI_FAILURE;
+
+create_lun:
+	if ((guid != NULL) && (mpt->m_mpxio_enable == TRUE)) {
+		rval = mptsas_create_virt_lun(pdip, sd_inq, guid, lun_dip, &pip,
+		    ptgt, lun);
+	}
+	if (rval != DDI_SUCCESS) {
+		rval = mptsas_create_phys_lun(pdip, sd_inq, guid, lun_dip,
+		    ptgt, lun);
+	}
+out:
+	if (guid != NULL) {
+		/*
+		 * guid no longer needed
+		 */
+		ddi_devid_free_guid(guid);
+	}
+	if (inq83 != NULL)
+		kmem_free(inq83, inq83_len1);
+	return (rval);
+}
+
+static int
+mptsas_create_virt_lun(dev_info_t *pdip, struct scsi_inquiry *inq, char *guid,
+    dev_info_t **lun_dip, mdi_pathinfo_t **pip, mptsas_target_t *ptgt, int lun)
+{
+	int			target;
+	char			*nodename = NULL;
+	char			**compatible = NULL;
+	int			ncompatible	= 0;
+	int			mdi_rtn = MDI_FAILURE;
+	int			rval = DDI_FAILURE;
+	char			*old_guid = NULL;
+	mptsas_t		*mpt = DIP2MPT(pdip);
+	char			*lun_addr = NULL;
+	char			*wwn_str = NULL;
+	char			*component = NULL;
+	uint8_t			phy = 0xFF;
+	uint64_t		sas_wwn;
+	uint32_t		devinfo;
+
+	mutex_enter(&mpt->m_mutex);
+	target = ptgt->m_devhdl;
+	sas_wwn = ptgt->m_sas_wwn;
+	devinfo = ptgt->m_deviceinfo;
+	phy = ptgt->m_phynum;
+	mutex_exit(&mpt->m_mutex);
+
+	if (sas_wwn) {
+		*pip = mptsas_find_path_addr(pdip, sas_wwn, lun);
+	} else {
+		*pip = mptsas_find_path_phy(pdip, phy);
+	}
+
+	if (*pip != NULL) {
+		*lun_dip = MDI_PI(*pip)->pi_client->ct_dip;
+		ASSERT(*lun_dip != NULL);
+		if (ddi_prop_lookup_string(DDI_DEV_T_ANY, *lun_dip,
+		    (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM),
+		    MDI_CLIENT_GUID_PROP, &old_guid) == DDI_SUCCESS) {
+			if (strncmp(guid, old_guid, strlen(guid)) == 0) {
+				/*
+				 * Same path back online again.
+				 */
+				(void) ddi_prop_free(old_guid);
+				if (!MDI_PI_IS_ONLINE(*pip) &&
+				    !MDI_PI_IS_STANDBY(*pip)) {
+					rval = mdi_pi_online(*pip, 0);
+				} else {
+					rval = DDI_SUCCESS;
+				}
+				if (rval != DDI_SUCCESS) {
+					mptsas_log(mpt, CE_WARN, "path:target: "
+					    "%x, lun:%x online failed!", target,
+					    lun);
+					*pip = NULL;
+					*lun_dip = NULL;
+				}
+				return (rval);
+			} else {
+				/*
+				 * The GUID of the LUN has changed which maybe
+				 * because customer mapped another volume to the
+				 * same LUN.
+				 */
+				mptsas_log(mpt, CE_WARN, "The GUID of the "
+				    "target:%x, lun:%x was changed, maybe "
+				    "because someone mapped another volume "
+				    "to the same LUN", target, lun);
+				(void) ddi_prop_free(old_guid);
+				if (!MDI_PI_IS_OFFLINE(*pip)) {
+					rval = mdi_pi_offline(*pip, 0);
+					if (rval != MDI_SUCCESS) {
+						mptsas_log(mpt, CE_WARN, "path:"
+						    "target:%x, lun:%x offline "
+						    "failed!", target, lun);
+						*pip = NULL;
+						*lun_dip = NULL;
+						return (DDI_FAILURE);
+					}
+				}
+				if (mdi_pi_free(*pip, 0) != MDI_SUCCESS) {
+					mptsas_log(mpt, CE_WARN, "path:target:"
+					    "%x, lun:%x free failed!", target,
+					    lun);
+					*pip = NULL;
+					*lun_dip = NULL;
+					return (DDI_FAILURE);
+				}
+			}
+		} else {
+			mptsas_log(mpt, CE_WARN, "Can't get client-guid "
+			    "property for path:target:%x, lun:%x", target, lun);
+			*pip = NULL;
+			*lun_dip = NULL;
+			return (DDI_FAILURE);
+		}
+	}
+	scsi_hba_nodename_compatible_get(inq, NULL,
+	    inq->inq_dtype, NULL, &nodename, &compatible, &ncompatible);
+
+	/*
+	 * if nodename can't be determined then print a message and skip it
+	 */
+	if (nodename == NULL) {
+		mptsas_log(mpt, CE_WARN, "mptsas driver found no compatible "
+		    "driver for target%d lun %d dtype:0x%02x", target, lun,
+		    inq->inq_dtype);
+		return (DDI_FAILURE);
+	}
+
+	wwn_str = kmem_zalloc(MPTSAS_WWN_STRLEN, KM_SLEEP);
+	/* The property is needed by MPAPI */
+	(void) sprintf(wwn_str, "%016"PRIx64, sas_wwn);
+
+	lun_addr = kmem_zalloc(SCSI_MAXNAMELEN, KM_SLEEP);
+	if (sas_wwn)
+		(void) sprintf(lun_addr, "w%s,%x", wwn_str, lun);
+	else
+		(void) sprintf(lun_addr, "p%x,%x", phy, lun);
+
+	mdi_rtn = mdi_pi_alloc_compatible(pdip, nodename,
+	    guid, lun_addr, compatible, ncompatible,
+	    0, pip);
+	if (mdi_rtn == MDI_SUCCESS) {
+
+		if (mdi_prop_update_string(*pip, MDI_GUID,
+		    guid) != DDI_SUCCESS) {
+			mptsas_log(mpt, CE_WARN, "mptsas driver unable to "
+			    "create property for target %d lun %d (MDI_GUID)",
+			    target, lun);
+			mdi_rtn = MDI_FAILURE;
+			goto virt_create_done;
+		}
+
+		if (mdi_prop_update_int(*pip, LUN_PROP,
+		    lun) != DDI_SUCCESS) {
+			mptsas_log(mpt, CE_WARN, "mptsas driver unable to "
+			    "create property for target %d lun %d (LUN_PROP)",
+			    target, lun);
+			mdi_rtn = MDI_FAILURE;
+			goto virt_create_done;
+		}
+		if (mdi_prop_update_string_array(*pip, "compatible",
+		    compatible, ncompatible) !=
+		    DDI_PROP_SUCCESS) {
+			mptsas_log(mpt, CE_WARN, "mptsas driver unable to "
+			    "create property for target %d lun %d (COMPATIBLE)",
+			    target, lun);
+			mdi_rtn = MDI_FAILURE;
+			goto virt_create_done;
+		}
+		if (sas_wwn && (mdi_prop_update_string(*pip, "target-port",
+		    wwn_str) != DDI_PROP_SUCCESS)) {
+			mptsas_log(mpt, CE_WARN, "mptsas driver unable to "
+			    "create property for target %d lun %d "
+			    "(target-port)", target, lun);
+			mdi_rtn = MDI_FAILURE;
+			goto virt_create_done;
+		} else if ((sas_wwn == 0) && (mdi_prop_update_int(*pip,
+		    "sata-phy", phy) != DDI_PROP_SUCCESS)) {
+			/*
+			 * Direct attached SATA device without DeviceName
+			 */
+			mptsas_log(mpt, CE_WARN, "mptsas driver unable to "
+			    "create property for SAS target %d lun %d "
+			    "(sata-phy)", target, lun);
+			mdi_rtn = NDI_FAILURE;
+			goto virt_create_done;
+		}
+
+		if (inq->inq_dtype == 0) {
+			component = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
+			/*
+			 * set obp path for pathinfo
+			 */
+			(void) snprintf(component, MAXPATHLEN,
+			    "disk@%s", lun_addr);
+
+			if (mdi_pi_pathname_obp_set(*pip, component) !=
+			    DDI_SUCCESS) {
+				mptsas_log(mpt, CE_WARN, "mpt_sas driver "
+				    "unable to set obp-path for object %s",
+				    component);
+				mdi_rtn = MDI_FAILURE;
+				goto virt_create_done;
+			}
+		}
+
+		*lun_dip = MDI_PI(*pip)->pi_client->ct_dip;
+		if (devinfo & (MPI2_SAS_DEVICE_INFO_SATA_DEVICE |
+		    MPI2_SAS_DEVICE_INFO_ATAPI_DEVICE)) {
+			if ((ndi_prop_update_int(DDI_DEV_T_NONE, *lun_dip,
+			    "pm-capable", 1)) !=
+			    DDI_PROP_SUCCESS) {
+				mptsas_log(mpt, CE_WARN, "mptsas driver"
+				    "failed to create pm-capable "
+				    "property, target %d", target);
+				mdi_rtn = MDI_FAILURE;
+				goto virt_create_done;
+			}
+		}
+		NDBG20(("new path:%s onlining,", MDI_PI(*pip)->pi_addr));
+		mdi_rtn = mdi_pi_online(*pip, 0);
+		if (mdi_rtn == MDI_NOT_SUPPORTED) {
+			mdi_rtn = MDI_FAILURE;
+		}
+virt_create_done:
+		if (*pip && mdi_rtn != MDI_SUCCESS) {
+			(void) mdi_pi_free(*pip, 0);
+			*pip = NULL;
+			*lun_dip = NULL;
+		}
+	}
+
+	scsi_hba_nodename_compatible_free(nodename, compatible);
+	if (lun_addr != NULL) {
+		kmem_free(lun_addr, SCSI_MAXNAMELEN);
+	}
+	if (wwn_str != NULL) {
+		kmem_free(wwn_str, MPTSAS_WWN_STRLEN);
+	}
+	if (component != NULL) {
+		kmem_free(component, MAXPATHLEN);
+	}
+
+	return ((mdi_rtn == MDI_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE);
+}
+
+static int
+mptsas_create_phys_lun(dev_info_t *pdip, struct scsi_inquiry *inq,
+    char *guid, dev_info_t **lun_dip, mptsas_target_t *ptgt, int lun)
+{
+	int			target;
+	int			ndi_rtn = NDI_FAILURE;
+	uint64_t		be_sas_wwn;
+	char			*nodename = NULL;
+	char			**compatible = NULL;
+	int			ncompatible = 0;
+	int			instance = 0;
+	mptsas_t		*mpt = DIP2MPT(pdip);
+	char			*wwn_str = NULL;
+	char			*component = NULL;
+	uint8_t			phy = 0xFF;
+	uint64_t		sas_wwn;
+	uint32_t		devinfo;
+
+	mutex_enter(&mpt->m_mutex);
+	target = ptgt->m_devhdl;
+	sas_wwn = ptgt->m_sas_wwn;
+	devinfo = ptgt->m_deviceinfo;
+	phy = ptgt->m_phynum;
+	mutex_exit(&mpt->m_mutex);
+
+	/*
+	 * generate compatible property with binding-set "mpt"
+	 */
+	scsi_hba_nodename_compatible_get(inq, NULL, inq->inq_dtype, NULL,
+	    &nodename, &compatible, &ncompatible);
+
+	/*
+	 * if nodename can't be determined then print a message and skip it
+	 */
+	if (nodename == NULL) {
+		mptsas_log(mpt, CE_WARN, "mptsas found no comptible driver "
+		    "for target %d lun %d", target, lun);
+		return (DDI_FAILURE);
+	}
+
+	ndi_rtn = ndi_devi_alloc(pdip, nodename,
+	    DEVI_SID_NODEID, lun_dip);
+
+	/*
+	 * if lun alloc success, set props
+	 */
+	if (ndi_rtn == NDI_SUCCESS) {
+
+		if (ndi_prop_update_int(DDI_DEV_T_NONE,
+		    *lun_dip, LUN_PROP, lun) !=
+		    DDI_PROP_SUCCESS) {
+			mptsas_log(mpt, CE_WARN, "mptsas unable to create "
+			    "property for target %d lun %d (LUN_PROP)",
+			    target, lun);
+			ndi_rtn = NDI_FAILURE;
+			goto phys_create_done;
+		}
+
+		if (ndi_prop_update_string_array(DDI_DEV_T_NONE,
+		    *lun_dip, "compatible", compatible, ncompatible)
+		    != DDI_PROP_SUCCESS) {
+			mptsas_log(mpt, CE_WARN, "mptsas unable to create "
+			    "property for target %d lun %d (COMPATIBLE)",
+			    target, lun);
+			ndi_rtn = NDI_FAILURE;
+			goto phys_create_done;
+		}
+
+		/*
+		 * We need the SAS WWN for non-multipath devices, so
+		 * we'll use the same property as that multipathing
+		 * devices need to present for MPAPI. If we don't have
+		 * a WWN (e.g. parallel SCSI), don't create the prop.
+		 */
+		wwn_str = kmem_zalloc(MPTSAS_WWN_STRLEN, KM_SLEEP);
+		(void) sprintf(wwn_str, "%016"PRIx64, sas_wwn);
+		if (sas_wwn && ndi_prop_update_string(DDI_DEV_T_NONE,
+		    *lun_dip, "target-port", wwn_str)
+		    != DDI_PROP_SUCCESS) {
+			mptsas_log(mpt, CE_WARN, "mptsas unable to "
+			    "create property for SAS target %d lun %d "
+			    "(target-port)", target, lun);
+			ndi_rtn = NDI_FAILURE;
+			goto phys_create_done;
+		}
+		be_sas_wwn = BE_64(sas_wwn);
+		if (sas_wwn && ndi_prop_update_byte_array(
+		    DDI_DEV_T_NONE, *lun_dip, "port-wwn",
+		    (uchar_t *)&be_sas_wwn, 8) != DDI_PROP_SUCCESS) {
+			mptsas_log(mpt, CE_WARN, "mptsas unable to "
+			    "create property for SAS target %d lun %d "
+			    "(port-wwn)", target, lun);
+			ndi_rtn = NDI_FAILURE;
+			goto phys_create_done;
+		} else if ((sas_wwn == 0) && (ndi_prop_update_int(
+		    DDI_DEV_T_NONE, *lun_dip, "sata-phy", phy) !=
+		    DDI_PROP_SUCCESS)) {
+			/*
+			 * Direct attached SATA device without DeviceName
+			 */
+			mptsas_log(mpt, CE_WARN, "mptsas unable to "
+			    "create property for SAS target %d lun %d "
+			    "(sata-phy)", target, lun);
+			ndi_rtn = NDI_FAILURE;
+			goto phys_create_done;
+		}
+		if (ndi_prop_create_boolean(DDI_DEV_T_NONE,
+		    *lun_dip, SAS_PROP) != DDI_PROP_SUCCESS) {
+			mptsas_log(mpt, CE_WARN, "mptsas unable to"
+			    "create property for SAS target %d lun %d"
+			    " (SAS_PROP)", target, lun);
+			ndi_rtn = NDI_FAILURE;
+			goto phys_create_done;
+		}
+		if (guid && (ndi_prop_update_string(DDI_DEV_T_NONE,
+		    *lun_dip, NDI_GUID, guid) != DDI_SUCCESS)) {
+			mptsas_log(mpt, CE_WARN, "mptsas unable "
+			    "to create guid property for target %d "
+			    "lun %d", target, lun);
+			ndi_rtn = NDI_FAILURE;
+			goto phys_create_done;
+		}
+
+		/*
+		 * if this is a SAS controller, and the target is a SATA
+		 * drive, set the 'pm-capable' property for sd and if on
+		 * an OPL platform, also check if this is an ATAPI
+		 * device.
+		 */
+		instance = ddi_get_instance(mpt->m_dip);
+		if (devinfo & (MPI2_SAS_DEVICE_INFO_SATA_DEVICE |
+		    MPI2_SAS_DEVICE_INFO_ATAPI_DEVICE)) {
+			NDBG2(("mptsas%d: creating pm-capable property, "
+			    "target %d", instance, target));
+
+			if ((ndi_prop_update_int(DDI_DEV_T_NONE,
+			    *lun_dip, "pm-capable", 1)) !=
+			    DDI_PROP_SUCCESS) {
+				mptsas_log(mpt, CE_WARN, "mptsas "
+				    "failed to create pm-capable "
+				    "property, target %d", target);
+				ndi_rtn = NDI_FAILURE;
+				goto phys_create_done;
+			}
+
+		}
+
+		if (inq->inq_dtype == 0) {
+			/*
+			 * add 'obp-path' properties for devinfo
+			 */
+			component = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
+			if (sas_wwn) {
+				(void) snprintf(component, MAXPATHLEN,
+				    "disk@w%s,%x", wwn_str, lun);
+			} else {
+				(void) snprintf(component, MAXPATHLEN,
+				    "disk@p%x,%x", phy, lun);
+			}
+			if (ddi_pathname_obp_set(*lun_dip, component)
+			    != DDI_SUCCESS) {
+				mptsas_log(mpt, CE_WARN, "mpt_sas driver "
+				    "unable to set obp-path for SAS "
+				    "object %s", component);
+				ndi_rtn = NDI_FAILURE;
+				goto phys_create_done;
+			}
+		}
+
+phys_create_done:
+		/*
+		 * If props were setup ok, online the lun
+		 */
+		if (ndi_rtn == NDI_SUCCESS) {
+			/*
+			 * Try to online the new node
+			 */
+			ndi_rtn = ndi_devi_online(*lun_dip, NDI_ONLINE_ATTACH);
+		}
+
+		/*
+		 * If success set rtn flag, else unwire alloc'd lun
+		 */
+		if (ndi_rtn != NDI_SUCCESS) {
+			NDBG12(("mptsas driver unable to online "
+			    "target %d lun %d", target, lun));
+			ndi_prop_remove_all(*lun_dip);
+			(void) ndi_devi_free(*lun_dip);
+			*lun_dip = NULL;
+		}
+	}
+
+	scsi_hba_nodename_compatible_free(nodename, compatible);
+
+	if (wwn_str != NULL) {
+		kmem_free(wwn_str, MPTSAS_WWN_STRLEN);
+	}
+	if (component != NULL) {
+		kmem_free(component, MAXPATHLEN);
+	}
+
+	return ((ndi_rtn == NDI_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE);
+}
+
+static int
+mptsas_probe_smp(dev_info_t *pdip, uint64_t wwn)
+{
+	struct smp_device smp;
+
+	bzero(&smp, sizeof (struct smp_device));
+	smp.smp_addr.a_hba_tran = ndi_flavorv_get(pdip, SCSA_FLAVOR_SMP);
+	bcopy(&wwn, smp.smp_addr.a_wwn, SAS_WWN_BYTE_SIZE);
+
+	if (sas_hba_probe_smp(&smp) != DDI_PROBE_SUCCESS) {
+		return (NDI_FAILURE);
+	}
+	return (NDI_SUCCESS);
+}
+
+static int
+mptsas_config_smp(dev_info_t *pdip, uint64_t sas_wwn, dev_info_t **smp_dip)
+{
+	mptsas_t	*mpt = DIP2MPT(pdip);
+	mptsas_smp_t	*psmp = NULL;
+	int		rval;
+	int		phymask;
+
+	/*
+	 * Get the physical port associated to the iport
+	 * PHYMASK TODO
+	 */
+	phymask = ddi_prop_get_int(DDI_DEV_T_ANY, pdip, 0,
+	    "phymask", 0);
+	/*
+	 * Find the smp node in hash table with specified sas address and
+	 * physical port
+	 */
+	psmp = mptsas_wwid_to_psmp(mpt, phymask, sas_wwn);
+	if (psmp == NULL) {
+		return (DDI_FAILURE);
+	}
+
+	rval = mptsas_online_smp(pdip, psmp, smp_dip);
+
+	return (rval);
+}
+
+static int
+mptsas_online_smp(dev_info_t *pdip, mptsas_smp_t *smp_node,
+    dev_info_t **smp_dip)
+{
+	char		wwn_str[MPTSAS_WWN_STRLEN];
+	int		ndi_rtn = NDI_FAILURE;
+	mptsas_t	*mpt = DIP2MPT(pdip);
+
+	(void) sprintf(wwn_str, "%"PRIx64, smp_node->m_sasaddr);
+
+	/*
+	 * Probe smp device, prevent the node of removed device from being
+	 * configured succesfully
+	 */
+	if (mptsas_probe_smp(pdip, smp_node->m_sasaddr) != NDI_SUCCESS) {
+		return (DDI_FAILURE);
+	}
+
+	if ((*smp_dip = mptsas_find_smp_child(pdip, wwn_str)) != NULL) {
+		return (DDI_SUCCESS);
+	}
+
+	ndi_rtn = ndi_devi_alloc(pdip, "smp", DEVI_SID_NODEID, smp_dip);
+
+	/*
+	 * if lun alloc success, set props
+	 */
+	if (ndi_rtn == NDI_SUCCESS) {
+		/*
+		 * Set the flavor of the child to be SMP flavored
+		 */
+		ndi_flavor_set(*smp_dip, SCSA_FLAVOR_SMP);
+
+		if (ndi_prop_update_string(DDI_DEV_T_NONE,
+		    *smp_dip, SMP_WWN, wwn_str) !=
+		    DDI_PROP_SUCCESS) {
+			mptsas_log(mpt, CE_WARN, "mptsas unable to create "
+			    "property for smp device %s (sas_wwn)",
+			    wwn_str);
+			ndi_rtn = NDI_FAILURE;
+			goto smp_create_done;
+		}
+
+		if (ndi_prop_create_boolean(DDI_DEV_T_NONE,
+		    *smp_dip, SMP_PROP) != DDI_PROP_SUCCESS) {
+			mptsas_log(mpt, CE_WARN, "mptsas unable to "
+			    "create property for SMP %s (SMP_PROP) ",
+			    wwn_str);
+			ndi_rtn = NDI_FAILURE;
+			goto smp_create_done;
+		}
+
+smp_create_done:
+		/*
+		 * If props were setup ok, online the lun
+		 */
+		if (ndi_rtn == NDI_SUCCESS) {
+			/*
+			 * Try to online the new node
+			 */
+			ndi_rtn = ndi_devi_online(*smp_dip, NDI_ONLINE_ATTACH);
+		}
+
+		/*
+		 * If success set rtn flag, else unwire alloc'd lun
+		 */
+		if (ndi_rtn != NDI_SUCCESS) {
+			NDBG12(("mptsas unable to online "
+			    "SMP target %s", wwn_str));
+			ndi_prop_remove_all(*smp_dip);
+			(void) ndi_devi_free(*smp_dip);
+		}
+	}
+
+	return ((ndi_rtn == NDI_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE);
+}
+
+/*ARGSUSED*/
+static int mptsas_getcap(struct sas_addr *ap, char *cap)
+{
+	int	ckey = -1;
+	int	ret = EINVAL;
+
+	ckey = sas_hba_lookup_capstr(cap);
+	if (ckey == -1)
+		return (EINVAL);
+
+	switch (ckey) {
+	case SAS_CAP_SMP_CRC:
+		/*
+		 * mpt controller support generate CRC for
+		 * SMP passthrough frame and handle CRC by
+		 * IOC itself.
+		 */
+		ret = 0;
+		break;
+	default:
+		ret = EINVAL;
+		break;
+	}
+	return (ret);
+}
+
+/* smp transport routine */
+static int mptsas_smp_start(struct smp_pkt *pktp)
+{
+	uint64_t			wwn;
+	Mpi2SmpPassthroughRequest_t	req;
+	Mpi2SmpPassthroughReply_t	rep;
+	uint32_t			direction = 0;
+	mptsas_t			*mpt;
+	int				ret;
+	uint64_t			tmp64;
+
+	mpt = (mptsas_t *)pktp->pkt_address->a_hba_tran->tran_hba_private;
+
+	bcopy(pktp->pkt_address->a_wwn, &wwn, SAS_WWN_BYTE_SIZE);
+	/*
+	 * Need to compose a SMP request message
+	 * and call mptsas_do_passthru() function
+	 */
+	bzero(&req, sizeof (req));
+	bzero(&rep, sizeof (rep));
+	req.PassthroughFlags = 0;
+	req.PhysicalPort = 0xff;
+	req.ChainOffset = 0;
+	req.Function = MPI2_FUNCTION_SMP_PASSTHROUGH;
+
+	if ((pktp->pkt_reqsize & 0xffff0000ul) != 0) {
+		pktp->pkt_reason = ERANGE;
+		return (DDI_FAILURE);
+	}
+	req.RequestDataLength = LE_16((uint16_t)(pktp->pkt_reqsize - 4));
+
+	req.MsgFlags = 0;
+	tmp64 = LE_64(wwn);
+	bcopy(&tmp64, &req.SASAddress, SAS_WWN_BYTE_SIZE);
+	if (pktp->pkt_rspsize > 0) {
+		direction |= MPTSAS_PASS_THRU_DIRECTION_READ;
+	}
+	if (pktp->pkt_reqsize > 0) {
+		direction |= MPTSAS_PASS_THRU_DIRECTION_WRITE;
+	}
+
+	mutex_enter(&mpt->m_mutex);
+	ret = mptsas_do_passthru(mpt, (uint8_t *)&req, (uint8_t *)&rep,
+	    (uint8_t *)pktp->pkt_rsp, offsetof(Mpi2SmpPassthroughRequest_t,
+	    SGL), sizeof (rep), pktp->pkt_rspsize - 4, direction,
+	    (uint8_t *)pktp->pkt_req, pktp->pkt_reqsize - 4,
+	    pktp->pkt_timeout, FKIOCTL);
+	mutex_exit(&mpt->m_mutex);
+	if (ret != 0) {
+		cmn_err(CE_WARN, "smp_start do passthru error %d", ret);
+		pktp->pkt_reason = (uchar_t)(ret);
+		return (DDI_FAILURE);
+	}
+	/* do passthrough success, check the smp status */
+	if (LE_16(rep.IOCStatus) != MPI2_IOCSTATUS_SUCCESS) {
+		switch (LE_16(rep.IOCStatus)) {
+		case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
+			pktp->pkt_reason = ENODEV;
+			break;
+		case MPI2_IOCSTATUS_SAS_SMP_DATA_OVERRUN:
+			pktp->pkt_reason = EOVERFLOW;
+			break;
+		case MPI2_IOCSTATUS_SAS_SMP_REQUEST_FAILED:
+			pktp->pkt_reason = EIO;
+			break;
+		default:
+			mptsas_log(mpt, CE_NOTE, "smp_start: get unknown ioc"
+			    "status:%x", LE_16(rep.IOCStatus));
+			pktp->pkt_reason = EIO;
+			break;
+		}
+		return (DDI_FAILURE);
+	}
+	if (rep.SASStatus != MPI2_SASSTATUS_SUCCESS) {
+		mptsas_log(mpt, CE_NOTE, "smp_start: get error SAS status:%x",
+		    rep.SASStatus);
+		pktp->pkt_reason = EIO;
+		return (DDI_FAILURE);
+	}
+
+	return (DDI_SUCCESS);
+}
+
+static void
+mptsas_idle_pm(void *arg)
+{
+	mptsas_t	*mpt = arg;
+
+	(void) pm_idle_component(mpt->m_dip, 0);
+	mutex_enter(&mpt->m_mutex);
+	mpt->m_pm_timeid = 0;
+	mutex_exit(&mpt->m_mutex);
+}
+
+/*
+ * If we didn't get a match, we need to get sas page0 for each device, and
+ * untill we get a match. If failed, return NULL
+ * TODO should be implemented similar to mptsas_wwid_to_ptgt?
+ */
+static mptsas_target_t *
+mptsas_phy_to_tgt(dev_info_t *pdip, uint8_t phy)
+{
+	int		i, j = 0;
+	int		rval = 0;
+	uint16_t	cur_handle;
+	uint32_t	page_address;
+	mptsas_target_t	*ptgt = NULL;
+	mptsas_t	*mpt = DIP2MPT(pdip);
+	int		phymask;
+
+	/*
+	 * Get the physical port associated to the iport
+	 */
+	phymask = ddi_prop_get_int(DDI_DEV_T_ANY, pdip, 0,
+	    "phymask", 0);
+
+	if (phymask == 0)
+		return (NULL);
+
+	/*
+	 * PHY named device must be direct attached and attaches to
+	 * narrow port, if the iport is not parent of the device which
+	 * we are looking for.
+	 */
+	for (i = 0; i < MPTSAS_MAX_PHYS; i++) {
+		if ((1 << i) & phymask)
+			j++;
+	}
+
+	if (j > 1)
+		return (NULL);
+
+	/*
+	 * Must be a narrow port and single device attached to the narrow port
+	 * So the physical port num of device  which is equal to the iport's
+	 * port num is the device what we are looking for.
+	 */
+
+	if (mpt->m_phy_info[phy].phy_mask != phymask)
+		return (NULL);
+
+	mutex_enter(&mpt->m_mutex);
+
+	ptgt = (mptsas_target_t *)mptsas_hash_traverse(&mpt->m_active->m_tgttbl,
+	    MPTSAS_HASH_FIRST);
+	while (ptgt != NULL) {
+			if ((ptgt->m_sas_wwn == 0) && (ptgt->m_phynum == phy)) {
+			mutex_exit(&mpt->m_mutex);
+			return (ptgt);
+		}
+
+		ptgt = (mptsas_target_t *)mptsas_hash_traverse(
+		    &mpt->m_active->m_tgttbl, MPTSAS_HASH_NEXT);
+	}
+
+	if (mpt->m_done_traverse_dev) {
+		mutex_exit(&mpt->m_mutex);
+		return (NULL);
+	}
+
+	/* If didn't get a match, come here */
+	cur_handle = mpt->m_dev_handle;
+	for (; ; ) {
+		ptgt = NULL;
+		page_address = (MPI2_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE &
+		    MPI2_SAS_DEVICE_PGAD_FORM_MASK) | (uint32_t)cur_handle;
+		rval = mptsas_get_target_device_info(mpt, page_address,
+		    &cur_handle, &ptgt);
+		if ((rval == DEV_INFO_FAIL_PAGE0) ||
+		    (rval == DEV_INFO_FAIL_ALLOC)) {
+			break;
+		}
+		if ((rval == DEV_INFO_WRONG_DEVICE_TYPE) ||
+		    (rval == DEV_INFO_PHYS_DISK)) {
+			continue;
+		}
+		mpt->m_dev_handle = cur_handle;
+
+		if ((ptgt->m_sas_wwn == 0) && (ptgt->m_phynum == phy)) {
+			break;
+		}
+	}
+
+	mutex_exit(&mpt->m_mutex);
+	return (ptgt);
+}
+
+/*
+ * The ptgt->m_sas_wwn contains the wwid for each disk.
+ * For Raid volumes, we need to check m_raidvol[x].m_raidwwid
+ * If we didn't get a match, we need to get sas page0 for each device, and
+ * untill we get a match
+ * If failed, return NULL
+ */
+static mptsas_target_t *
+mptsas_wwid_to_ptgt(mptsas_t *mpt, int phymask, uint64_t wwid)
+{
+	int		rval = 0;
+	uint16_t	cur_handle;
+	uint32_t	page_address;
+	mptsas_target_t	*tmp_tgt = NULL;
+
+	mutex_enter(&mpt->m_mutex);
+	tmp_tgt = (struct mptsas_target *)mptsas_hash_search(
+	    &mpt->m_active->m_tgttbl, wwid, phymask);
+	if (tmp_tgt != NULL) {
+		mutex_exit(&mpt->m_mutex);
+		return (tmp_tgt);
+	}
+
+	if (phymask == 0) {
+		/*
+		 * It's IR volume
+		 */
+		rval = mptsas_get_raid_info(mpt);
+		if (rval) {
+			tmp_tgt = (struct mptsas_target *)mptsas_hash_search(
+			    &mpt->m_active->m_tgttbl, wwid, phymask);
+		}
+		mutex_exit(&mpt->m_mutex);
+		return (tmp_tgt);
+	}
+
+	if (mpt->m_done_traverse_dev) {
+		mutex_exit(&mpt->m_mutex);
+		return (NULL);
+	}
+
+	/* If didn't get a match, come here */
+	cur_handle = mpt->m_dev_handle;
+	for (; ; ) {
+		tmp_tgt = NULL;
+		page_address = (MPI2_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE &
+		    MPI2_SAS_DEVICE_PGAD_FORM_MASK) | cur_handle;
+		rval = mptsas_get_target_device_info(mpt, page_address,
+		    &cur_handle, &tmp_tgt);
+		if ((rval == DEV_INFO_FAIL_PAGE0) ||
+		    (rval == DEV_INFO_FAIL_ALLOC)) {
+			tmp_tgt = NULL;
+			break;
+		}
+		if ((rval == DEV_INFO_WRONG_DEVICE_TYPE) ||
+		    (rval == DEV_INFO_PHYS_DISK)) {
+			continue;
+		}
+		mpt->m_dev_handle = cur_handle;
+		if ((tmp_tgt->m_sas_wwn) && (tmp_tgt->m_sas_wwn == wwid) &&
+		    (tmp_tgt->m_phymask == phymask)) {
+			break;
+		}
+	}
+
+	mutex_exit(&mpt->m_mutex);
+	return (tmp_tgt);
+}
+
+static mptsas_smp_t *
+mptsas_wwid_to_psmp(mptsas_t *mpt, int phymask, uint64_t wwid)
+{
+	int		rval = 0;
+	uint16_t	cur_handle;
+	uint32_t	page_address;
+	mptsas_smp_t	smp_node, *psmp = NULL;
+
+	mutex_enter(&mpt->m_mutex);
+	psmp = (struct mptsas_smp *)mptsas_hash_search(&mpt->m_active->m_smptbl,
+	    wwid, phymask);
+	if (psmp != NULL) {
+		mutex_exit(&mpt->m_mutex);
+		return (psmp);
+	}
+
+	if (mpt->m_done_traverse_smp) {
+		mutex_exit(&mpt->m_mutex);
+		return (NULL);
+	}
+
+	/* If didn't get a match, come here */
+	cur_handle = mpt->m_smp_devhdl;
+	for (; ; ) {
+		psmp = NULL;
+		page_address = (MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL &
+		    MPI2_SAS_EXPAND_PGAD_FORM_MASK) | (uint32_t)cur_handle;
+		rval = mptsas_get_sas_expander_page0(mpt, page_address,
+		    &smp_node);
+		if (rval != DDI_SUCCESS) {
+			break;
+		}
+		mpt->m_smp_devhdl = cur_handle = smp_node.m_devhdl;
+		psmp = mptsas_smp_alloc(&mpt->m_active->m_smptbl, &smp_node);
+		ASSERT(psmp);
+		if ((psmp->m_sasaddr) && (psmp->m_sasaddr == wwid) &&
+		    (psmp->m_phymask == phymask)) {
+			break;
+		}
+	}
+
+	mutex_exit(&mpt->m_mutex);
+	return (psmp);
+}
+
+/* helper functions using hash */
+
+/*
+ * Can't have duplicate entries for same devhdl,
+ * if there are invalid entries, the devhdl should be set to 0xffff
+ */
+static void *
+mptsas_search_by_devhdl(mptsas_hash_table_t *hashtab, uint16_t devhdl)
+{
+	mptsas_hash_data_t *data;
+
+	data = mptsas_hash_traverse(hashtab, MPTSAS_HASH_FIRST);
+	while (data != NULL) {
+		if (data->devhdl == devhdl) {
+			break;
+		}
+		data = mptsas_hash_traverse(hashtab, MPTSAS_HASH_NEXT);
+	}
+	return (data);
+}
+
+mptsas_target_t *
+mptsas_tgt_alloc(mptsas_hash_table_t *hashtab, uint16_t devhdl, uint64_t wwid,
+    uint32_t devinfo, uint8_t phymask, uint8_t phynum)
+{
+	mptsas_target_t *tmp_tgt = NULL;
+
+	tmp_tgt = mptsas_hash_search(hashtab, wwid, phymask);
+	if (tmp_tgt != NULL) {
+		NDBG20(("Hash item already exist"));
+		tmp_tgt->m_deviceinfo = devinfo;
+		tmp_tgt->m_devhdl = devhdl;
+		return (tmp_tgt);
+	}
+	tmp_tgt = kmem_zalloc(sizeof (struct mptsas_target), KM_SLEEP);
+	if (tmp_tgt == NULL) {
+		cmn_err(CE_WARN, "Fatal, allocated tgt failed");
+		return (NULL);
+	}
+	tmp_tgt->m_devhdl = devhdl;
+	tmp_tgt->m_sas_wwn = wwid;
+	tmp_tgt->m_deviceinfo = devinfo;
+	tmp_tgt->m_phymask = phymask;
+	tmp_tgt->m_phynum = phynum;
+	/* Initialized the tgt structure */
+	tmp_tgt->m_qfull_retries = QFULL_RETRIES;
+	tmp_tgt->m_qfull_retry_interval =
+	    drv_usectohz(QFULL_RETRY_INTERVAL * 1000);
+	tmp_tgt->m_t_throttle = MAX_THROTTLE;
+
+	mptsas_hash_add(hashtab, tmp_tgt);
+
+	return (tmp_tgt);
+}
+
+static void
+mptsas_tgt_free(mptsas_hash_table_t *hashtab, uint64_t wwid, uint8_t phymask)
+{
+	mptsas_target_t *tmp_tgt;
+	tmp_tgt = mptsas_hash_rem(hashtab, wwid, phymask);
+	if (tmp_tgt == NULL) {
+		cmn_err(CE_WARN, "Tgt not found, nothing to free");
+	} else {
+		kmem_free(tmp_tgt, sizeof (struct mptsas_target));
+	}
+}
+
+/*
+ * Return the entry in the hash table
+ */
+static mptsas_smp_t *
+mptsas_smp_alloc(mptsas_hash_table_t *hashtab, mptsas_smp_t *data)
+{
+	uint64_t key1 = data->m_sasaddr;
+	uint8_t key2 = data->m_phymask;
+	mptsas_smp_t *ret_data;
+
+	ret_data = mptsas_hash_search(hashtab, key1, key2);
+	if (ret_data != NULL) {
+		bcopy(data, ret_data, sizeof (mptsas_smp_t));
+		return (ret_data);
+	}
+
+	ret_data = kmem_alloc(sizeof (mptsas_smp_t), KM_SLEEP);
+	bcopy(data, ret_data, sizeof (mptsas_smp_t));
+	mptsas_hash_add(hashtab, ret_data);
+	return (ret_data);
+}
+
+static void
+mptsas_smp_free(mptsas_hash_table_t *hashtab, uint64_t wwid, uint8_t phymask)
+{
+	mptsas_smp_t *tmp_smp;
+	tmp_smp = mptsas_hash_rem(hashtab, wwid, phymask);
+	if (tmp_smp == NULL) {
+		cmn_err(CE_WARN, "Smp element not found, nothing to free");
+	} else {
+		kmem_free(tmp_smp, sizeof (struct mptsas_smp));
+	}
+}
+
+/*
+ * Hash operation functions
+ * key1 is the sas_wwn, key2 is the phymask
+ */
+static void
+mptsas_hash_init(mptsas_hash_table_t *hashtab)
+{
+	if (hashtab == NULL) {
+		return;
+	}
+	bzero(hashtab->head, sizeof (mptsas_hash_node_t) *
+	    MPTSAS_HASH_ARRAY_SIZE);
+	hashtab->cur = NULL;
+	hashtab->line = 0;
+}
+
+static void
+mptsas_hash_uninit(mptsas_hash_table_t *hashtab, size_t datalen)
+{
+	uint16_t line = 0;
+	mptsas_hash_node_t *cur = NULL, *last = NULL;
+
+	if (hashtab == NULL) {
+		return;
+	}
+	for (line = 0; line < MPTSAS_HASH_ARRAY_SIZE; line++) {
+		cur = hashtab->head[line];
+		while (cur != NULL) {
+			last = cur;
+			cur = cur->next;
+			kmem_free(last->data, datalen);
+			kmem_free(last, sizeof (mptsas_hash_node_t));
+		}
+	}
+}
+
+/*
+ * You must guarantee the element doesn't exist in the hash table
+ * before you call mptsas_hash_add()
+ */
+static void
+mptsas_hash_add(mptsas_hash_table_t *hashtab, void *data)
+{
+	uint64_t key1 = ((mptsas_hash_data_t *)data)->key1;
+	uint8_t	key2 = ((mptsas_hash_data_t *)data)->key2;
+	mptsas_hash_node_t **head = NULL;
+	mptsas_hash_node_t *node = NULL;
+
+	if (hashtab == NULL) {
+		return;
+	}
+	ASSERT(mptsas_hash_search(hashtab, key1, key2) == NULL);
+	node = kmem_zalloc(sizeof (mptsas_hash_node_t), KM_NOSLEEP);
+	node->data = data;
+
+	head = &(hashtab->head[key1 % MPTSAS_HASH_ARRAY_SIZE]);
+	if (*head == NULL) {
+		*head = node;
+	} else {
+		node->next = *head;
+		*head = node;
+	}
+}
+
+static void *
+mptsas_hash_rem(mptsas_hash_table_t *hashtab, uint64_t key1, uint8_t key2)
+{
+	mptsas_hash_node_t **head = NULL;
+	mptsas_hash_node_t *last = NULL, *cur = NULL;
+	mptsas_hash_data_t *data;
+	if (hashtab == NULL) {
+		return (NULL);
+	}
+	head = &(hashtab->head[key1 % MPTSAS_HASH_ARRAY_SIZE]);
+	cur = *head;
+	while (cur != NULL) {
+		data = cur->data;
+		if ((data->key1 == key1) && (data->key2 == key2)) {
+			if (last == NULL) {
+				(*head) = cur->next;
+			} else {
+				last->next = cur->next;
+			}
+			kmem_free(cur, sizeof (mptsas_hash_node_t));
+			return (data);
+		} else {
+			last = cur;
+			cur = cur->next;
+		}
+	}
+	return (NULL);
+}
+
+static void *
+mptsas_hash_search(mptsas_hash_table_t *hashtab, uint64_t key1, uint8_t key2)
+{
+	mptsas_hash_node_t *cur = NULL;
+	mptsas_hash_data_t *data;
+	if (hashtab == NULL) {
+		return (NULL);
+	}
+	cur = hashtab->head[key1 % MPTSAS_HASH_ARRAY_SIZE];
+	while (cur != NULL) {
+		data = cur->data;
+		if ((data->key1 == key1) && (data->key2 == key2)) {
+			return (data);
+		} else {
+			cur = cur->next;
+		}
+	}
+	return (NULL);
+}
+
+static void *
+mptsas_hash_traverse(mptsas_hash_table_t *hashtab, int pos)
+{
+	mptsas_hash_node_t *this = NULL;
+
+	if (hashtab == NULL) {
+		return (NULL);
+	}
+
+	if (pos == MPTSAS_HASH_FIRST) {
+		hashtab->line = 0;
+		hashtab->cur = NULL;
+		this = hashtab->head[0];
+	} else {
+		if (hashtab->cur == NULL) {
+			return (NULL);
+		} else {
+			this = hashtab->cur->next;
+		}
+	}
+
+	while (this == NULL) {
+		hashtab->line++;
+		if (hashtab->line >= MPTSAS_HASH_ARRAY_SIZE) {
+			/* the traverse reaches the end */
+			hashtab->cur = NULL;
+			return (NULL);
+		} else {
+			this = hashtab->head[hashtab->line];
+		}
+	}
+	hashtab->cur = this;
+	return (this->data);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas_impl.c	Fri Jun 19 20:12:07 2009 +0800
@@ -0,0 +1,2643 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Copyright (c) 2000 to 2009, LSI Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms of all code within
+ * this file that is exclusively owned by LSI, with or without
+ * modification, is permitted provided that, in addition to the CDDL 1.0
+ * License requirements, the following conditions are met:
+ *
+ *    Neither the name of the author nor the names of its contributors may be
+ *    used to endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ */
+
+/*
+ * mptsas_impl - This file contains all the basic functions for communicating
+ * to MPT based hardware.
+ */
+
+#if defined(lint) || defined(DEBUG)
+#define	MPTSAS_DEBUG
+#endif
+
+/*
+ * standard header files
+ */
+#include <sys/note.h>
+#include <sys/scsi/scsi.h>
+#include <sys/pci.h>
+
+#pragma pack(1)
+#include <sys/scsi/adapters/mpt_sas/mpi/mpi2_type.h>
+#include <sys/scsi/adapters/mpt_sas/mpi/mpi2.h>
+#include <sys/scsi/adapters/mpt_sas/mpi/mpi2_cnfg.h>
+#include <sys/scsi/adapters/mpt_sas/mpi/mpi2_init.h>
+#include <sys/scsi/adapters/mpt_sas/mpi/mpi2_ioc.h>
+#include <sys/scsi/adapters/mpt_sas/mpi/mpi2_sas.h>
+#pragma pack()
+
+/*
+ * private header files.
+ */
+#include <sys/scsi/adapters/mpt_sas/mptsas_var.h>
+
+/*
+ * FMA header files.
+ */
+#include <sys/fm/io/ddi.h>
+
+#if defined(MPTSAS_DEBUG)
+extern uint32_t mptsas_debug_flags;
+#endif
+
+/*
+ *  prototypes
+ */
+static void mptsas_ioc_event_cmdq_add(mptsas_t *mpt, m_event_struct_t *cmd);
+static void mptsas_ioc_event_cmdq_delete(mptsas_t *mpt, m_event_struct_t *cmd);
+static m_event_struct_t *mptsas_ioc_event_find_by_cmd(mptsas_t *mpt,
+    struct mptsas_cmd *cmd);
+
+/*
+ * add ioc evnet cmd into the queue
+ */
+static void
+mptsas_ioc_event_cmdq_add(mptsas_t *mpt, m_event_struct_t *cmd)
+{
+	if ((cmd->m_event_linkp = mpt->m_ioc_event_cmdq) == NULL) {
+		mpt->m_ioc_event_cmdtail = &cmd->m_event_linkp;
+		mpt->m_ioc_event_cmdq = cmd;
+	} else {
+		cmd->m_event_linkp = NULL;
+		*(mpt->m_ioc_event_cmdtail) = cmd;
+		mpt->m_ioc_event_cmdtail = &cmd->m_event_linkp;
+	}
+}
+
+/*
+ * remove specified cmd from the ioc event queue
+ */
+static void
+mptsas_ioc_event_cmdq_delete(mptsas_t *mpt, m_event_struct_t *cmd)
+{
+	m_event_struct_t	*prev = mpt->m_ioc_event_cmdq;
+	if (prev == cmd) {
+		if ((mpt->m_ioc_event_cmdq = cmd->m_event_linkp) == NULL) {
+			mpt->m_ioc_event_cmdtail = &mpt->m_ioc_event_cmdq;
+		}
+		cmd->m_event_linkp = NULL;
+		return;
+	}
+	while (prev != NULL) {
+		if (prev->m_event_linkp == cmd) {
+			prev->m_event_linkp = cmd->m_event_linkp;
+			if (cmd->m_event_linkp == NULL) {
+				mpt->m_ioc_event_cmdtail = &prev->m_event_linkp;
+			}
+
+			cmd->m_event_linkp = NULL;
+			return;
+		}
+		prev = prev->m_event_linkp;
+	}
+}
+
+static m_event_struct_t *
+mptsas_ioc_event_find_by_cmd(mptsas_t *mpt, struct mptsas_cmd *cmd)
+{
+	m_event_struct_t	*ioc_cmd = NULL;
+
+	ioc_cmd = mpt->m_ioc_event_cmdq;
+	while (ioc_cmd != NULL) {
+		if (&(ioc_cmd->m_event_cmd) == cmd) {
+			return (ioc_cmd);
+		}
+		ioc_cmd = ioc_cmd->m_event_linkp;
+	}
+	ioc_cmd = NULL;
+	return (ioc_cmd);
+}
+
+void
+mptsas_destroy_ioc_event_cmd(mptsas_t *mpt)
+{
+	m_event_struct_t	*ioc_cmd = NULL;
+	m_event_struct_t	*ioc_cmd_tmp = NULL;
+	ioc_cmd = mpt->m_ioc_event_cmdq;
+
+	/*
+	 * because the IOC event queue is resource of per instance for driver,
+	 * it's not only ACK event commands used it, but also some others used
+	 * it. We need destroy all ACK event commands when IOC reset, but can't
+	 * disturb others.So we use filter to clear the ACK event cmd in ioc
+	 * event queue, and other requests should be reserved, and they would
+	 * be free by its owner.
+	 */
+	while (ioc_cmd != NULL) {
+		if (ioc_cmd->m_event_cmd.cmd_flags & CFLAG_CMDACK) {
+			NDBG20(("destroy!! remove Ack Flag ioc_cmd\n"));
+			if ((mpt->m_ioc_event_cmdq =
+			    ioc_cmd->m_event_linkp) == NULL)
+				mpt->m_ioc_event_cmdtail =
+				    &mpt->m_ioc_event_cmdq;
+			ioc_cmd_tmp = ioc_cmd;
+			ioc_cmd = ioc_cmd->m_event_linkp;
+			kmem_free(ioc_cmd_tmp, M_EVENT_STRUCT_SIZE);
+		} else {
+			/*
+			 * it's not ack cmd, so continue to check next one
+			 */
+
+			NDBG20(("destroy!! it's not Ack Flag, continue\n"));
+			ioc_cmd = ioc_cmd->m_event_linkp;
+		}
+
+	}
+}
+
+void
+mptsas_start_config_page_access(mptsas_t *mpt, mptsas_cmd_t *cmd)
+{
+	pMpi2ConfigRequest_t	request;
+	pMpi2SGESimple64_t	sge;
+	struct scsi_pkt		*pkt = cmd->cmd_pkt;
+	mptsas_config_request_t	*config = pkt->pkt_ha_private;
+	uint8_t			direction;
+	uint32_t		length, flagslength, request_desc_low;
+
+	ASSERT(mutex_owned(&mpt->m_mutex));
+
+	/*
+	 * Point to the correct message and clear it as well as the global
+	 * config page memory.
+	 */
+	request = (pMpi2ConfigRequest_t)(mpt->m_req_frame +
+	    (mpt->m_req_frame_size * cmd->cmd_slot));
+	bzero(request, mpt->m_req_frame_size);
+
+	/*
+	 * Form the request message.
+	 */
+	ddi_put8(mpt->m_acc_req_frame_hdl, &request->Function,
+	    MPI2_FUNCTION_CONFIG);
+	ddi_put8(mpt->m_acc_req_frame_hdl, &request->Action, config->action);
+	direction = MPI2_SGE_FLAGS_IOC_TO_HOST;
+	length = 0;
+	sge = (pMpi2SGESimple64_t)&request->PageBufferSGE;
+	if (config->action == MPI2_CONFIG_ACTION_PAGE_HEADER) {
+		if (config->page_type > MPI2_CONFIG_PAGETYPE_MASK) {
+			ddi_put8(mpt->m_acc_req_frame_hdl,
+			    &request->Header.PageType,
+			    MPI2_CONFIG_PAGETYPE_EXTENDED);
+			ddi_put8(mpt->m_acc_req_frame_hdl,
+			    &request->ExtPageType, config->page_type);
+		} else {
+			ddi_put8(mpt->m_acc_req_frame_hdl,
+			    &request->Header.PageType, config->page_type);
+		}
+	} else {
+		ddi_put8(mpt->m_acc_req_frame_hdl, &request->ExtPageType,
+		    config->ext_page_type);
+		ddi_put16(mpt->m_acc_req_frame_hdl, &request->ExtPageLength,
+		    config->ext_page_length);
+		ddi_put8(mpt->m_acc_req_frame_hdl, &request->Header.PageType,
+		    config->page_type);
+		ddi_put8(mpt->m_acc_req_frame_hdl, &request->Header.PageLength,
+		    config->page_length);
+		ddi_put8(mpt->m_acc_req_frame_hdl,
+		    &request->Header.PageVersion, config->page_version);
+		if ((config->page_type & MPI2_CONFIG_PAGETYPE_MASK) ==
+		    MPI2_CONFIG_PAGETYPE_EXTENDED) {
+			length = config->ext_page_length * 4;
+		} else {
+			length = config->page_length * 4;
+		}
+
+		if (config->action == MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM) {
+			direction = MPI2_SGE_FLAGS_HOST_TO_IOC;
+		}
+		ddi_put32(mpt->m_acc_req_frame_hdl, &sge->Address.Low,
+		    (uint32_t)cmd->cmd_dma_addr);
+		ddi_put32(mpt->m_acc_req_frame_hdl, &sge->Address.High,
+		    (uint32_t)(cmd->cmd_dma_addr >> 32));
+	}
+	ddi_put8(mpt->m_acc_req_frame_hdl, &request->Header.PageNumber,
+	    config->page_number);
+	ddi_put32(mpt->m_acc_req_frame_hdl, &request->PageAddress,
+	    config->page_address);
+	flagslength = ((uint32_t)(MPI2_SGE_FLAGS_LAST_ELEMENT |
+	    MPI2_SGE_FLAGS_END_OF_BUFFER |
+	    MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
+	    MPI2_SGE_FLAGS_SYSTEM_ADDRESS |
+	    MPI2_SGE_FLAGS_64_BIT_ADDRESSING |
+	    direction |
+	    MPI2_SGE_FLAGS_END_OF_LIST) << MPI2_SGE_FLAGS_SHIFT);
+	flagslength |= length;
+	ddi_put32(mpt->m_acc_req_frame_hdl, &sge->FlagsLength, flagslength);
+
+	(void) ddi_dma_sync(mpt->m_dma_req_frame_hdl, 0, 0,
+	    DDI_DMA_SYNC_FORDEV);
+	request_desc_low = (cmd->cmd_slot << 16) +
+	    MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
+	cmd->cmd_rfm = NULL;
+	MPTSAS_START_CMD(mpt, request_desc_low, 0);
+	if ((mptsas_check_dma_handle(mpt->m_dma_req_frame_hdl) !=
+	    DDI_SUCCESS) ||
+	    (mptsas_check_acc_handle(mpt->m_acc_req_frame_hdl) !=
+	    DDI_SUCCESS)) {
+		ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
+	}
+}
+
+int
+mptsas_access_config_page(mptsas_t *mpt, uint8_t action, uint8_t page_type,
+    uint8_t page_number, uint32_t page_address, int (*callback) (mptsas_t *,
+    caddr_t, ddi_acc_handle_t, uint16_t, uint32_t, va_list), ...)
+{
+	va_list			ap;
+	ddi_dma_attr_t		attrs;
+	uint_t			ncookie;
+	ddi_dma_cookie_t	cookie;
+	ddi_acc_handle_t	accessp;
+	size_t			len = 0, alloc_len;
+	mptsas_config_request_t	config;
+	int			rval = DDI_SUCCESS, config_flags = 0;
+	mptsas_cmd_t		*cmd;
+	struct scsi_pkt		*pkt;
+	uint32_t		reply_index;
+	pMpi2ConfigReply_t	reply;
+	uint16_t		iocstatus = 0;
+	uint32_t		iocloginfo;
+	caddr_t			page_memp;
+
+	va_start(ap, callback);
+	ASSERT(mutex_owned(&mpt->m_mutex));
+
+	/*
+	 * Get a command from the pool.
+	 */
+	if ((rval = (mptsas_request_from_pool(mpt, &cmd, &pkt))) == -1) {
+		mptsas_log(mpt, CE_NOTE, "command pool is full for config "
+		    "page request");
+		rval = DDI_FAILURE;
+		goto page_done;
+	}
+	config_flags |= MPTSAS_REQUEST_POOL_CMD;
+
+	bzero((caddr_t)cmd, sizeof (*cmd));
+	bzero((caddr_t)pkt, scsi_pkt_size());
+	bzero((caddr_t)&config, sizeof (config));
+
+	/*
+	 * Save the data for this request to be used in the call to start the
+	 * config header request.
+	 */
+	config.action = MPI2_CONFIG_ACTION_PAGE_HEADER;
+	config.page_type = page_type;
+	config.page_number = page_number;
+	config.page_address = page_address;
+
+	/*
+	 * Form a blank cmd/pkt to store the acknowledgement message
+	 */
+	pkt->pkt_ha_private	= (opaque_t)&config;
+	pkt->pkt_flags		= FLAG_HEAD;
+	pkt->pkt_time		= 60;
+	cmd->cmd_pkt		= pkt;
+	cmd->cmd_flags		= CFLAG_CMDIOC | CFLAG_CONFIG;
+
+	/*
+	 * Save the config header request message in a slot.
+	 */
+	if (mptsas_save_cmd(mpt, cmd) == TRUE) {
+		cmd->cmd_flags |= CFLAG_PREPARED;
+		mptsas_start_config_page_access(mpt, cmd);
+	} else {
+		mptsas_waitq_add(mpt, cmd);
+	}
+
+	/*
+	 * Wait for the command to complete or timeout.
+	 */
+	while ((cmd->cmd_flags & CFLAG_FINISHED) == 0) {
+		cv_wait(&mpt->m_config_cv, &mpt->m_mutex);
+	}
+
+	/*
+	 * Check if the header request completed without timing out
+	 */
+	if (cmd->cmd_flags & CFLAG_TIMEOUT) {
+		mptsas_log(mpt, CE_WARN, "config header request timeout");
+		rval = DDI_FAILURE;
+		goto page_done;
+	}
+
+	/*
+	 * cmd_rfm points to the reply message if a reply was given.  Check the
+	 * IOCStatus to make sure everything went OK with the header request.
+	 */
+	if (cmd->cmd_rfm) {
+		config_flags |= MPTSAS_ADDRESS_REPLY;
+		(void) ddi_dma_sync(mpt->m_dma_reply_frame_hdl, 0, 0,
+		    DDI_DMA_SYNC_FORCPU);
+		reply = (pMpi2ConfigReply_t)(mpt->m_reply_frame + (cmd->cmd_rfm
+		    - mpt->m_reply_frame_dma_addr));
+		config.page_type = ddi_get8(mpt->m_acc_reply_frame_hdl,
+		    &reply->Header.PageType);
+		config.page_number = ddi_get8(mpt->m_acc_reply_frame_hdl,
+		    &reply->Header.PageNumber);
+		config.page_length = ddi_get8(mpt->m_acc_reply_frame_hdl,
+		    &reply->Header.PageLength);
+		config.page_version = ddi_get8(mpt->m_acc_reply_frame_hdl,
+		    &reply->Header.PageVersion);
+		config.ext_page_type = ddi_get8(mpt->m_acc_reply_frame_hdl,
+		    &reply->ExtPageType);
+		config.ext_page_length = ddi_get16(mpt->m_acc_reply_frame_hdl,
+		    &reply->ExtPageLength);
+
+		iocstatus = ddi_get16(mpt->m_acc_reply_frame_hdl,
+		    &reply->IOCStatus);
+		iocloginfo = ddi_get32(mpt->m_acc_reply_frame_hdl,
+		    &reply->IOCLogInfo);
+
+		if (iocstatus) {
+			NDBG13(("mptsas_access_config_page header: "
+			    "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
+			    iocloginfo));
+			rval = DDI_FAILURE;
+			goto page_done;
+		}
+
+		if ((config.page_type & MPI2_CONFIG_PAGETYPE_MASK) ==
+		    MPI2_CONFIG_PAGETYPE_EXTENDED)
+			len = (config.ext_page_length * 4);
+		else
+			len = (config.page_length * 4);
+
+	}
+
+	if (pkt->pkt_reason == CMD_RESET) {
+		mptsas_log(mpt, CE_WARN, "ioc reset abort config header "
+		    "request");
+		rval = DDI_FAILURE;
+		goto page_done;
+	}
+
+	/*
+	 * Put the reply frame back on the free queue, increment the free
+	 * index, and write the new index to the free index register.  But only
+	 * if this reply is an ADDRESS reply.
+	 */
+	if (config_flags & MPTSAS_ADDRESS_REPLY) {
+		reply_index = mpt->m_free_index;
+		ddi_put32(mpt->m_acc_free_queue_hdl,
+		    &((uint32_t *)(void *)mpt->m_free_queue)[reply_index],
+		    cmd->cmd_rfm);
+		(void) ddi_dma_sync(mpt->m_dma_free_queue_hdl, 0, 0,
+		    DDI_DMA_SYNC_FORDEV);
+		if (++reply_index == mpt->m_free_queue_depth) {
+			reply_index = 0;
+		}
+		mpt->m_free_index = reply_index;
+		ddi_put32(mpt->m_datap, &mpt->m_reg->ReplyFreeHostIndex,
+		    reply_index);
+		config_flags &= (~MPTSAS_ADDRESS_REPLY);
+	}
+
+	/*
+	 * Allocate DMA buffer here.  Store the info regarding this buffer in
+	 * the cmd struct so that it can be used for this specific command and
+	 * de-allocated after the command completes.  The size of the reply
+	 * will not be larger than the reply frame size.
+	 */
+	attrs = mpt->m_msg_dma_attr;
+	attrs.dma_attr_sgllen = 1;
+	attrs.dma_attr_granular = (uint32_t)len;
+
+	if (ddi_dma_alloc_handle(mpt->m_dip, &attrs,
+	    DDI_DMA_SLEEP, NULL, &cmd->cmd_dmahandle) != DDI_SUCCESS) {
+		mptsas_log(mpt, CE_WARN, "unable to allocate dma handle for "
+		    "config page.");
+		rval = DDI_FAILURE;
+		goto page_done;
+	}
+	if (ddi_dma_mem_alloc(cmd->cmd_dmahandle, len,
+	    &mpt->m_dev_acc_attr, DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL,
+	    &page_memp, &alloc_len, &accessp) != DDI_SUCCESS) {
+		ddi_dma_free_handle(&cmd->cmd_dmahandle);
+		cmd->cmd_dmahandle = NULL;
+		mptsas_log(mpt, CE_WARN, "unable to allocate config page "
+		    "structure.");
+		rval = DDI_FAILURE;
+		goto page_done;
+	}
+
+	if (ddi_dma_addr_bind_handle(cmd->cmd_dmahandle, NULL, page_memp,
+	    alloc_len, DDI_DMA_RDWR | DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL,
+	    &cookie, &ncookie) != DDI_DMA_MAPPED) {
+		(void) ddi_dma_mem_free(&accessp);
+		ddi_dma_free_handle(&cmd->cmd_dmahandle);
+		cmd->cmd_dmahandle = NULL;
+		mptsas_log(mpt, CE_WARN, "unable to bind DMA resources for "
+		    "config page.");
+		rval = DDI_FAILURE;
+		goto page_done;
+	}
+	cmd->cmd_dma_addr = cookie.dmac_laddress;
+	bzero(page_memp, len);
+
+	/*
+	 * Save the data for this request to be used in the call to start the
+	 * config page read
+	 */
+	config.action = action;
+	config.page_address = page_address;
+
+	/*
+	 * Re-use the cmd that was used to get the header.  Reset some of the
+	 * values.
+	 */
+	bzero((caddr_t)pkt, scsi_pkt_size());
+	pkt->pkt_ha_private	= (opaque_t)&config;
+	pkt->pkt_flags		= FLAG_HEAD;
+	pkt->pkt_time		= 60;
+	cmd->cmd_flags		= CFLAG_PREPARED | CFLAG_CMDIOC | CFLAG_CONFIG;
+
+	/*
+	 * Send the config page request.  cmd is re-used from header request.
+	 */
+	mptsas_start_config_page_access(mpt, cmd);
+
+	/*
+	 * Wait for the command to complete or timeout.
+	 */
+	while ((cmd->cmd_flags & CFLAG_FINISHED) == 0) {
+		cv_wait(&mpt->m_config_cv, &mpt->m_mutex);
+	}
+
+	/*
+	 * Check if the request completed without timing out
+	 */
+	if (cmd->cmd_flags & CFLAG_TIMEOUT) {
+		mptsas_log(mpt, CE_WARN, "config page request timeout");
+		rval = DDI_FAILURE;
+		goto page_done;
+	}
+
+	/*
+	 * cmd_rfm points to the reply message if a reply was given.  The reply
+	 * frame and the config page are returned from this function in the
+	 * param list.
+	 */
+	if (cmd->cmd_rfm) {
+		config_flags |= MPTSAS_ADDRESS_REPLY;
+		(void) ddi_dma_sync(mpt->m_dma_reply_frame_hdl, 0, 0,
+		    DDI_DMA_SYNC_FORCPU);
+		(void) ddi_dma_sync(cmd->cmd_dmahandle, 0, 0,
+		    DDI_DMA_SYNC_FORCPU);
+		reply = (pMpi2ConfigReply_t)(mpt->m_reply_frame + (cmd->cmd_rfm
+		    - mpt->m_reply_frame_dma_addr));
+		iocstatus = ddi_get16(mpt->m_acc_reply_frame_hdl,
+		    &reply->IOCStatus);
+		iocstatus = MPTSAS_IOCSTATUS(iocstatus);
+		iocloginfo = ddi_get32(mpt->m_acc_reply_frame_hdl,
+		    &reply->IOCLogInfo);
+	}
+
+	if (callback(mpt, page_memp, accessp, iocstatus, iocloginfo, ap)) {
+		rval = DDI_FAILURE;
+		goto page_done;
+	}
+
+	mptsas_fma_check(mpt, cmd);
+	/*
+	 * Check the DMA/ACC handles and then free the DMA buffer.
+	 */
+	if ((mptsas_check_dma_handle(cmd->cmd_dmahandle) != DDI_SUCCESS) ||
+	    (mptsas_check_acc_handle(accessp) != DDI_SUCCESS)) {
+		ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
+		rval = DDI_FAILURE;
+	}
+
+	if (pkt->pkt_reason == CMD_TRAN_ERR) {
+		mptsas_log(mpt, CE_WARN, "config fma error");
+		rval = DDI_FAILURE;
+		goto page_done;
+	}
+	if (pkt->pkt_reason == CMD_RESET) {
+		mptsas_log(mpt, CE_WARN, "ioc reset abort config request");
+		rval = DDI_FAILURE;
+		goto page_done;
+	}
+
+page_done:
+	va_end(ap);
+	/*
+	 * Put the reply frame back on the free queue, increment the free
+	 * index, and write the new index to the free index register.  But only
+	 * if this reply is an ADDRESS reply.
+	 */
+	if (config_flags & MPTSAS_ADDRESS_REPLY) {
+		reply_index = mpt->m_free_index;
+		ddi_put32(mpt->m_acc_free_queue_hdl,
+		    &((uint32_t *)(void *)mpt->m_free_queue)[reply_index],
+		    cmd->cmd_rfm);
+		(void) ddi_dma_sync(mpt->m_dma_free_queue_hdl, 0, 0,
+		    DDI_DMA_SYNC_FORDEV);
+		if (++reply_index == mpt->m_free_queue_depth) {
+			reply_index = 0;
+		}
+		mpt->m_free_index = reply_index;
+		ddi_put32(mpt->m_datap, &mpt->m_reg->ReplyFreeHostIndex,
+		    reply_index);
+	}
+
+	if (cmd->cmd_dmahandle != NULL) {
+		(void) ddi_dma_unbind_handle(cmd->cmd_dmahandle);
+		(void) ddi_dma_mem_free(&accessp);
+		ddi_dma_free_handle(&cmd->cmd_dmahandle);
+	}
+
+	if (cmd && (cmd->cmd_flags & CFLAG_PREPARED)) {
+		mptsas_remove_cmd(mpt, cmd);
+		config_flags &= (~MPTSAS_REQUEST_POOL_CMD);
+	}
+	if (config_flags & MPTSAS_REQUEST_POOL_CMD)
+		mptsas_return_to_pool(mpt, cmd);
+
+	if (config_flags & MPTSAS_CMD_TIMEOUT) {
+		if ((mptsas_restart_ioc(mpt)) == DDI_FAILURE) {
+			mptsas_log(mpt, CE_WARN, "mptsas_restart_ioc failed");
+		}
+	}
+
+	return (rval);
+}
+
+int
+mptsas_send_config_request_msg(mptsas_t *mpt, uint8_t action, uint8_t pagetype,
+	uint32_t pageaddress, uint8_t pagenumber, uint8_t pageversion,
+	uint8_t pagelength, uint32_t SGEflagslength, uint32_t SGEaddress32)
+{
+	pMpi2ConfigRequest_t	config;
+	int			send_numbytes;
+
+	bzero(mpt->m_hshk_memp, sizeof (MPI2_CONFIG_REQUEST));
+	config = (pMpi2ConfigRequest_t)mpt->m_hshk_memp;
+	ddi_put8(mpt->m_hshk_acc_hdl, &config->Function, MPI2_FUNCTION_CONFIG);
+	ddi_put8(mpt->m_hshk_acc_hdl, &config->Action, action);
+	ddi_put8(mpt->m_hshk_acc_hdl, &config->Header.PageNumber, pagenumber);
+	ddi_put8(mpt->m_hshk_acc_hdl, &config->Header.PageType, pagetype);
+	ddi_put32(mpt->m_hshk_acc_hdl, &config->PageAddress, pageaddress);
+	ddi_put8(mpt->m_hshk_acc_hdl, &config->Header.PageVersion, pageversion);
+	ddi_put8(mpt->m_hshk_acc_hdl, &config->Header.PageLength, pagelength);
+	ddi_put32(mpt->m_hshk_acc_hdl,
+	    &config->PageBufferSGE.MpiSimple.FlagsLength, SGEflagslength);
+	ddi_put32(mpt->m_hshk_acc_hdl,
+	    &config->PageBufferSGE.MpiSimple.u.Address32, SGEaddress32);
+	send_numbytes = sizeof (MPI2_CONFIG_REQUEST);
+
+	/*
+	 * Post message via handshake
+	 */
+	if (mptsas_send_handshake_msg(mpt, (caddr_t)config, send_numbytes,
+	    mpt->m_hshk_acc_hdl)) {
+		return (-1);
+	}
+	return (0);
+}
+
+int
+mptsas_send_extended_config_request_msg(mptsas_t *mpt, uint8_t action,
+	uint8_t extpagetype, uint32_t pageaddress, uint8_t pagenumber,
+	uint8_t pageversion, uint16_t extpagelength,
+	uint32_t SGEflagslength, uint32_t SGEaddress32)
+{
+	pMpi2ConfigRequest_t	config;
+	int			send_numbytes;
+
+	bzero(mpt->m_hshk_memp, sizeof (MPI2_CONFIG_REQUEST));
+	config = (pMpi2ConfigRequest_t)mpt->m_hshk_memp;
+	ddi_put8(mpt->m_hshk_acc_hdl, &config->Function, MPI2_FUNCTION_CONFIG);
+	ddi_put8(mpt->m_hshk_acc_hdl, &config->Action, action);
+	ddi_put8(mpt->m_hshk_acc_hdl, &config->Header.PageNumber, pagenumber);
+	ddi_put8(mpt->m_hshk_acc_hdl, &config->Header.PageType,
+	    MPI2_CONFIG_PAGETYPE_EXTENDED);
+	ddi_put8(mpt->m_hshk_acc_hdl, &config->ExtPageType, extpagetype);
+	ddi_put32(mpt->m_hshk_acc_hdl, &config->PageAddress, pageaddress);
+	ddi_put8(mpt->m_hshk_acc_hdl, &config->Header.PageVersion, pageversion);
+	ddi_put16(mpt->m_hshk_acc_hdl, &config->ExtPageLength, extpagelength);
+	ddi_put32(mpt->m_hshk_acc_hdl,
+	    &config->PageBufferSGE.MpiSimple.FlagsLength, SGEflagslength);
+	ddi_put32(mpt->m_hshk_acc_hdl,
+	    &config->PageBufferSGE.MpiSimple.u.Address32, SGEaddress32);
+	send_numbytes = sizeof (MPI2_CONFIG_REQUEST);
+
+	/*
+	 * Post message via handshake
+	 */
+	if (mptsas_send_handshake_msg(mpt, (caddr_t)config, send_numbytes,
+	    mpt->m_hshk_acc_hdl)) {
+		return (-1);
+	}
+	return (0);
+}
+
+int
+mptsas_ioc_wait_for_response(mptsas_t *mpt)
+{
+	int	polls = 0;
+
+	while ((ddi_get32(mpt->m_datap,
+	    &mpt->m_reg->HostInterruptStatus) & MPI2_HIS_IOP_DOORBELL_STATUS)) {
+		drv_usecwait(1000);
+		if (polls++ > 60000) {
+			return (-1);
+		}
+	}
+	return (0);
+}
+
+int
+mptsas_ioc_wait_for_doorbell(mptsas_t *mpt)
+{
+	int	polls = 0;
+
+	while ((ddi_get32(mpt->m_datap,
+	    &mpt->m_reg->HostInterruptStatus) & MPI2_HIM_DIM) == 0) {
+		drv_usecwait(1000);
+		if (polls++ > 300000) {
+			return (-1);
+		}
+	}
+	return (0);
+}
+
+int
+mptsas_send_handshake_msg(mptsas_t *mpt, caddr_t memp, int numbytes,
+	ddi_acc_handle_t accessp)
+{
+	int	i;
+
+	/*
+	 * clean pending doorbells
+	 */
+	ddi_put32(mpt->m_datap, &mpt->m_reg->HostInterruptStatus, 0);
+	ddi_put32(mpt->m_datap, &mpt->m_reg->Doorbell,
+	    ((MPI2_FUNCTION_HANDSHAKE << MPI2_DOORBELL_FUNCTION_SHIFT) |
+	    ((numbytes / 4) << MPI2_DOORBELL_ADD_DWORDS_SHIFT)));
+
+	if (mptsas_ioc_wait_for_doorbell(mpt)) {
+		NDBG19(("mptsas_send_handshake failed.  Doorbell not ready\n"));
+		return (-1);
+	}
+
+	/*
+	 * clean pending doorbells again
+	 */
+	ddi_put32(mpt->m_datap, &mpt->m_reg->HostInterruptStatus, 0);
+
+	if (mptsas_ioc_wait_for_response(mpt)) {
+		NDBG19(("mptsas_send_handshake failed.  Doorbell not "
+		    "cleared\n"));
+		return (-1);
+	}
+
+	/*
+	 * post handshake message
+	 */
+	for (i = 0; (i < numbytes / 4); i++, memp += 4) {
+		ddi_put32(mpt->m_datap, &mpt->m_reg->Doorbell,
+		    ddi_get32(accessp, (uint32_t *)((void *)(memp))));
+		if (mptsas_ioc_wait_for_response(mpt)) {
+			NDBG19(("mptsas_send_handshake failed posting "
+			    "message\n"));
+			return (-1);
+		}
+	}
+
+	if (mptsas_check_acc_handle(mpt->m_datap) != DDI_SUCCESS) {
+		ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
+		ddi_fm_acc_err_clear(mpt->m_datap, DDI_FME_VER0);
+		return (-1);
+	}
+
+	return (0);
+}
+
+int
+mptsas_get_handshake_msg(mptsas_t *mpt, caddr_t memp, int numbytes,
+	ddi_acc_handle_t accessp)
+{
+	int		i, totalbytes, bytesleft;
+	uint16_t	val;
+
+	/*
+	 * wait for doorbell
+	 */
+	if (mptsas_ioc_wait_for_doorbell(mpt)) {
+		NDBG19(("mptsas_get_handshake failed.  Doorbell not ready\n"));
+		return (-1);
+	}
+
+	/*
+	 * get first 2 bytes of handshake message to determine how much
+	 * data we will be getting
+	 */
+	for (i = 0; i < 2; i++, memp += 2) {
+		val = (ddi_get32(mpt->m_datap,
+		    &mpt->m_reg->Doorbell) & MPI2_DOORBELL_DATA_MASK);
+		ddi_put32(mpt->m_datap, &mpt->m_reg->HostInterruptStatus, 0);
+		if (mptsas_ioc_wait_for_doorbell(mpt)) {
+			NDBG19(("mptsas_get_handshake failure getting initial"
+			    " data\n"));
+			return (-1);
+		}
+		ddi_put16(accessp, (uint16_t *)((void *)(memp)), val);
+		if (i == 1) {
+			totalbytes = (val & 0xFF) * 2;
+		}
+	}
+
+	/*
+	 * If we are expecting less bytes than the message wants to send
+	 * we simply save as much as we expected and then throw out the rest
+	 * later
+	 */
+	if (totalbytes > (numbytes / 2)) {
+		bytesleft = ((numbytes / 2) - 2);
+	} else {
+		bytesleft = (totalbytes - 2);
+	}
+
+	/*
+	 * Get the rest of the data
+	 */
+	for (i = 0; i < bytesleft; i++, memp += 2) {
+		val = (ddi_get32(mpt->m_datap,
+		    &mpt->m_reg->Doorbell) & MPI2_DOORBELL_DATA_MASK);
+		ddi_put32(mpt->m_datap, &mpt->m_reg->HostInterruptStatus, 0);
+		if (mptsas_ioc_wait_for_doorbell(mpt)) {
+			NDBG19(("mptsas_get_handshake failure getting"
+			    " main data\n"));
+			return (-1);
+		}
+		ddi_put16(accessp, (uint16_t *)((void *)(memp)), val);
+	}
+
+	/*
+	 * Sometimes the device will send more data than is expected
+	 * This data is not used by us but needs to be cleared from
+	 * ioc doorbell.  So we just read the values and throw
+	 * them out.
+	 */
+	if (totalbytes > (numbytes / 2)) {
+		for (i = (numbytes / 2); i < totalbytes; i++) {
+			val = (ddi_get32(mpt->m_datap,
+			    &mpt->m_reg->Doorbell) &
+			    MPI2_DOORBELL_DATA_MASK);
+			ddi_put32(mpt->m_datap,
+			    &mpt->m_reg->HostInterruptStatus, 0);
+			if (mptsas_ioc_wait_for_doorbell(mpt)) {
+				NDBG19(("mptsas_get_handshake failure getting "
+				    "extra garbage data\n"));
+				return (-1);
+			}
+		}
+	}
+
+	ddi_put32(mpt->m_datap, &mpt->m_reg->HostInterruptStatus, 0);
+
+	if (mptsas_check_acc_handle(mpt->m_datap) != DDI_SUCCESS) {
+		ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
+		ddi_fm_acc_err_clear(mpt->m_datap, DDI_FME_VER0);
+		return (-1);
+	}
+
+	return (0);
+}
+
+int
+mptsas_kick_start(mptsas_t *mpt)
+{
+	int		polls = 0;
+	uint32_t	diag_reg, ioc_state, saved_HCB_size;
+
+	/*
+	 * Start a hard reset.  Write magic number and wait 900 uSeconds.
+	 */
+	MPTSAS_ENABLE_DRWE(mpt);
+	drv_usecwait(900);
+
+	/*
+	 * Read the current Diag Reg and save the Host Controlled Boot size.
+	 */
+	diag_reg = ddi_get32(mpt->m_datap, &mpt->m_reg->HostDiagnostic);
+	saved_HCB_size = ddi_get32(mpt->m_datap, &mpt->m_reg->HCBSize);
+
+	/*
+	 * Set Reset Adapter bit and wait 30 mSeconds.
+	 */
+	diag_reg |= MPI2_DIAG_RESET_ADAPTER;
+	ddi_put32(mpt->m_datap, &mpt->m_reg->HostDiagnostic, diag_reg);
+	drv_usecwait(30000);
+
+	/*
+	 * Poll, waiting for Reset Adapter bit to clear.  300 Seconds max
+	 * (600000 * 500 = 300,000,000 uSeconds, 300 seconds).
+	 * If no more adapter (all FF's), just return failure.
+	 */
+	for (polls = 0; polls < 600000; polls++) {
+		diag_reg = ddi_get32(mpt->m_datap,
+		    &mpt->m_reg->HostDiagnostic);
+		if (diag_reg == 0xFFFFFFFF) {
+			mptsas_fm_ereport(mpt, DDI_FM_DEVICE_NO_RESPONSE);
+			ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_LOST);
+			return (DDI_FAILURE);
+		}
+		if (!(diag_reg & MPI2_DIAG_RESET_ADAPTER)) {
+			break;
+		}
+		drv_usecwait(500);
+	}
+	if (polls == 600000) {
+		mptsas_fm_ereport(mpt, DDI_FM_DEVICE_NO_RESPONSE);
+		ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_LOST);
+		return (DDI_FAILURE);
+	}
+
+	/*
+	 * Check if adapter is in Host Boot Mode.  If so, restart adapter
+	 * assuming the HCB points to good FW.
+	 * Set BootDeviceSel to HCDW (Host Code and Data Window).
+	 */
+	if (diag_reg & MPI2_DIAG_HCB_MODE) {
+		diag_reg &= ~MPI2_DIAG_BOOT_DEVICE_SELECT_MASK;
+		diag_reg |= MPI2_DIAG_BOOT_DEVICE_SELECT_HCDW;
+		ddi_put32(mpt->m_datap, &mpt->m_reg->HostDiagnostic, diag_reg);
+
+		/*
+		 * Re-enable the HCDW.
+		 */
+		ddi_put32(mpt->m_datap, &mpt->m_reg->HCBSize,
+		    (saved_HCB_size | MPI2_HCB_SIZE_HCB_ENABLE));
+	}
+
+	/*
+	 * Restart the adapter.
+	 */
+	diag_reg &= ~MPI2_DIAG_HOLD_IOC_RESET;
+	ddi_put32(mpt->m_datap, &mpt->m_reg->HostDiagnostic, diag_reg);
+
+	/*
+	 * Disable writes to the Host Diag register.
+	 */
+	ddi_put32(mpt->m_datap, &mpt->m_reg->WriteSequence,
+	    MPI2_WRSEQ_FLUSH_KEY_VALUE);
+
+	/*
+	 * Wait 20 seconds max for FW to come to ready state.
+	 */
+	for (polls = 0; polls < 20000; polls++) {
+		ioc_state = ddi_get32(mpt->m_datap, &mpt->m_reg->Doorbell);
+		if (ioc_state == 0xFFFFFFFF) {
+			mptsas_fm_ereport(mpt, DDI_FM_DEVICE_NO_RESPONSE);
+			ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_LOST);
+			return (DDI_FAILURE);
+		}
+		if ((ioc_state & MPI2_IOC_STATE_MASK) ==
+		    MPI2_IOC_STATE_READY) {
+			break;
+		}
+		drv_usecwait(1000);
+	}
+	if (polls == 20000) {
+		mptsas_fm_ereport(mpt, DDI_FM_DEVICE_NO_RESPONSE);
+		ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_LOST);
+		return (DDI_FAILURE);
+	}
+
+	/*
+	 * Clear the ioc ack events queue.
+	 */
+	mptsas_destroy_ioc_event_cmd(mpt);
+
+	return (DDI_SUCCESS);
+}
+
+int
+mptsas_ioc_reset(mptsas_t *mpt)
+{
+#ifdef SLM
+	int		polls = 0;
+	uint32_t	reset_msg;
+
+#endif
+	uint32_t	ioc_state;
+	ioc_state = ddi_get32(mpt->m_datap, &mpt->m_reg->Doorbell);
+	/*
+	 * If chip is already in ready state then there is nothing to do.
+	 */
+	if (ioc_state == MPI2_IOC_STATE_READY) {
+		return (MPTSAS_NO_RESET);
+	}
+
+/*
+ * SLM-test; skip MUR for now
+ */
+#ifdef SLM
+	/*
+	 * If the chip is already operational, we just need to send
+	 * it a message unit reset to put it back in the ready state
+	 */
+	if (ioc_state & MPI2_IOC_STATE_OPERATIONAL) {
+		reset_msg = MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET;
+		ddi_put32(mpt->m_datap, &mpt->m_reg->Doorbell,
+		    (reset_msg << MPI2_DOORBELL_FUNCTION_SHIFT));
+		if (mptsas_ioc_wait_for_response(mpt)) {
+			NDBG19(("mptsas_ioc_reset failure sending "
+			    "message_unit_reset\n"));
+			goto hard_reset;
+		}
+
+		/*
+		 * Wait for chip to become ready
+		 */
+		while ((ddi_get32(mpt->m_datap, &mpt->m_reg->Doorbell) &
+		    MPI2_IOC_STATE_READY) == 0x0) {
+			drv_usecwait(1000);
+			if (polls++ > 20000) {
+				goto hard_reset;
+			}
+		}
+		/*
+		 * the message unit reset would do reset operations
+		 * clear reply and request queue, so we should clear
+		 * ACK event cmd.
+		 */
+		mptsas_destroy_ioc_event_cmd(mpt);
+		return (MPTSAS_NO_RESET);
+	}
+
+hard_reset:
+#endif
+	if (mptsas_kick_start(mpt) == DDI_FAILURE) {
+		mptsas_fm_ereport(mpt, DDI_FM_DEVICE_NO_RESPONSE);
+		ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_LOST);
+		return (MPTSAS_RESET_FAIL);
+	}
+	return (MPTSAS_SUCCESS_HARDRESET);
+}
+
+
+int
+mptsas_request_from_pool(mptsas_t *mpt, mptsas_cmd_t **cmd,
+    struct scsi_pkt **pkt)
+{
+	m_event_struct_t	*ioc_cmd = NULL;
+
+	ioc_cmd = kmem_zalloc(M_EVENT_STRUCT_SIZE, KM_SLEEP);
+	if (ioc_cmd == NULL) {
+		return (DDI_FAILURE);
+	}
+	ioc_cmd->m_event_linkp = NULL;
+	mptsas_ioc_event_cmdq_add(mpt, ioc_cmd);
+	*cmd = &(ioc_cmd->m_event_cmd);
+	*pkt = &(ioc_cmd->m_event_pkt);
+
+	return (DDI_SUCCESS);
+}
+
+void
+mptsas_return_to_pool(mptsas_t *mpt, mptsas_cmd_t *cmd)
+{
+	m_event_struct_t	*ioc_cmd = NULL;
+
+	ioc_cmd = mptsas_ioc_event_find_by_cmd(mpt, cmd);
+	if (ioc_cmd == NULL) {
+		return;
+	}
+
+	mptsas_ioc_event_cmdq_delete(mpt, ioc_cmd);
+	kmem_free(ioc_cmd, M_EVENT_STRUCT_SIZE);
+	ioc_cmd = NULL;
+}
+
+/*
+ * NOTE: We should be able to queue TM requests in the controller to make this
+ * a lot faster.  If resetting all targets, for example, we can load the hi
+ * priority queue with its limit and the controller will reply as they are
+ * completed.  This way, we don't have to poll for one reply at a time.
+ * Think about enhancing this later.
+ */
+int
+mptsas_ioc_task_management(mptsas_t *mpt, int task_type, uint16_t dev_handle,
+	int lun)
+{
+	/*
+	 * In order to avoid allocating variables on the stack,
+	 * we make use of the pre-existing mptsas_cmd_t and
+	 * scsi_pkt which are included in the mptsas_t which
+	 * is passed to this routine.
+	 */
+
+	pMpi2SCSITaskManagementRequest_t	task;
+	int					rval = FALSE;
+	mptsas_cmd_t				*cmd;
+	struct scsi_pkt				*pkt;
+	mptsas_slots_t				*slots = mpt->m_active;
+	uint32_t				request_desc_low, int_mask;
+
+	/*
+	 * Can't start another task management routine.
+	 */
+	if (slots->m_slot[MPTSAS_TM_SLOT(mpt)] != NULL) {
+		mptsas_log(mpt, CE_WARN, "Can only start 1 task management"
+		    " command at a time\n");
+		return (FALSE);
+	}
+
+	cmd = &(mpt->m_event_task_mgmt.m_event_cmd);
+	pkt = &(mpt->m_event_task_mgmt.m_event_pkt);
+
+	bzero((caddr_t)cmd, sizeof (*cmd));
+	bzero((caddr_t)pkt, scsi_pkt_size());
+
+	pkt->pkt_cdbp		= (opaque_t)&cmd->cmd_cdb[0];
+	pkt->pkt_scbp		= (opaque_t)&cmd->cmd_scb;
+	pkt->pkt_ha_private	= (opaque_t)cmd;
+	pkt->pkt_flags		= (FLAG_NOINTR | FLAG_HEAD);
+	pkt->pkt_time		= 60;
+	pkt->pkt_address.a_target = dev_handle;
+	pkt->pkt_address.a_lun = (uchar_t)lun;
+	cmd->cmd_pkt		= pkt;
+	cmd->cmd_scblen		= 1;
+	cmd->cmd_flags		= CFLAG_TM_CMD;
+	cmd->cmd_slot		= MPTSAS_TM_SLOT(mpt);
+
+	slots->m_slot[MPTSAS_TM_SLOT(mpt)] = cmd;
+
+	/*
+	 * Store the TM message in memory location corresponding to the TM slot
+	 * number.
+	 */
+	task = (pMpi2SCSITaskManagementRequest_t)(mpt->m_req_frame +
+	    (mpt->m_req_frame_size * cmd->cmd_slot));
+	bzero(task, mpt->m_req_frame_size);
+
+	/*
+	 * form message for requested task
+	 */
+	mptsas_init_std_hdr(mpt->m_acc_req_frame_hdl, task, dev_handle, lun, 0,
+	    MPI2_FUNCTION_SCSI_TASK_MGMT);
+
+	/*
+	 * Set the task type
+	 */
+	ddi_put8(mpt->m_acc_req_frame_hdl, &task->TaskType, task_type);
+
+	/*
+	 * Get the current interrupt mask.  When re-enabling ints, set mask to
+	 * saved value.
+	 */
+	int_mask = ddi_get32(mpt->m_datap, &mpt->m_reg->HostInterruptMask);
+
+	/*
+	 * Send TM request using High Priority Queue.
+	 */
+	MPTSAS_DISABLE_INTR(mpt);
+	(void) ddi_dma_sync(mpt->m_dma_req_frame_hdl, 0, 0,
+	    DDI_DMA_SYNC_FORDEV);
+	request_desc_low = (cmd->cmd_slot << 16) +
+	    MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY;
+	MPTSAS_START_CMD(mpt, request_desc_low, 0);
+	rval = mptsas_poll(mpt, cmd, MPTSAS_POLL_TIME);
+	ddi_put32(mpt->m_datap, &mpt->m_reg->HostInterruptMask, int_mask);
+
+	if (pkt->pkt_reason == CMD_INCOMPLETE)
+		rval = FALSE;
+
+	/*
+	 * clear the TM slot before returning
+	 */
+	slots->m_slot[MPTSAS_TM_SLOT(mpt)] = NULL;
+
+	/*
+	 * If we lost our task management command
+	 * we need to reset the ioc
+	 */
+	if (rval == FALSE) {
+		mptsas_log(mpt, CE_WARN, "mptsas_ioc_task_management failed "
+		    "try to reset ioc to recovery!");
+		if (mptsas_restart_ioc(mpt)) {
+			mptsas_log(mpt, CE_WARN, "mptsas_restart_ioc failed");
+			rval = FAILED;
+		}
+	}
+
+	return (rval);
+}
+
+int
+mptsas_update_flash(mptsas_t *mpt, caddr_t ptrbuffer, uint32_t size,
+    uint8_t type, int mode)
+{
+
+	/*
+	 * In order to avoid allocating variables on the stack,
+	 * we make use of the pre-existing mptsas_cmd_t and
+	 * scsi_pkt which are included in the mptsas_t which
+	 * is passed to this routine.
+	 */
+
+	ddi_dma_attr_t		flsh_dma_attrs;
+	uint_t			flsh_ncookie;
+	ddi_dma_cookie_t	flsh_cookie;
+	ddi_dma_handle_t	flsh_dma_handle;
+	ddi_acc_handle_t	flsh_accessp;
+	size_t			flsh_alloc_len;
+	caddr_t			memp, flsh_memp;
+	uint32_t		flagslength;
+	pMpi2FWDownloadRequest	fwdownload;
+	pMpi2FWDownloadTCSGE_t	tcsge;
+	pMpi2SGESimple64_t	sge;
+	mptsas_cmd_t		*cmd;
+	struct scsi_pkt		*pkt;
+	int			i;
+	int			rvalue = 0;
+	uint32_t		request_desc_low;
+
+	if ((rvalue = (mptsas_request_from_pool(mpt, &cmd, &pkt))) == -1) {
+		mptsas_log(mpt, CE_WARN, "mptsas_update_flash(): allocation "
+		    "failed. event ack command pool is full\n");
+		return (rvalue);
+	}
+
+	bzero((caddr_t)cmd, sizeof (*cmd));
+	bzero((caddr_t)pkt, scsi_pkt_size());
+	cmd->ioc_cmd_slot = (uint32_t)rvalue;
+
+	/*
+	 * dynamically create a customized dma attribute structure
+	 * that describes the flash file.
+	 */
+	flsh_dma_attrs = mpt->m_msg_dma_attr;
+	flsh_dma_attrs.dma_attr_sgllen = 1;
+
+	if (ddi_dma_alloc_handle(mpt->m_dip, &flsh_dma_attrs,
+	    DDI_DMA_SLEEP, NULL, &flsh_dma_handle) != DDI_SUCCESS) {
+		mptsas_log(mpt, CE_WARN,
+		    "(unable to allocate dma handle.");
+		mptsas_return_to_pool(mpt, cmd);
+		return (-1);
+	}
+
+	if (ddi_dma_mem_alloc(flsh_dma_handle, size,
+	    &mpt->m_dev_acc_attr, DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL,
+	    &flsh_memp, &flsh_alloc_len, &flsh_accessp) != DDI_SUCCESS) {
+		ddi_dma_free_handle(&flsh_dma_handle);
+		mptsas_log(mpt, CE_WARN,
+		    "unable to allocate flash structure.");
+		mptsas_return_to_pool(mpt, cmd);
+		return (-1);
+	}
+
+	if (ddi_dma_addr_bind_handle(flsh_dma_handle, NULL, flsh_memp,
+	    flsh_alloc_len, DDI_DMA_RDWR | DDI_DMA_CONSISTENT, DDI_DMA_SLEEP,
+	    NULL, &flsh_cookie, &flsh_ncookie) != DDI_DMA_MAPPED) {
+		(void) ddi_dma_mem_free(&flsh_accessp);
+		ddi_dma_free_handle(&flsh_dma_handle);
+		mptsas_log(mpt, CE_WARN, "unable to bind DMA resources.");
+		mptsas_return_to_pool(mpt, cmd);
+		return (-1);
+	}
+	bzero(flsh_memp, size);
+
+	for (i = 0; i < size; i++) {
+		(void) ddi_copyin(ptrbuffer + i, flsh_memp + i, 1, mode);
+	}
+	(void) ddi_dma_sync(flsh_dma_handle, 0, 0, DDI_DMA_SYNC_FORDEV);
+
+	/*
+	 * form a cmd/pkt to store the fw download message
+	 */
+	pkt->pkt_cdbp		= (opaque_t)&cmd->cmd_cdb[0];
+	pkt->pkt_scbp		= (opaque_t)&cmd->cmd_scb;
+	pkt->pkt_ha_private	= (opaque_t)cmd;
+	pkt->pkt_flags		= FLAG_HEAD;
+	pkt->pkt_time		= 60;
+	cmd->cmd_pkt		= pkt;
+	cmd->cmd_scblen		= 1;
+	cmd->cmd_flags		= CFLAG_CMDIOC | CFLAG_FW_CMD;
+
+	/*
+	 * Save the command in a slot
+	 */
+	if (mptsas_save_cmd(mpt, cmd) == FALSE) {
+		(void) ddi_dma_unbind_handle(flsh_dma_handle);
+		(void) ddi_dma_mem_free(&flsh_accessp);
+		ddi_dma_free_handle(&flsh_dma_handle);
+		mptsas_return_to_pool(mpt, cmd);
+		return (-1);
+	}
+
+	/*
+	 * Fill in fw download message
+	 */
+	ASSERT(cmd->cmd_slot != 0);
+	memp = mpt->m_req_frame + (mpt->m_req_frame_size * cmd->cmd_slot);
+	bzero(memp, mpt->m_req_frame_size);
+	fwdownload = (void *)memp;
+	ddi_put8(mpt->m_acc_req_frame_hdl, &fwdownload->Function,
+	    MPI2_FUNCTION_FW_DOWNLOAD);
+	ddi_put8(mpt->m_acc_req_frame_hdl, &fwdownload->ImageType, type);
+	ddi_put8(mpt->m_acc_req_frame_hdl, &fwdownload->MsgFlags,
+	    MPI2_FW_DOWNLOAD_MSGFLGS_LAST_SEGMENT);
+	ddi_put32(mpt->m_acc_req_frame_hdl, &fwdownload->TotalImageSize, size);
+
+	tcsge = (pMpi2FWDownloadTCSGE_t)&fwdownload->SGL;
+	ddi_put8(mpt->m_acc_req_frame_hdl, &tcsge->ContextSize, 0);
+	ddi_put8(mpt->m_acc_req_frame_hdl, &tcsge->DetailsLength, 12);
+	ddi_put8(mpt->m_acc_req_frame_hdl, &tcsge->Flags, 0);
+	ddi_put32(mpt->m_acc_req_frame_hdl, &tcsge->ImageOffset, 0);
+	ddi_put32(mpt->m_acc_req_frame_hdl, &tcsge->ImageSize, size);
+
+	sge = (pMpi2SGESimple64_t)(tcsge + 1);
+	flagslength = size;
+	flagslength |= ((uint32_t)(MPI2_SGE_FLAGS_LAST_ELEMENT |
+	    MPI2_SGE_FLAGS_END_OF_BUFFER |
+	    MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
+	    MPI2_SGE_FLAGS_SYSTEM_ADDRESS |
+	    MPI2_SGE_FLAGS_64_BIT_ADDRESSING |
+	    MPI2_SGE_FLAGS_HOST_TO_IOC |
+	    MPI2_SGE_FLAGS_END_OF_LIST) << MPI2_SGE_FLAGS_SHIFT);
+	ddi_put32(mpt->m_acc_req_frame_hdl, &sge->FlagsLength, flagslength);
+	ddi_put32(mpt->m_acc_req_frame_hdl, &sge->Address.Low,
+	    flsh_cookie.dmac_address);
+	ddi_put32(mpt->m_acc_req_frame_hdl, &sge->Address.High,
+	    (uint32_t)(flsh_cookie.dmac_laddress >> 32));
+
+	/*
+	 * Start command
+	 */
+	(void) ddi_dma_sync(mpt->m_dma_req_frame_hdl, 0, 0,
+	    DDI_DMA_SYNC_FORDEV);
+	request_desc_low = (cmd->cmd_slot << 16) +
+	    MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
+	cmd->cmd_rfm = NULL;
+	MPTSAS_START_CMD(mpt, request_desc_low, 0);
+
+	rvalue = 0;
+	(void) cv_timedwait(&mpt->m_fw_cv, &mpt->m_mutex,
+	    MPTSAS_CV_TIMEOUT(60));
+	if (!(cmd->cmd_flags & CFLAG_FINISHED)) {
+		if ((mptsas_restart_ioc(mpt)) == DDI_FAILURE) {
+			mptsas_log(mpt, CE_WARN, "mptsas_restart_ioc failed");
+		}
+		rvalue = -1;
+	}
+	mptsas_remove_cmd(mpt, cmd);
+
+	(void) ddi_dma_unbind_handle(flsh_dma_handle);
+	(void) ddi_dma_mem_free(&flsh_accessp);
+	ddi_dma_free_handle(&flsh_dma_handle);
+
+	return (rvalue);
+}
+
+static int
+mptsas_sasdevpage_0_cb(mptsas_t *mpt, caddr_t page_memp,
+    ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
+    va_list ap)
+{
+#ifndef __lock_lint
+	_NOTE(ARGUNUSED(ap))
+#endif
+	pMpi2SasDevicePage0_t	sasdevpage;
+	int			rval = DDI_SUCCESS, i;
+	uint8_t			*sas_addr = NULL;
+	uint8_t			tmp_sas_wwn[SAS_WWN_BYTE_SIZE];
+	uint16_t		*devhdl;
+	uint64_t		*sas_wwn;
+	uint32_t		*dev_info;
+	uint8_t			*physport, *phynum;
+	uint32_t		page_address;
+
+	if ((iocstatus != MPI2_IOCSTATUS_SUCCESS) &&
+	    (iocstatus != MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)) {
+		mptsas_log(mpt, CE_WARN, "mptsas_get_sas_device_page0 "
+		    "header: IOCStatus=0x%x, IOCLogInfo=0x%x",
+		    iocstatus, iocloginfo);
+		rval = DDI_FAILURE;
+		return (rval);
+	}
+	page_address = va_arg(ap, uint32_t);
+	/*
+	 * The INVALID_PAGE status is normal if using GET_NEXT_HANDLE and there
+	 * are no more pages.  If everything is OK up to this point but the
+	 * status is INVALID_PAGE, change rval to FAILURE and quit.  Also,
+	 * signal that device traversal is complete.
+	 */
+	if (iocstatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) {
+		if ((page_address & MPI2_SAS_DEVICE_PGAD_FORM_MASK) ==
+		    MPI2_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE) {
+			mpt->m_done_traverse_dev = 1;
+		}
+		rval = DDI_FAILURE;
+		return (rval);
+	}
+	devhdl = va_arg(ap, uint16_t *);
+	sas_wwn = va_arg(ap, uint64_t *);
+	dev_info = va_arg(ap, uint32_t *);
+	physport = va_arg(ap, uint8_t *);
+	phynum = va_arg(ap, uint8_t *);
+
+	sasdevpage = (pMpi2SasDevicePage0_t)page_memp;
+
+	*dev_info = ddi_get32(accessp, &sasdevpage->DeviceInfo);
+	*devhdl = ddi_get16(accessp, &sasdevpage->DevHandle);
+	sas_addr = (uint8_t *)(&sasdevpage->SASAddress);
+	for (i = 0; i < SAS_WWN_BYTE_SIZE; i++) {
+		tmp_sas_wwn[i] = ddi_get8(accessp, sas_addr + i);
+	}
+	bcopy(tmp_sas_wwn, sas_wwn, SAS_WWN_BYTE_SIZE);
+	*sas_wwn = LE_64(*sas_wwn);
+	*physport = ddi_get8(accessp, &sasdevpage->PhysicalPort);
+	*phynum = ddi_get8(accessp, &sasdevpage->PhyNum);
+	return (rval);
+}
+
+/*
+ * Request MPI configuration page SAS device page 0 to get DevHandle, device
+ * info and SAS address.
+ */
+int
+mptsas_get_sas_device_page0(mptsas_t *mpt, uint32_t page_address,
+    uint16_t *dev_handle, uint64_t *sas_wwn, uint32_t *dev_info,
+    uint8_t *physport, uint8_t *phynum)
+{
+	int rval = DDI_SUCCESS;
+
+	ASSERT(mutex_owned(&mpt->m_mutex));
+
+	/*
+	 * Get the header and config page.  reply contains the reply frame,
+	 * which holds status info for the request.
+	 */
+	rval = mptsas_access_config_page(mpt,
+	    MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
+	    MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE, 0, page_address,
+	    mptsas_sasdevpage_0_cb, page_address, dev_handle, sas_wwn,
+	    dev_info, physport, phynum);
+
+	return (rval);
+}
+
+static int
+mptsas_sasexpdpage_0_cb(mptsas_t *mpt, caddr_t page_memp,
+    ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
+    va_list ap)
+{
+#ifndef __lock_lint
+	_NOTE(ARGUNUSED(ap))
+#endif
+	pMpi2ExpanderPage0_t	expddevpage;
+	int			rval = DDI_SUCCESS, i;
+	uint8_t			*sas_addr = NULL;
+	uint8_t			tmp_sas_wwn[SAS_WWN_BYTE_SIZE];
+	uint16_t		*devhdl;
+	uint64_t		*sas_wwn;
+	uint8_t			physport, *phymask;
+	uint32_t		page_address;
+
+	if ((iocstatus != MPI2_IOCSTATUS_SUCCESS) &&
+	    (iocstatus != MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)) {
+		mptsas_log(mpt, CE_WARN, "mptsas_get_sas_expander_page0 "
+		    "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
+		    iocstatus, iocloginfo);
+		rval = DDI_FAILURE;
+		return (rval);
+	}
+	page_address = va_arg(ap, uint32_t);
+	/*
+	 * The INVALID_PAGE status is normal if using GET_NEXT_HANDLE and there
+	 * are no more pages.  If everything is OK up to this point but the
+	 * status is INVALID_PAGE, change rval to FAILURE and quit.  Also,
+	 * signal that device traversal is complete.
+	 */
+	if (iocstatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) {
+		if ((page_address & MPI2_SAS_EXPAND_PGAD_FORM_MASK) ==
+		    MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL) {
+			mpt->m_done_traverse_smp = 1;
+		}
+		rval = DDI_FAILURE;
+		return (rval);
+	}
+	devhdl = va_arg(ap, uint16_t *);
+	sas_wwn = va_arg(ap, uint64_t *);
+	phymask = va_arg(ap, uint8_t *);
+
+	expddevpage = (pMpi2ExpanderPage0_t)page_memp;
+
+	*devhdl = ddi_get16(accessp, &expddevpage->DevHandle);
+	physport = ddi_get8(accessp, &expddevpage->PhysicalPort);
+	*phymask = mptsas_physport_to_phymask(mpt, physport);
+	sas_addr = (uint8_t *)(&expddevpage->SASAddress);
+	for (i = 0; i < SAS_WWN_BYTE_SIZE; i++) {
+		tmp_sas_wwn[i] = ddi_get8(accessp, sas_addr + i);
+	}
+	bcopy(tmp_sas_wwn, sas_wwn, SAS_WWN_BYTE_SIZE);
+	*sas_wwn = LE_64(*sas_wwn);
+	return (rval);
+}
+
+/*
+ * Request MPI configuration page SAS device page 0 to get DevHandle, phymask
+ * and SAS address.
+ */
+int
+mptsas_get_sas_expander_page0(mptsas_t *mpt, uint32_t page_address,
+    mptsas_smp_t *info)
+{
+	int			rval = DDI_SUCCESS;
+
+	ASSERT(mutex_owned(&mpt->m_mutex));
+
+	/*
+	 * Get the header and config page.  reply contains the reply frame,
+	 * which holds status info for the request.
+	 */
+	rval = mptsas_access_config_page(mpt,
+	    MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
+	    MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER, 0, page_address,
+	    mptsas_sasexpdpage_0_cb, page_address, &info->m_devhdl,
+	    &info->m_sasaddr, &info->m_phymask);
+
+	return (rval);
+}
+
+static int
+mptsas_sasportpage_0_cb(mptsas_t *mpt, caddr_t page_memp,
+    ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
+    va_list ap)
+{
+#ifndef __lock_lint
+	_NOTE(ARGUNUSED(ap))
+#endif
+	int	rval = DDI_SUCCESS, i;
+	uint8_t	*sas_addr = NULL;
+	uint64_t *sas_wwn;
+	uint8_t	tmp_sas_wwn[SAS_WWN_BYTE_SIZE];
+	uint8_t *portwidth;
+	pMpi2SasPortPage0_t sasportpage;
+
+	if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
+		mptsas_log(mpt, CE_WARN, "mptsas_get_sas_port_page0 "
+		    "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
+		    iocstatus, iocloginfo);
+		rval = DDI_FAILURE;
+		return (rval);
+	}
+	sas_wwn = va_arg(ap, uint64_t *);
+	portwidth = va_arg(ap, uint8_t *);
+
+	sasportpage = (pMpi2SasPortPage0_t)page_memp;
+	sas_addr = (uint8_t *)(&sasportpage->SASAddress);
+	for (i = 0; i < SAS_WWN_BYTE_SIZE; i++) {
+		tmp_sas_wwn[i] = ddi_get8(accessp, sas_addr + i);
+	}
+	bcopy(tmp_sas_wwn, sas_wwn, SAS_WWN_BYTE_SIZE);
+	*sas_wwn = LE_64(*sas_wwn);
+	*portwidth = ddi_get8(accessp, &sasportpage->PortWidth);
+	return (rval);
+}
+
+/*
+ * Request MPI configuration page SAS port page 0 to get initiator SAS address
+ * and port width.
+ */
+int
+mptsas_get_sas_port_page0(mptsas_t *mpt, uint32_t page_address,
+    uint64_t *sas_wwn, uint8_t *portwidth)
+{
+	int rval = DDI_SUCCESS;
+
+	ASSERT(mutex_owned(&mpt->m_mutex));
+
+	/*
+	 * Get the header and config page.  reply contains the reply frame,
+	 * which holds status info for the request.
+	 */
+	rval = mptsas_access_config_page(mpt,
+	    MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
+	    MPI2_CONFIG_EXTPAGETYPE_SAS_PORT, 0, page_address,
+	    mptsas_sasportpage_0_cb, sas_wwn, portwidth);
+
+	return (rval);
+}
+
+static int
+mptsas_sasiou_page_0_cb(mptsas_t *mpt, caddr_t page_memp,
+    ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
+    va_list ap)
+{
+#ifndef __lock_lint
+	_NOTE(ARGUNUSED(ap))
+#endif
+	int rval = DDI_SUCCESS;
+	pMpi2SasIOUnitPage0_t sasioupage0;
+	int i, num_phys;
+	uint32_t cpdi[8], *retrypage0, *readpage1;
+	uint8_t port_flags;
+
+	if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
+		mptsas_log(mpt, CE_WARN, "mptsas_get_sas_io_unit_page0 "
+		    "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
+		    iocstatus, iocloginfo);
+		rval = DDI_FAILURE;
+		return (rval);
+	}
+	readpage1 = va_arg(ap, uint32_t *);
+	retrypage0 = va_arg(ap, uint32_t *);
+
+	sasioupage0 = (pMpi2SasIOUnitPage0_t)page_memp;
+
+	num_phys = ddi_get8(accessp, &sasioupage0->NumPhys);
+	for (i = 0; i < num_phys; i++) {
+		cpdi[i] = ddi_get32(accessp,
+		    &sasioupage0->PhyData[i].
+		    ControllerPhyDeviceInfo);
+		port_flags = ddi_get8(accessp,
+		    &sasioupage0->PhyData[i].PortFlags);
+		mpt->m_phy_info[i].port_num =
+		    ddi_get8(accessp,
+		    &sasioupage0->PhyData[i].Port);
+		mpt->m_phy_info[i].ctrl_devhdl =
+		    ddi_get16(accessp, &sasioupage0->
+		    PhyData[i].ControllerDevHandle);
+		mpt->m_phy_info[i].attached_devhdl =
+		    ddi_get16(accessp, &sasioupage0->
+		    PhyData[i].AttachedDevHandle);
+		mpt->m_phy_info[i].phy_device_type = cpdi[i];
+		mpt->m_phy_info[i].port_flags = port_flags;
+
+		if (port_flags & DISCOVERY_IN_PROGRESS) {
+			*retrypage0 = *retrypage0 + 1;
+			break;
+		} else {
+			*retrypage0 = 0;
+		}
+		if (!(port_flags & AUTO_PORT_CONFIGURATION)) {
+			/*
+			 * some PHY configuration described in
+			 * SAS IO Unit Page1
+			 */
+			*readpage1 = 1;
+		}
+	}
+
+	return (rval);
+}
+
+static int
+mptsas_sasiou_page_1_cb(mptsas_t *mpt, caddr_t page_memp,
+    ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
+    va_list ap)
+{
+#ifndef __lock_lint
+	_NOTE(ARGUNUSED(ap))
+#endif
+	int rval = DDI_SUCCESS;
+	pMpi2SasIOUnitPage1_t sasioupage1;
+	int i, num_phys;
+	uint32_t cpdi[8];
+	uint8_t port_flags;
+
+	if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
+		mptsas_log(mpt, CE_WARN, "mptsas_get_sas_io_unit_page1 "
+		    "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
+		    iocstatus, iocloginfo);
+		rval = DDI_FAILURE;
+		return (rval);
+	}
+
+	sasioupage1 = (pMpi2SasIOUnitPage1_t)page_memp;
+	num_phys = ddi_get8(accessp, &sasioupage1->NumPhys);
+	for (i = 0; i < num_phys; i++) {
+		cpdi[i] = ddi_get32(accessp, &sasioupage1->PhyData[i].
+		    ControllerPhyDeviceInfo);
+		port_flags = ddi_get8(accessp,
+		    &sasioupage1->PhyData[i].PortFlags);
+		mpt->m_phy_info[i].port_num =
+		    ddi_get8(accessp,
+		    &sasioupage1->PhyData[i].Port);
+		mpt->m_phy_info[i].port_flags = port_flags;
+		mpt->m_phy_info[i].phy_device_type = cpdi[i];
+
+	}
+	return (rval);
+}
+
+/*
+ * Read IO unit page 0 to get information for each PHY. If needed, Read IO Unit
+ * page1 to update the PHY information.  This is the message passing method of
+ * this function which should be called except during initialization.
+ */
+int
+mptsas_get_sas_io_unit_page(mptsas_t *mpt)
+{
+	int rval = DDI_SUCCESS, state;
+	uint32_t readpage1 = 0, retrypage0 = 0;
+
+	ASSERT(mutex_owned(&mpt->m_mutex));
+
+	/*
+	 * Now we cycle through the state machine.  Here's what happens:
+	 * 1. Read IO unit page 0 and set phy information
+	 * 2. See if Read IO unit page1 is needed because of port configuration
+	 * 3. Read IO unit page 1 and update phy information.
+	 */
+	state = IOUC_READ_PAGE0;
+	while (state != IOUC_DONE) {
+		if (state == IOUC_READ_PAGE0) {
+			rval = mptsas_access_config_page(mpt,
+			    MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
+			    MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 0, 0,
+			    mptsas_sasiou_page_0_cb, &readpage1,
+			    &retrypage0);
+		} else if (state == IOUC_READ_PAGE1) {
+			rval = mptsas_access_config_page(mpt,
+			    MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
+			    MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 1, 0,
+			    mptsas_sasiou_page_1_cb);
+		}
+
+		if (rval == DDI_SUCCESS) {
+			switch (state) {
+			case IOUC_READ_PAGE0:
+				/*
+				 * retry 30 times if discovery is in process
+				 */
+				if (retrypage0 && (retrypage0 < 30)) {
+					drv_usecwait(1000 * 100);
+					state = IOUC_READ_PAGE0;
+					break;
+				} else if (retrypage0 == 30) {
+					mptsas_log(mpt, CE_WARN,
+					    "!Discovery in progress, can't "
+					    "verify IO unit config, then "
+					    "after 30 times retry, give "
+					    "up!");
+					state = IOUC_DONE;
+					rval = DDI_FAILURE;
+					break;
+				}
+
+				if (readpage1 == 0) {
+					state = IOUC_DONE;
+					rval = DDI_SUCCESS;
+					break;
+				}
+
+				state = IOUC_READ_PAGE1;
+				break;
+
+			case IOUC_READ_PAGE1:
+				state = IOUC_DONE;
+				rval = DDI_SUCCESS;
+				break;
+			}
+		} else {
+			return (rval);
+		}
+	}
+
+	return (rval);
+}
+
+/*
+ * Read IO unit page 0 to get information for each PHY. If needed, Read IO Unit
+ * page1 to update the PHY information.  This is the handshaking version of
+ * this function, which should be called during initialization only.
+ */
+int
+mptsas_get_sas_io_unit_page_hndshk(mptsas_t *mpt)
+{
+	ddi_dma_attr_t		recv_dma_attrs, page_dma_attrs;
+	uint_t			recv_ncookie, page_ncookie;
+	ddi_dma_cookie_t	recv_cookie, page_cookie;
+	ddi_dma_handle_t	recv_dma_handle, page_dma_handle;
+	ddi_acc_handle_t	recv_accessp, page_accessp;
+	size_t			recv_alloc_len, page_alloc_len;
+	pMpi2ConfigReply_t	configreply;
+	pMpi2SasIOUnitPage0_t	sasioupage0;
+	pMpi2SasIOUnitPage1_t	sasioupage1;
+	int			recv_numbytes;
+	caddr_t			recv_memp, page_memp;
+	int			recv_dmastate = 0;
+	int			page_dmastate = 0;
+	int			i, num_phys;
+	int			page0_size =
+	    sizeof (MPI2_CONFIG_PAGE_SASIOUNIT_0) +
+	    (sizeof (MPI2_SAS_IO_UNIT0_PHY_DATA) * 7);
+	int			page1_size =
+	    sizeof (MPI2_CONFIG_PAGE_SASIOUNIT_1) +
+	    (sizeof (MPI2_SAS_IO_UNIT1_PHY_DATA) * 7);
+	uint32_t		flags_length;
+	uint32_t		cpdi[8], readpage1 = 0, retrypage0 = 0;
+	uint16_t		iocstatus;
+	uint8_t			port_flags, page_number, action;
+	uint32_t		reply_size = 256; /* Big enough for any page */
+	uint_t			state;
+	int			rval = DDI_FAILURE;
+
+	/*
+	 * Initialize our "state machine".  This is a bit convoluted,
+	 * but it keeps us from having to do the ddi allocations numerous
+	 * times.
+	 */
+
+	NDBG20(("mptsas_get_sas_io_unit_page_hndshk enter"));
+	ASSERT(mutex_owned(&mpt->m_mutex));
+	state = IOUC_READ_PAGE0;
+
+	/*
+	 * dynamically create a customized dma attribute structure
+	 * that describes mpt's config reply page request structure.
+	 */
+	recv_dma_attrs = mpt->m_msg_dma_attr;
+	recv_dma_attrs.dma_attr_sgllen = 1;
+	recv_dma_attrs.dma_attr_granular = (sizeof (MPI2_CONFIG_REPLY));
+
+	if (ddi_dma_alloc_handle(mpt->m_dip, &recv_dma_attrs,
+	    DDI_DMA_SLEEP, NULL, &recv_dma_handle) != DDI_SUCCESS) {
+		goto cleanup;
+	}
+
+	recv_dmastate |= MPTSAS_DMA_HANDLE_ALLOCD;
+
+	if (ddi_dma_mem_alloc(recv_dma_handle,
+	    (sizeof (MPI2_CONFIG_REPLY)),
+	    &mpt->m_dev_acc_attr, DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL,
+	    &recv_memp, &recv_alloc_len, &recv_accessp) != DDI_SUCCESS) {
+		goto cleanup;
+	}
+
+	recv_dmastate |= MPTSAS_DMA_MEMORY_ALLOCD;
+
+	if (ddi_dma_addr_bind_handle(recv_dma_handle, NULL, recv_memp,
+	    recv_alloc_len, DDI_DMA_RDWR | DDI_DMA_CONSISTENT, DDI_DMA_SLEEP,
+	    NULL, &recv_cookie, &recv_ncookie) != DDI_DMA_MAPPED) {
+		goto cleanup;
+	}
+
+	recv_dmastate |= MPTSAS_DMA_HANDLE_BOUND;
+
+	page_dma_attrs = mpt->m_msg_dma_attr;
+	page_dma_attrs.dma_attr_sgllen = 1;
+	page_dma_attrs.dma_attr_granular = reply_size;
+
+	if (ddi_dma_alloc_handle(mpt->m_dip, &page_dma_attrs,
+	    DDI_DMA_SLEEP, NULL, &page_dma_handle) != DDI_SUCCESS) {
+		goto cleanup;
+	}
+
+	page_dmastate |= MPTSAS_DMA_HANDLE_ALLOCD;
+
+	/*
+	 * Page 0 size is larger, so just use that for both.
+	 */
+
+	if (ddi_dma_mem_alloc(page_dma_handle, reply_size,
+	    &mpt->m_dev_acc_attr, DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL,
+	    &page_memp, &page_alloc_len, &page_accessp) != DDI_SUCCESS) {
+		goto cleanup;
+	}
+
+	page_dmastate |= MPTSAS_DMA_MEMORY_ALLOCD;
+
+	if (ddi_dma_addr_bind_handle(page_dma_handle, NULL, page_memp,
+	    page_alloc_len, DDI_DMA_RDWR | DDI_DMA_CONSISTENT, DDI_DMA_SLEEP,
+	    NULL, &page_cookie, &page_ncookie) != DDI_DMA_MAPPED) {
+		goto cleanup;
+	}
+
+	page_dmastate |= MPTSAS_DMA_HANDLE_BOUND;
+
+	/*
+	 * Now we cycle through the state machine.  Here's what happens:
+	 * 1. Read IO unit page 0 and set phy information
+	 * 2. See if Read IO unit page1 is needed because of port configuration
+	 * 3. Read IO unit page 1 and update phy information.
+	 */
+
+	sasioupage0 = (pMpi2SasIOUnitPage0_t)page_memp;
+	sasioupage1 = (pMpi2SasIOUnitPage1_t)page_memp;
+
+	while (state != IOUC_DONE) {
+		switch (state) {
+		case IOUC_READ_PAGE0:
+			page_number = 0;
+			action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
+			flags_length = (uint32_t)page0_size;
+			flags_length |= ((uint32_t)(
+			    MPI2_SGE_FLAGS_LAST_ELEMENT |
+			    MPI2_SGE_FLAGS_END_OF_BUFFER |
+			    MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
+			    MPI2_SGE_FLAGS_SYSTEM_ADDRESS |
+			    MPI2_SGE_FLAGS_32_BIT_ADDRESSING |
+			    MPI2_SGE_FLAGS_IOC_TO_HOST |
+			    MPI2_SGE_FLAGS_END_OF_LIST) <<
+			    MPI2_SGE_FLAGS_SHIFT);
+
+			break;
+
+		case IOUC_READ_PAGE1:
+			page_number = 1;
+			action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
+			flags_length = (uint32_t)page1_size;
+			flags_length |= ((uint32_t)(
+			    MPI2_SGE_FLAGS_LAST_ELEMENT |
+			    MPI2_SGE_FLAGS_END_OF_BUFFER |
+			    MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
+			    MPI2_SGE_FLAGS_SYSTEM_ADDRESS |
+			    MPI2_SGE_FLAGS_32_BIT_ADDRESSING |
+			    MPI2_SGE_FLAGS_IOC_TO_HOST |
+			    MPI2_SGE_FLAGS_END_OF_LIST) <<
+			    MPI2_SGE_FLAGS_SHIFT);
+
+			break;
+		default:
+			break;
+		}
+
+		bzero(recv_memp, sizeof (MPI2_CONFIG_REPLY));
+		configreply = (pMpi2ConfigReply_t)recv_memp;
+		recv_numbytes = sizeof (MPI2_CONFIG_REPLY);
+
+		if (mptsas_send_extended_config_request_msg(mpt,
+		    MPI2_CONFIG_ACTION_PAGE_HEADER,
+		    MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT,
+		    0, page_number, 0, 0, 0, 0)) {
+			goto cleanup;
+		}
+
+		if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
+		    recv_accessp)) {
+			goto cleanup;
+		}
+
+		iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus);
+		iocstatus = MPTSAS_IOCSTATUS(iocstatus);
+
+		if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
+			mptsas_log(mpt, CE_WARN,
+			    "mptsas_get_sas_io_unit_page_hndshk: read page "
+			    "header iocstatus = 0x%x", iocstatus);
+			goto cleanup;
+		}
+
+		if (action != MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM) {
+			bzero(page_memp, reply_size);
+		}
+
+		if (mptsas_send_extended_config_request_msg(mpt, action,
+		    MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 0, page_number,
+		    ddi_get8(recv_accessp, &configreply->Header.PageVersion),
+		    ddi_get16(recv_accessp, &configreply->ExtPageLength),
+		    flags_length, page_cookie.dmac_address)) {
+			goto cleanup;
+		}
+
+		if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
+		    recv_accessp)) {
+			goto cleanup;
+		}
+
+		iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus);
+		iocstatus = MPTSAS_IOCSTATUS(iocstatus);
+
+		if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
+			mptsas_log(mpt, CE_WARN,
+			    "mptsas_get_sas_io_unit_page_hndshk: IO unit "
+			    "config failed for action %d, iocstatus = 0x%x",
+			    action, iocstatus);
+			goto cleanup;
+		}
+
+		switch (state) {
+		case IOUC_READ_PAGE0:
+			if ((ddi_dma_sync(page_dma_handle, 0, 0,
+			    DDI_DMA_SYNC_FORCPU)) != DDI_SUCCESS) {
+				goto cleanup;
+			}
+
+			num_phys = ddi_get8(page_accessp,
+			    &sasioupage0->NumPhys);
+			for (i = 0; i < num_phys; i++) {
+				cpdi[i] = ddi_get32(page_accessp,
+				    &sasioupage0->PhyData[i].
+				    ControllerPhyDeviceInfo);
+				port_flags = ddi_get8(page_accessp,
+				    &sasioupage0->PhyData[i].PortFlags);
+
+				mpt->m_phy_info[i].port_num =
+				    ddi_get8(page_accessp,
+				    &sasioupage0->PhyData[i].Port);
+				mpt->m_phy_info[i].ctrl_devhdl =
+				    ddi_get16(page_accessp, &sasioupage0->
+				    PhyData[i].ControllerDevHandle);
+				mpt->m_phy_info[i].attached_devhdl =
+				    ddi_get16(page_accessp, &sasioupage0->
+				    PhyData[i].AttachedDevHandle);
+				mpt->m_phy_info[i].phy_device_type = cpdi[i];
+				mpt->m_phy_info[i].port_flags = port_flags;
+
+				if (port_flags & DISCOVERY_IN_PROGRESS) {
+					retrypage0++;
+					NDBG20(("Discovery in progress, can't "
+					    "verify IO unit config, then NO.%d"
+					    " times retry", retrypage0));
+					break;
+				} else {
+					retrypage0 = 0;
+				}
+				if (!(port_flags & AUTO_PORT_CONFIGURATION)) {
+					/*
+					 * some PHY configuration described in
+					 * SAS IO Unit Page1
+					 */
+					readpage1 = 1;
+				}
+			}
+
+			/*
+			 * retry 30 times if discovery is in process
+			 */
+			if (retrypage0 && (retrypage0 < 30)) {
+				drv_usecwait(1000 * 100);
+				state = IOUC_READ_PAGE0;
+				break;
+			} else if (retrypage0 == 30) {
+				mptsas_log(mpt, CE_WARN,
+				    "!Discovery in progress, can't "
+				    "verify IO unit config, then after"
+				    " 30 times retry, give up!");
+				state = IOUC_DONE;
+				rval = DDI_FAILURE;
+				break;
+			}
+
+			if (readpage1 == 0) {
+				state = IOUC_DONE;
+				rval = DDI_SUCCESS;
+				break;
+			}
+
+			state = IOUC_READ_PAGE1;
+			break;
+
+		case IOUC_READ_PAGE1:
+			if ((ddi_dma_sync(page_dma_handle, 0, 0,
+			    DDI_DMA_SYNC_FORCPU)) != DDI_SUCCESS) {
+				goto cleanup;
+			}
+
+			num_phys = ddi_get8(page_accessp,
+			    &sasioupage1->NumPhys);
+
+			for (i = 0; i < num_phys; i++) {
+				cpdi[i] = ddi_get32(page_accessp,
+				    &sasioupage1->PhyData[i].
+				    ControllerPhyDeviceInfo);
+				port_flags = ddi_get8(page_accessp,
+				    &sasioupage1->PhyData[i].PortFlags);
+				mpt->m_phy_info[i].port_num =
+				    ddi_get8(page_accessp,
+				    &sasioupage1->PhyData[i].Port);
+				mpt->m_phy_info[i].port_flags = port_flags;
+				mpt->m_phy_info[i].phy_device_type = cpdi[i];
+
+			}
+
+			state = IOUC_DONE;
+			rval = DDI_SUCCESS;
+			break;
+		}
+	}
+	if ((mptsas_check_dma_handle(recv_dma_handle) != DDI_SUCCESS) ||
+	    (mptsas_check_dma_handle(page_dma_handle) != DDI_SUCCESS)) {
+		ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
+		rval = DDI_FAILURE;
+		goto cleanup;
+	}
+	if ((mptsas_check_acc_handle(recv_accessp) != DDI_SUCCESS) ||
+	    (mptsas_check_acc_handle(page_accessp) != DDI_SUCCESS)) {
+		ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
+		rval = DDI_FAILURE;
+		goto cleanup;
+	}
+
+cleanup:
+	if (recv_dmastate & MPTSAS_DMA_HANDLE_BOUND)
+		(void) ddi_dma_unbind_handle(recv_dma_handle);
+	if (page_dmastate & MPTSAS_DMA_HANDLE_BOUND)
+		(void) ddi_dma_unbind_handle(page_dma_handle);
+	if (recv_dmastate & MPTSAS_DMA_MEMORY_ALLOCD)
+		(void) ddi_dma_mem_free(&recv_accessp);
+	if (page_dmastate & MPTSAS_DMA_MEMORY_ALLOCD)
+		(void) ddi_dma_mem_free(&page_accessp);
+	if (recv_dmastate & MPTSAS_DMA_HANDLE_ALLOCD)
+		ddi_dma_free_handle(&recv_dma_handle);
+	if (page_dmastate & MPTSAS_DMA_HANDLE_ALLOCD)
+		ddi_dma_free_handle(&page_dma_handle);
+
+	if (rval != DDI_SUCCESS) {
+		mptsas_fm_ereport(mpt, DDI_FM_DEVICE_NO_RESPONSE);
+		ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_LOST);
+	}
+	return (rval);
+}
+
+/*
+ * Check if the PHYs are currently in target mode. If they are not, we don't
+ * need to change anything.  Otherwise, we need to modify the appropriate bits
+ * and write them to IO unit page 1.  Once that is done, an IO unit reset is
+ * necessary to begin operating in initiator mode.  Since this function is only
+ * called during the initialization process, use handshaking.
+ */
+int
+mptsas_set_initiator_mode(mptsas_t *mpt)
+{
+	ddi_dma_attr_t		recv_dma_attrs, page_dma_attrs;
+	uint_t			recv_ncookie, page_ncookie;
+	ddi_dma_cookie_t	recv_cookie, page_cookie;
+	ddi_dma_handle_t	recv_dma_handle, page_dma_handle;
+	ddi_acc_handle_t	recv_accessp, page_accessp;
+	size_t			recv_alloc_len, page_alloc_len;
+	pMpi2ConfigReply_t	configreply;
+	pMpi2SasIOUnitPage1_t	sasioupage1;
+	int			recv_numbytes;
+	caddr_t			recv_memp, page_memp;
+	int			recv_dmastate = 0;
+	int			page_dmastate = 0;
+	int			i;
+	int			page1_size =
+	    sizeof (MPI2_CONFIG_PAGE_SASIOUNIT_1) +
+	    (sizeof (MPI2_SAS_IO_UNIT0_PHY_DATA) * 7);
+	uint32_t		flags_length;
+	uint32_t		cpdi[8], reprogram = 0;
+	uint16_t		iocstatus;
+	uint8_t			port_flags, page_number, action;
+	uint32_t		reply_size = 256; /* Big enough for any page */
+	uint_t			state;
+	int			rval = DDI_FAILURE;
+
+	ASSERT(mutex_owned(&mpt->m_mutex));
+	/*
+	 * get each PHY informations from SAS IO Unit Pages.  Use handshakiing
+	 * to get SAS IO Unit Page information since this is during init.
+	 */
+	rval = mptsas_get_sas_io_unit_page_hndshk(mpt);
+	if (rval != DDI_SUCCESS)
+		return (rval);
+
+	for (i = 0; i < mpt->m_num_phys; i++) {
+		if (mpt->m_phy_info[i].phy_device_type &
+		    MPI2_SAS_DEVICE_INFO_SSP_TARGET) {
+			reprogram = 1;
+			break;
+		}
+	}
+	if (reprogram == 0)
+		return (DDI_SUCCESS);
+
+	/*
+	 * Initialize our "state machine".  This is a bit convoluted,
+	 * but it keeps us from having to do the ddi allocations numerous
+	 * times.
+	 */
+
+	state = IOUC_READ_PAGE1;
+
+	/*
+	 * dynamically create a customized dma attribute structure
+	 * that describes mpt's config reply page request structure.
+	 */
+	recv_dma_attrs = mpt->m_msg_dma_attr;
+	recv_dma_attrs.dma_attr_sgllen = 1;
+	recv_dma_attrs.dma_attr_granular = (sizeof (MPI2_CONFIG_REPLY));
+
+	if (ddi_dma_alloc_handle(mpt->m_dip, &recv_dma_attrs,
+	    DDI_DMA_SLEEP, NULL, &recv_dma_handle) != DDI_SUCCESS) {
+		goto cleanup;
+	}
+
+	recv_dmastate |= MPTSAS_DMA_HANDLE_ALLOCD;
+
+	if (ddi_dma_mem_alloc(recv_dma_handle,
+	    (sizeof (MPI2_CONFIG_REPLY)),
+	    &mpt->m_dev_acc_attr, DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL,
+	    &recv_memp, &recv_alloc_len, &recv_accessp) != DDI_SUCCESS) {
+		goto cleanup;
+	}
+
+	recv_dmastate |= MPTSAS_DMA_MEMORY_ALLOCD;
+
+	if (ddi_dma_addr_bind_handle(recv_dma_handle, NULL, recv_memp,
+	    recv_alloc_len, DDI_DMA_RDWR | DDI_DMA_CONSISTENT, DDI_DMA_SLEEP,
+	    NULL, &recv_cookie, &recv_ncookie) != DDI_DMA_MAPPED) {
+		goto cleanup;
+	}
+
+	recv_dmastate |= MPTSAS_DMA_HANDLE_BOUND;
+
+	page_dma_attrs = mpt->m_msg_dma_attr;
+	page_dma_attrs.dma_attr_sgllen = 1;
+	page_dma_attrs.dma_attr_granular = reply_size;
+
+	if (ddi_dma_alloc_handle(mpt->m_dip, &page_dma_attrs,
+	    DDI_DMA_SLEEP, NULL, &page_dma_handle) != DDI_SUCCESS) {
+		goto cleanup;
+	}
+
+	page_dmastate |= MPTSAS_DMA_HANDLE_ALLOCD;
+
+	if (ddi_dma_mem_alloc(page_dma_handle, reply_size,
+	    &mpt->m_dev_acc_attr, DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL,
+	    &page_memp, &page_alloc_len, &page_accessp) != DDI_SUCCESS) {
+		goto cleanup;
+	}
+
+	page_dmastate |= MPTSAS_DMA_MEMORY_ALLOCD;
+
+	if (ddi_dma_addr_bind_handle(page_dma_handle, NULL, page_memp,
+	    page_alloc_len, DDI_DMA_RDWR | DDI_DMA_CONSISTENT, DDI_DMA_SLEEP,
+	    NULL, &page_cookie, &page_ncookie) != DDI_DMA_MAPPED) {
+		goto cleanup;
+	}
+
+	page_dmastate |= MPTSAS_DMA_HANDLE_BOUND;
+
+	/*
+	 * Now we cycle through the state machine.  Here's what happens:
+	 * 1. Read IO unit page 1.
+	 * 2. Change the appropriate bits
+	 * 3. Write the updated settings to IO unit page 1.
+	 * 4. Reset the IO unit.
+	 */
+
+	sasioupage1 = (pMpi2SasIOUnitPage1_t)page_memp;
+
+	while (state != IOUC_DONE) {
+		switch (state) {
+		case IOUC_READ_PAGE1:
+			page_number = 1;
+			action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
+			flags_length = (uint32_t)page1_size;
+			flags_length |= ((uint32_t)(
+			    MPI2_SGE_FLAGS_LAST_ELEMENT |
+			    MPI2_SGE_FLAGS_END_OF_BUFFER |
+			    MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
+			    MPI2_SGE_FLAGS_SYSTEM_ADDRESS |
+			    MPI2_SGE_FLAGS_32_BIT_ADDRESSING |
+			    MPI2_SGE_FLAGS_IOC_TO_HOST |
+			    MPI2_SGE_FLAGS_END_OF_LIST) <<
+			    MPI2_SGE_FLAGS_SHIFT);
+
+			break;
+
+		case IOUC_WRITE_PAGE1:
+			page_number = 1;
+			action = MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM;
+			flags_length = (uint32_t)page1_size;
+			flags_length |= ((uint32_t)(
+			    MPI2_SGE_FLAGS_LAST_ELEMENT |
+			    MPI2_SGE_FLAGS_END_OF_BUFFER |
+			    MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
+			    MPI2_SGE_FLAGS_SYSTEM_ADDRESS |
+			    MPI2_SGE_FLAGS_32_BIT_ADDRESSING |
+			    MPI2_SGE_FLAGS_HOST_TO_IOC |
+			    MPI2_SGE_FLAGS_END_OF_LIST) <<
+			    MPI2_SGE_FLAGS_SHIFT);
+
+			break;
+		}
+
+		bzero(recv_memp, sizeof (MPI2_CONFIG_REPLY));
+		configreply = (pMpi2ConfigReply_t)recv_memp;
+		recv_numbytes = sizeof (MPI2_CONFIG_REPLY);
+
+		if (mptsas_send_extended_config_request_msg(mpt,
+		    MPI2_CONFIG_ACTION_PAGE_HEADER,
+		    MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT,
+		    0, page_number, 0, 0, 0, 0)) {
+			goto cleanup;
+		}
+
+		if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
+		    recv_accessp)) {
+			goto cleanup;
+		}
+
+		iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus);
+		iocstatus = MPTSAS_IOCSTATUS(iocstatus);
+
+		if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
+			mptsas_log(mpt, CE_WARN,
+			    "mptsas_set_initiator_mode: read page hdr iocstatus"
+			    ": 0x%x", iocstatus);
+			goto cleanup;
+		}
+
+		if (action != MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM) {
+			bzero(page_memp, reply_size);
+		}
+
+		if (mptsas_send_extended_config_request_msg(mpt, action,
+		    MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 0, page_number,
+		    ddi_get8(recv_accessp, &configreply->Header.PageVersion),
+		    ddi_get16(recv_accessp, &configreply->ExtPageLength),
+		    flags_length, page_cookie.dmac_address)) {
+			goto cleanup;
+		}
+
+		if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
+		    recv_accessp)) {
+			goto cleanup;
+		}
+
+		iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus);
+		iocstatus = MPTSAS_IOCSTATUS(iocstatus);
+
+		if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
+			mptsas_log(mpt, CE_WARN,
+			    "mptsas_set_initiator_mode: IO unit config failed "
+			    "for action %d, iocstatus = 0x%x", action,
+			    iocstatus);
+			goto cleanup;
+		}
+
+		switch (state) {
+		case IOUC_READ_PAGE1:
+			if ((ddi_dma_sync(page_dma_handle, 0, 0,
+			    DDI_DMA_SYNC_FORCPU)) != DDI_SUCCESS) {
+				goto cleanup;
+			}
+
+			/*
+			 * All the PHYs should have the same settings, so we
+			 * really only need to read 1 and use its config for
+			 * every PHY.
+			 */
+
+			cpdi[0] = ddi_get32(page_accessp,
+			    &sasioupage1->PhyData[0].ControllerPhyDeviceInfo);
+			port_flags = ddi_get8(page_accessp,
+			    &sasioupage1->PhyData[0].PortFlags);
+			port_flags |=
+			    MPI2_SASIOUNIT1_PORT_FLAGS_AUTO_PORT_CONFIG;
+
+			/*
+			 * Write the configuration to SAS I/O unit page 1
+			 */
+
+			mptsas_log(mpt, CE_NOTE,
+			    "?IO unit in target mode, changing to initiator");
+
+			/*
+			 * Modify the PHY settings for initiator mode
+			 */
+
+			cpdi[0] &= ~MPI2_SAS_DEVICE_INFO_SSP_TARGET;
+			cpdi[0] |= (MPI2_SAS_DEVICE_INFO_SSP_INITIATOR |
+			    MPI2_SAS_DEVICE_INFO_STP_INITIATOR |
+			    MPI2_SAS_DEVICE_INFO_SMP_INITIATOR);
+
+			for (i = 0; i < mpt->m_num_phys; i++) {
+				ddi_put32(page_accessp,
+				    &sasioupage1->PhyData[i].
+				    ControllerPhyDeviceInfo, cpdi[0]);
+				ddi_put8(page_accessp,
+				    &sasioupage1->PhyData[i].
+				    PortFlags, port_flags);
+				/*
+				 * update phy information
+				 */
+				mpt->m_phy_info[i].phy_device_type = cpdi[0];
+				mpt->m_phy_info[i].port_flags = port_flags;
+			}
+
+			if ((ddi_dma_sync(page_dma_handle, 0, 0,
+			    DDI_DMA_SYNC_FORDEV)) != DDI_SUCCESS) {
+				goto cleanup;
+			}
+
+			state = IOUC_WRITE_PAGE1;
+
+			break;
+
+		case IOUC_WRITE_PAGE1:
+			/*
+			 * If we're here, we wrote IO unit page 1 succesfully.
+			 */
+			state = IOUC_DONE;
+
+			rval = DDI_SUCCESS;
+			break;
+		}
+	}
+
+	/*
+	 * We need to do a Message Unit Reset in order to activate the changes.
+	 */
+	mpt->m_softstate |= MPTSAS_SS_MSG_UNIT_RESET;
+	rval = mptsas_init_chip(mpt, FALSE);
+
+cleanup:
+	if (recv_dmastate & MPTSAS_DMA_HANDLE_BOUND)
+		(void) ddi_dma_unbind_handle(recv_dma_handle);
+	if (page_dmastate & MPTSAS_DMA_HANDLE_BOUND)
+		(void) ddi_dma_unbind_handle(page_dma_handle);
+	if (recv_dmastate & MPTSAS_DMA_MEMORY_ALLOCD)
+		(void) ddi_dma_mem_free(&recv_accessp);
+	if (page_dmastate & MPTSAS_DMA_MEMORY_ALLOCD)
+		(void) ddi_dma_mem_free(&page_accessp);
+	if (recv_dmastate & MPTSAS_DMA_HANDLE_ALLOCD)
+		ddi_dma_free_handle(&recv_dma_handle);
+	if (page_dmastate & MPTSAS_DMA_HANDLE_ALLOCD)
+		ddi_dma_free_handle(&page_dma_handle);
+
+	return (rval);
+}
+
+/*
+ * mptsas_get_manufacture_page5
+ *
+ * This function will retrieve the base WWID from the adapter.  Since this
+ * function is only called during the initialization process, use handshaking.
+ */
+int
+mptsas_get_manufacture_page5(mptsas_t *mpt)
+{
+	ddi_dma_attr_t			recv_dma_attrs, page_dma_attrs;
+	ddi_dma_cookie_t		recv_cookie, page_cookie;
+	ddi_dma_handle_t		recv_dma_handle, page_dma_handle;
+	ddi_acc_handle_t		recv_accessp, page_accessp;
+	size_t				recv_alloc_len, page_alloc_len;
+	pMpi2ConfigReply_t		configreply;
+	uint_t				recv_ncookie, page_ncookie;
+	caddr_t				recv_memp, page_memp;
+	int				recv_numbytes;
+	pMpi2ManufacturingPage5_t	m5;
+	int				recv_dmastate = 0;
+	int				page_dmastate = 0;
+	uint32_t			flagslength;
+	int				rval = DDI_SUCCESS;
+	uint_t				iocstatus;
+
+	MPTSAS_DISABLE_INTR(mpt);
+
+	if (mptsas_send_config_request_msg(mpt, MPI2_CONFIG_ACTION_PAGE_HEADER,
+	    MPI2_CONFIG_PAGETYPE_MANUFACTURING, 0, 5, 0, 0, 0, 0)) {
+		rval = DDI_FAILURE;
+		goto done;
+	}
+
+	/*
+	 * dynamically create a customized dma attribute structure
+	 * that describes the MPT's config reply page request structure.
+	 */
+	recv_dma_attrs = mpt->m_msg_dma_attr;
+	recv_dma_attrs.dma_attr_sgllen = 1;
+	recv_dma_attrs.dma_attr_granular = (sizeof (MPI2_CONFIG_REPLY));
+
+	if (ddi_dma_alloc_handle(mpt->m_dip, &recv_dma_attrs,
+	    DDI_DMA_SLEEP, NULL, &recv_dma_handle) != DDI_SUCCESS) {
+		mptsas_log(mpt, CE_WARN,
+		    "(unable to allocate dma handle.");
+		rval = DDI_FAILURE;
+		goto done;
+	}
+	recv_dmastate |= MPTSAS_DMA_HANDLE_ALLOCD;
+
+	if (ddi_dma_mem_alloc(recv_dma_handle,
+	    (sizeof (MPI2_CONFIG_REPLY)),
+	    &mpt->m_dev_acc_attr, DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL,
+	    &recv_memp, &recv_alloc_len, &recv_accessp) != DDI_SUCCESS) {
+		mptsas_log(mpt, CE_WARN,
+		    "unable to allocate config_reply structure.");
+		rval = DDI_FAILURE;
+		goto done;
+	}
+	recv_dmastate |= MPTSAS_DMA_MEMORY_ALLOCD;
+
+	if (ddi_dma_addr_bind_handle(recv_dma_handle, NULL, recv_memp,
+	    recv_alloc_len, DDI_DMA_RDWR | DDI_DMA_CONSISTENT, DDI_DMA_SLEEP,
+	    NULL, &recv_cookie, &recv_ncookie) != DDI_DMA_MAPPED) {
+		mptsas_log(mpt, CE_WARN, "unable to bind DMA resources.");
+		rval = DDI_FAILURE;
+		goto done;
+	}
+	recv_dmastate |= MPTSAS_DMA_HANDLE_BOUND;
+	bzero(recv_memp, sizeof (MPI2_CONFIG_REPLY));
+	configreply = (pMpi2ConfigReply_t)recv_memp;
+	recv_numbytes = sizeof (MPI2_CONFIG_REPLY);
+
+	/*
+	 * get config reply message
+	 */
+	if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
+	    recv_accessp)) {
+		rval = DDI_FAILURE;
+		goto done;
+	}
+
+	if (iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus)) {
+		mptsas_log(mpt, CE_WARN, "mptsas_get_manufacture_page5 update: "
+		    "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
+		    ddi_get32(recv_accessp, &configreply->IOCLogInfo));
+		goto done;
+	}
+
+	/*
+	 * dynamically create a customized dma attribute structure
+	 * that describes the MPT's config page structure.
+	 */
+	page_dma_attrs = mpt->m_msg_dma_attr;
+	page_dma_attrs.dma_attr_sgllen = 1;
+	page_dma_attrs.dma_attr_granular = (sizeof (MPI2_CONFIG_PAGE_MAN_5));
+
+	if (ddi_dma_alloc_handle(mpt->m_dip, &page_dma_attrs,
+	    DDI_DMA_SLEEP, NULL, &page_dma_handle) != DDI_SUCCESS) {
+		mptsas_log(mpt, CE_WARN,
+		    "(unable to allocate dma handle.");
+		rval = DDI_FAILURE;
+		goto done;
+	}
+	page_dmastate |= MPTSAS_DMA_HANDLE_ALLOCD;
+
+	if (ddi_dma_mem_alloc(page_dma_handle,
+	    (sizeof (MPI2_CONFIG_PAGE_MAN_5)),
+	    &mpt->m_dev_acc_attr, DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL,
+	    &page_memp, &page_alloc_len, &page_accessp) != DDI_SUCCESS) {
+		mptsas_log(mpt, CE_WARN,
+		    "unable to allocate manufacturing page structure.");
+		rval = DDI_FAILURE;
+		goto done;
+	}
+	page_dmastate |= MPTSAS_DMA_MEMORY_ALLOCD;
+
+	if (ddi_dma_addr_bind_handle(page_dma_handle, NULL, page_memp,
+	    page_alloc_len, DDI_DMA_RDWR | DDI_DMA_CONSISTENT, DDI_DMA_SLEEP,
+	    NULL, &page_cookie, &page_ncookie) != DDI_DMA_MAPPED) {
+		mptsas_log(mpt, CE_WARN, "unable to bind DMA resources.");
+		rval = DDI_FAILURE;
+		goto done;
+	}
+	page_dmastate |= MPTSAS_DMA_HANDLE_BOUND;
+	bzero(page_memp, sizeof (MPI2_CONFIG_PAGE_MAN_5));
+	m5 = (pMpi2ManufacturingPage5_t)page_memp;
+
+	/*
+	 * Give reply address to IOC to store config page in and send
+	 * config request out.
+	 */
+
+	flagslength = sizeof (MPI2_CONFIG_PAGE_MAN_5);
+	flagslength |= ((uint32_t)(MPI2_SGE_FLAGS_LAST_ELEMENT |
+	    MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
+	    MPI2_SGE_FLAGS_SYSTEM_ADDRESS | MPI2_SGE_FLAGS_32_BIT_ADDRESSING |
+	    MPI2_SGE_FLAGS_IOC_TO_HOST |
+	    MPI2_SGE_FLAGS_END_OF_LIST) << MPI2_SGE_FLAGS_SHIFT);
+
+	if (mptsas_send_config_request_msg(mpt,
+	    MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
+	    MPI2_CONFIG_PAGETYPE_MANUFACTURING, 0, 5,
+	    ddi_get8(recv_accessp, &configreply->Header.PageVersion),
+	    ddi_get8(recv_accessp, &configreply->Header.PageLength),
+	    flagslength, page_cookie.dmac_address)) {
+		rval = DDI_FAILURE;
+		goto done;
+	}
+
+	/*
+	 * get reply view handshake
+	 */
+	if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
+	    recv_accessp)) {
+		rval = DDI_FAILURE;
+		goto done;
+	}
+
+	if (iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus)) {
+		mptsas_log(mpt, CE_WARN, "mptsas_get_manufacture_page5 config: "
+		    "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
+		    ddi_get32(recv_accessp, &configreply->IOCLogInfo));
+		goto done;
+	}
+
+	(void) ddi_dma_sync(page_dma_handle, 0, 0, DDI_DMA_SYNC_FORCPU);
+
+	/*
+	 * Fusion-MPT stores fields in little-endian format.  This is
+	 * why the low-order 32 bits are stored first.
+	 */
+	mpt->un.sasaddr.m_base_wwid_lo =
+	    ddi_get32(page_accessp, (uint32_t *)(void *)&m5->Phy[0].WWID);
+	mpt->un.sasaddr.m_base_wwid_hi =
+	    ddi_get32(page_accessp, (uint32_t *)(void *)&m5->Phy[0].WWID + 1);
+
+	if (ddi_prop_update_int64(DDI_DEV_T_NONE, mpt->m_dip,
+	    "base-wwid", mpt->un.m_base_wwid) != DDI_PROP_SUCCESS) {
+		NDBG2(("%s%d: failed to create base-wwid property",
+		    ddi_driver_name(mpt->m_dip), ddi_get_instance(mpt->m_dip)));
+	}
+
+	/*
+	 * Set the number of PHYs present.
+	 */
+	mpt->m_num_phys = ddi_get8(page_accessp, (uint8_t *)&m5->NumPhys);
+
+	if (ddi_prop_update_int(DDI_DEV_T_NONE, mpt->m_dip,
+	    "num-phys", mpt->m_num_phys) != DDI_PROP_SUCCESS) {
+		NDBG2(("%s%d: failed to create num-phys property",
+		    ddi_driver_name(mpt->m_dip), ddi_get_instance(mpt->m_dip)));
+	}
+
+	mptsas_log(mpt, CE_NOTE, "!mpt%d: Initiator WWNs: 0x%016llx-0x%016llx",
+	    mpt->m_instance, (unsigned long long)mpt->un.m_base_wwid,
+	    (unsigned long long)mpt->un.m_base_wwid + mpt->m_num_phys - 1);
+
+	if ((mptsas_check_dma_handle(recv_dma_handle) != DDI_SUCCESS) ||
+	    (mptsas_check_dma_handle(page_dma_handle) != DDI_SUCCESS)) {
+		ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
+		rval = DDI_FAILURE;
+		goto done;
+	}
+	if ((mptsas_check_acc_handle(recv_accessp) != DDI_SUCCESS) ||
+	    (mptsas_check_acc_handle(page_accessp) != DDI_SUCCESS)) {
+		ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
+		rval = DDI_FAILURE;
+	}
+done:
+	/*
+	 * free up memory
+	 */
+	if (recv_dmastate & MPTSAS_DMA_HANDLE_BOUND)
+		(void) ddi_dma_unbind_handle(recv_dma_handle);
+	if (page_dmastate & MPTSAS_DMA_HANDLE_BOUND)
+		(void) ddi_dma_unbind_handle(page_dma_handle);
+	if (recv_dmastate & MPTSAS_DMA_MEMORY_ALLOCD)
+		(void) ddi_dma_mem_free(&recv_accessp);
+	if (page_dmastate & MPTSAS_DMA_MEMORY_ALLOCD)
+		(void) ddi_dma_mem_free(&page_accessp);
+	if (recv_dmastate & MPTSAS_DMA_HANDLE_ALLOCD)
+		ddi_dma_free_handle(&recv_dma_handle);
+	if (page_dmastate & MPTSAS_DMA_HANDLE_ALLOCD)
+		ddi_dma_free_handle(&page_dma_handle);
+
+	MPTSAS_ENABLE_INTR(mpt);
+
+	return (rval);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas_init.c	Fri Jun 19 20:12:07 2009 +0800
@@ -0,0 +1,646 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Copyright (c) 2000 to 2009, LSI Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms of all code within
+ * this file that is exclusively owned by LSI, with or without
+ * modification, is permitted provided that, in addition to the CDDL 1.0
+ * License requirements, the following conditions are met:
+ *
+ *    Neither the name of the author nor the names of its contributors may be
+ *    used to endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ */
+
+/*
+ * mptsas_init - This file contains all the functions used to initialize
+ * MPT2.0 based hardware.
+ */
+
+#if defined(lint) || defined(DEBUG)
+#define	MPTSAS_DEBUG
+#endif
+
+/*
+ * standard header files
+ */
+#include <sys/note.h>
+#include <sys/scsi/scsi.h>
+
+#pragma pack(1)
+#include <sys/scsi/adapters/mpt_sas/mpi/mpi2_type.h>
+#include <sys/scsi/adapters/mpt_sas/mpi/mpi2.h>
+#include <sys/scsi/adapters/mpt_sas/mpi/mpi2_cnfg.h>
+#include <sys/scsi/adapters/mpt_sas/mpi/mpi2_init.h>
+#include <sys/scsi/adapters/mpt_sas/mpi/mpi2_ioc.h>
+#pragma pack()
+/*
+ * private header files.
+ */
+#include <sys/scsi/adapters/mpt_sas/mptsas_var.h>
+
+static int mptsas_ioc_do_get_facts(mptsas_t *mpt, caddr_t memp, int var,
+	ddi_acc_handle_t accessp);
+static int mptsas_ioc_do_get_facts_reply(mptsas_t *mpt, caddr_t memp, int var,
+	ddi_acc_handle_t accessp);
+static int mptsas_ioc_do_get_port_facts(mptsas_t *mpt, caddr_t memp, int var,
+	ddi_acc_handle_t accessp);
+static int mptsas_ioc_do_get_port_facts_reply(mptsas_t *mpt, caddr_t memp,
+    int var, ddi_acc_handle_t accessp);
+static int mptsas_ioc_do_enable_port(mptsas_t *mpt, caddr_t memp, int var,
+	ddi_acc_handle_t accessp);
+static int mptsas_ioc_do_enable_port_reply(mptsas_t *mpt, caddr_t memp, int var,
+	ddi_acc_handle_t accessp);
+static int mptsas_ioc_do_enable_event_notification(mptsas_t *mpt, caddr_t memp,
+	int var, ddi_acc_handle_t accessp);
+static int mptsas_ioc_do_enable_event_notification_reply(mptsas_t *mpt,
+    caddr_t memp, int var, ddi_acc_handle_t accessp);
+static int mptsas_do_ioc_init(mptsas_t *mpt, caddr_t memp, int var,
+	ddi_acc_handle_t accessp);
+static int mptsas_do_ioc_init_reply(mptsas_t *mpt, caddr_t memp, int var,
+	ddi_acc_handle_t accessp);
+
+static const char *
+mptsas_product_type_string(mptsas_t *mpt)
+{
+	switch (mpt->m_productid & MPI2_FW_HEADER_PID_PROD_MASK) {
+
+	case MPI2_FW_HEADER_PID_PROD_A:
+		return ("A");
+	default:
+		return ("?");
+	}
+}
+
+int
+mptsas_ioc_get_facts(mptsas_t *mpt)
+{
+	/*
+	 * Send get facts messages
+	 */
+	if (mptsas_do_dma(mpt, sizeof (MPI2_IOC_FACTS_REQUEST), NULL,
+	    mptsas_ioc_do_get_facts)) {
+		return (DDI_FAILURE);
+	}
+
+	/*
+	 * Get facts reply messages
+	 */
+	if (mptsas_do_dma(mpt, sizeof (MPI2_IOC_FACTS_REPLY), NULL,
+	    mptsas_ioc_do_get_facts_reply)) {
+		return (DDI_FAILURE);
+	}
+
+	return (DDI_SUCCESS);
+}
+
+static int
+mptsas_ioc_do_get_facts(mptsas_t *mpt, caddr_t memp, int var,
+		ddi_acc_handle_t accessp)
+{
+#ifndef __lock_lint
+	_NOTE(ARGUNUSED(var))
+#endif
+	pMpi2IOCFactsRequest_t	facts;
+	int			numbytes;
+
+	bzero(memp, sizeof (*facts));
+	facts = (void *)memp;
+	ddi_put8(accessp, &facts->Function, MPI2_FUNCTION_IOC_FACTS);
+	numbytes = sizeof (*facts);
+
+	/*
+	 * Post message via handshake
+	 */
+	if (mptsas_send_handshake_msg(mpt, memp, numbytes, accessp)) {
+		return (DDI_FAILURE);
+	}
+
+	return (DDI_SUCCESS);
+}
+
+static int
+mptsas_ioc_do_get_facts_reply(mptsas_t *mpt, caddr_t memp, int var,
+		ddi_acc_handle_t accessp)
+{
+#ifndef __lock_lint
+	_NOTE(ARGUNUSED(var))
+#endif
+
+	pMpi2IOCFactsReply_t	factsreply;
+	int			numbytes;
+	uint_t			iocstatus;
+	char			buf[32];
+	uint16_t		numReplyFrames;
+	uint16_t		queueSize, queueDiff;
+	int			simple_sge_main;
+	int			simple_sge_next;
+
+	bzero(memp, sizeof (*factsreply));
+	factsreply = (void *)memp;
+	numbytes = sizeof (*factsreply);
+
+	/*
+	 * get ioc facts reply message
+	 */
+	if (mptsas_get_handshake_msg(mpt, memp, numbytes, accessp)) {
+		return (DDI_FAILURE);
+	}
+
+	if (iocstatus = ddi_get16(accessp, &factsreply->IOCStatus)) {
+		mptsas_log(mpt, CE_WARN, "mptsas_ioc_do_get_facts_reply: "
+		    "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
+		    ddi_get32(accessp, &factsreply->IOCLogInfo));
+		return (DDI_FAILURE);
+	}
+
+	/*
+	 * store key values from reply to mpt structure
+	 */
+	mpt->m_fwversion = ddi_get32(accessp, &factsreply->FWVersion.Word);
+	mpt->m_productid = ddi_get16(accessp, &factsreply->ProductID);
+
+
+	(void) sprintf(buf, "%u.%u.%u.%u",
+	    ddi_get8(accessp, &factsreply->FWVersion.Struct.Major),
+	    ddi_get8(accessp, &factsreply->FWVersion.Struct.Minor),
+	    ddi_get8(accessp, &factsreply->FWVersion.Struct.Unit),
+	    ddi_get8(accessp, &factsreply->FWVersion.Struct.Dev));
+	mptsas_log(mpt, CE_NOTE, "?mpt%d Firmware version v%s (%s)\n",
+	    mpt->m_instance, buf, mptsas_product_type_string(mpt));
+	(void) ddi_prop_update_string(DDI_DEV_T_NONE, mpt->m_dip,
+	    "firmware-version", buf);
+
+	/*
+	 * Set up request info.
+	 */
+	mpt->m_max_requests = ddi_get16(accessp,
+	    &factsreply->RequestCredit) - 1;
+	mpt->m_req_frame_size = ddi_get16(accessp,
+	    &factsreply->IOCRequestFrameSize) * 4;
+
+	/*
+	 * Size of reply free queue should be the number of requests
+	 * plus some additional for events (32).  Make sure number of
+	 * reply frames is not a multiple of 16 so that the queue sizes
+	 * are calculated correctly later to be a multiple of 16.
+	 */
+	mpt->m_reply_frame_size = ddi_get8(accessp,
+	    &factsreply->ReplyFrameSize) * 4;
+	numReplyFrames = mpt->m_max_requests + 32;
+	if (!(numReplyFrames % 16)) {
+		numReplyFrames--;
+	}
+	mpt->m_max_replies = numReplyFrames;
+	queueSize = numReplyFrames;
+	queueSize += 16 - (queueSize % 16);
+	mpt->m_free_queue_depth = queueSize;
+
+	/*
+	 * Size of reply descriptor post queue should be the number of
+	 * request frames + the number of reply frames + 1 and needs to
+	 * be a multiple of 16.  This size can be no larger than
+	 * MaxReplyDescriptorPostQueueDepth from IOCFacts.  If the
+	 * calculated queue size is larger than allowed, subtract a
+	 * multiple of 16 from m_max_requests, m_max_replies, and
+	 * m_reply_free_depth.
+	 */
+	queueSize = mpt->m_max_requests + numReplyFrames + 1;
+	if (queueSize % 16) {
+		queueSize += 16 - (queueSize % 16);
+	}
+	mpt->m_post_queue_depth = ddi_get16(accessp,
+	    &factsreply->MaxReplyDescriptorPostQueueDepth);
+	if (queueSize > mpt->m_post_queue_depth) {
+		queueDiff = queueSize - mpt->m_post_queue_depth;
+		if (queueDiff % 16) {
+			queueDiff += 16 - (queueDiff % 16);
+		}
+		mpt->m_max_requests -= queueDiff;
+		mpt->m_max_replies -= queueDiff;
+		mpt->m_free_queue_depth -= queueDiff;
+		queueSize -= queueDiff;
+	}
+	mpt->m_post_queue_depth = queueSize;
+
+	/*
+	 * Set up other stuff.
+	 */
+	mpt->m_max_chain_depth = ddi_get8(accessp,
+	    &factsreply->MaxChainDepth);
+
+	/*
+	 * Calculate max frames per request based on DMA S/G length.
+	 */
+
+	simple_sge_main = MPTSAS_MAX_FRAME_SGES64(mpt) - 1;
+	simple_sge_next = mpt->m_req_frame_size /
+	    sizeof (MPI2_SGE_SIMPLE64) - 1;
+
+	mpt->m_max_request_frames = (MPTSAS_MAX_DMA_SEGS -
+	    simple_sge_main) / simple_sge_next + 1;
+	if (((MPTSAS_MAX_DMA_SEGS - simple_sge_main) %
+	    simple_sge_next) > 1) {
+		mpt->m_max_request_frames++;
+	}
+
+	return (DDI_SUCCESS);
+}
+
+int
+mptsas_ioc_get_port_facts(mptsas_t *mpt, int port)
+{
+	/*
+	 * Send get port facts message
+	 */
+	if (mptsas_do_dma(mpt, sizeof (MPI2_PORT_FACTS_REQUEST), port,
+	    mptsas_ioc_do_get_port_facts)) {
+		return (DDI_FAILURE);
+	}
+
+	/*
+	 * Get port facts reply message
+	 */
+	if (mptsas_do_dma(mpt, sizeof (MPI2_PORT_FACTS_REPLY), port,
+	    mptsas_ioc_do_get_port_facts_reply)) {
+		return (DDI_FAILURE);
+	}
+
+	return (DDI_SUCCESS);
+}
+
+static int
+mptsas_ioc_do_get_port_facts(mptsas_t *mpt, caddr_t memp, int var,
+			ddi_acc_handle_t accessp)
+{
+	pMpi2PortFactsRequest_t	facts;
+	int			numbytes;
+
+	bzero(memp, sizeof (*facts));
+	facts = (void *)memp;
+	ddi_put8(accessp, &facts->Function, MPI2_FUNCTION_PORT_FACTS);
+	ddi_put8(accessp, &facts->PortNumber, var);
+	numbytes = sizeof (*facts);
+
+	/*
+	 * Send port facts message via handshake
+	 */
+	if (mptsas_send_handshake_msg(mpt, memp, numbytes, accessp)) {
+		return (DDI_FAILURE);
+	}
+
+	return (DDI_SUCCESS);
+}
+
+static int
+mptsas_ioc_do_get_port_facts_reply(mptsas_t *mpt, caddr_t memp, int var,
+				ddi_acc_handle_t accessp)
+{
+#ifndef __lock_lint
+	_NOTE(ARGUNUSED(var))
+#endif
+	pMpi2PortFactsReply_t	factsreply;
+	int			numbytes;
+	uint_t			iocstatus;
+
+	bzero(memp, sizeof (*factsreply));
+	factsreply = (void *)memp;
+	numbytes = sizeof (*factsreply);
+
+	/*
+	 * Get port facts reply message via handshake
+	 */
+	if (mptsas_get_handshake_msg(mpt, memp, numbytes, accessp)) {
+		return (DDI_FAILURE);
+	}
+
+	if (iocstatus = ddi_get16(accessp, &factsreply->IOCStatus)) {
+		mptsas_log(mpt, CE_WARN, "mptsas_ioc_do_get_port_facts_reply: "
+		    "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
+		    ddi_get32(accessp, &factsreply->IOCLogInfo));
+		return (DDI_FAILURE);
+	}
+
+	return (DDI_SUCCESS);
+}
+
+int
+mptsas_ioc_enable_port(mptsas_t *mpt)
+{
+	/*
+	 * Send enable port message
+	 */
+	if (mptsas_do_dma(mpt, sizeof (MPI2_PORT_ENABLE_REQUEST), 0,
+	    mptsas_ioc_do_enable_port)) {
+		return (DDI_FAILURE);
+	}
+
+	/*
+	 * Get enable port reply message
+	 */
+	if (mptsas_do_dma(mpt, sizeof (MPI2_PORT_ENABLE_REPLY), 0,
+	    mptsas_ioc_do_enable_port_reply)) {
+		return (DDI_FAILURE);
+	}
+
+	return (DDI_SUCCESS);
+}
+
+static int
+mptsas_ioc_do_enable_port(mptsas_t *mpt, caddr_t memp, int var,
+	ddi_acc_handle_t accessp)
+{
+#ifndef __lock_lint
+	_NOTE(ARGUNUSED(var))
+#endif
+	pMpi2PortEnableRequest_t	enable;
+	int				numbytes;
+
+	bzero(memp, sizeof (*enable));
+	enable = (void *)memp;
+	ddi_put8(accessp, &enable->Function, MPI2_FUNCTION_PORT_ENABLE);
+	numbytes = sizeof (*enable);
+
+	/*
+	 * Send message via handshake
+	 */
+	if (mptsas_send_handshake_msg(mpt, memp, numbytes, accessp)) {
+		return (DDI_FAILURE);
+	}
+
+	return (DDI_SUCCESS);
+}
+
+static int
+mptsas_ioc_do_enable_port_reply(mptsas_t *mpt, caddr_t memp, int var,
+	ddi_acc_handle_t accessp)
+{
+#ifndef __lock_lint
+	_NOTE(ARGUNUSED(var))
+#endif
+
+	int			numbytes;
+	uint_t			iocstatus;
+	pMpi2PortEnableReply_t	portreply;
+
+	numbytes = sizeof (MPI2_PORT_ENABLE_REPLY);
+	bzero(memp, numbytes);
+	portreply = (void *)memp;
+
+	/*
+	 * Get message via handshake
+	 */
+	if (mptsas_get_handshake_msg(mpt, memp, numbytes, accessp)) {
+		return (DDI_FAILURE);
+	}
+
+	if (iocstatus = ddi_get16(accessp, &portreply->IOCStatus)) {
+		mptsas_log(mpt, CE_WARN, "mptsas_ioc_do_enable_port_reply: "
+		    "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
+		    ddi_get32(accessp, &portreply->IOCLogInfo));
+		return (DDI_FAILURE);
+	}
+
+	return (DDI_SUCCESS);
+}
+
+int
+mptsas_ioc_enable_event_notification(mptsas_t *mpt)
+{
+	ASSERT(mutex_owned(&mpt->m_mutex));
+
+	/*
+	 * Send enable event notification message
+	 */
+	if (mptsas_do_dma(mpt, sizeof (MPI2_EVENT_NOTIFICATION_REQUEST), NULL,
+	    mptsas_ioc_do_enable_event_notification)) {
+		return (DDI_FAILURE);
+	}
+
+	/*
+	 * Get enable event reply message
+	 */
+	if (mptsas_do_dma(mpt, sizeof (MPI2_EVENT_NOTIFICATION_REPLY), NULL,
+	    mptsas_ioc_do_enable_event_notification_reply)) {
+		return (DDI_FAILURE);
+	}
+
+	return (DDI_SUCCESS);
+}
+
+static int
+mptsas_ioc_do_enable_event_notification(mptsas_t *mpt, caddr_t memp, int var,
+	ddi_acc_handle_t accessp)
+{
+#ifndef __lock_lint
+	_NOTE(ARGUNUSED(var))
+#endif
+
+	pMpi2EventNotificationRequest_t	event;
+	int				numbytes;
+
+	bzero(memp, sizeof (*event));
+	event = (void *)memp;
+	ddi_put8(accessp, &event->Function, MPI2_FUNCTION_EVENT_NOTIFICATION);
+	numbytes = sizeof (*event);
+
+	/*
+	 * Send message via handshake
+	 */
+	if (mptsas_send_handshake_msg(mpt, memp, numbytes, accessp)) {
+		return (DDI_FAILURE);
+	}
+
+	return (DDI_SUCCESS);
+}
+
+static int
+mptsas_ioc_do_enable_event_notification_reply(mptsas_t *mpt, caddr_t memp,
+    int var, ddi_acc_handle_t accessp)
+{
+#ifndef __lock_lint
+	_NOTE(ARGUNUSED(var))
+#endif
+	int				numbytes;
+	uint_t				iocstatus;
+	pMpi2EventNotificationReply_t	eventsreply;
+
+	numbytes = sizeof (MPI2_EVENT_NOTIFICATION_REPLY);
+	bzero(memp, numbytes);
+	eventsreply = (void *)memp;
+
+	/*
+	 * Get message via handshake
+	 */
+	if (mptsas_get_handshake_msg(mpt, memp, numbytes, accessp)) {
+		return (DDI_FAILURE);
+	}
+
+	if (iocstatus = ddi_get16(accessp, &eventsreply->IOCStatus)) {
+		mptsas_log(mpt, CE_WARN,
+		    "mptsas_ioc_do_enable_event_notification_reply: "
+		    "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
+		    ddi_get32(accessp, &eventsreply->IOCLogInfo));
+		return (DDI_FAILURE);
+	}
+
+	return (DDI_SUCCESS);
+}
+
+int
+mptsas_ioc_init(mptsas_t *mpt)
+{
+	/*
+	 * Send ioc init message
+	 */
+	if (mptsas_do_dma(mpt, sizeof (MPI2_IOC_INIT_REQUEST), NULL,
+	    mptsas_do_ioc_init)) {
+		return (DDI_FAILURE);
+	}
+
+	/*
+	 * Get ioc init reply message
+	 */
+	if (mptsas_do_dma(mpt, sizeof (MPI2_IOC_INIT_REPLY), NULL,
+	    mptsas_do_ioc_init_reply)) {
+		return (DDI_FAILURE);
+	}
+
+	return (DDI_SUCCESS);
+}
+
+static int
+mptsas_do_ioc_init(mptsas_t *mpt, caddr_t memp, int var,
+    ddi_acc_handle_t accessp)
+{
+#ifndef __lock_lint
+	_NOTE(ARGUNUSED(var))
+#endif
+
+	pMpi2IOCInitRequest_t	init;
+	int			numbytes;
+
+	bzero(memp, sizeof (*init));
+	init = (void *)memp;
+	ddi_put8(accessp, &init->Function, MPI2_FUNCTION_IOC_INIT);
+	ddi_put8(accessp, &init->WhoInit, MPI2_WHOINIT_HOST_DRIVER);
+	ddi_put16(accessp, &init->MsgVersion, MPI2_VERSION);
+	ddi_put16(accessp, &init->HeaderVersion, MPI2_HEADER_VERSION);
+	ddi_put16(accessp, &init->SystemRequestFrameSize,
+	    mpt->m_req_frame_size / 4);
+	ddi_put16(accessp, &init->ReplyDescriptorPostQueueDepth,
+	    mpt->m_post_queue_depth);
+	ddi_put16(accessp, &init->ReplyFreeQueueDepth,
+	    mpt->m_free_queue_depth);
+
+	/*
+	 * These addresses are set using the DMA cookie addresses from when the
+	 * memory was allocated.  Sense buffer hi address should be 0.
+	 */
+	ddi_put32(accessp, &init->SenseBufferAddressHigh, 0);
+	ddi_put32(accessp, &init->SystemReplyAddressHigh,
+	    (uint32_t)(mpt->m_reply_frame_dma_addr >> 32));
+	ddi_put32(accessp, &init->SystemRequestFrameBaseAddress.High,
+	    (uint32_t)(mpt->m_req_frame_dma_addr >> 32));
+	ddi_put32(accessp, &init->SystemRequestFrameBaseAddress.Low,
+	    (uint32_t)mpt->m_req_frame_dma_addr);
+	ddi_put32(accessp, &init->ReplyDescriptorPostQueueAddress.High,
+	    (uint32_t)(mpt->m_post_queue_dma_addr >> 32));
+	ddi_put32(accessp, &init->ReplyDescriptorPostQueueAddress.Low,
+	    (uint32_t)mpt->m_post_queue_dma_addr);
+	ddi_put32(accessp, &init->ReplyFreeQueueAddress.High,
+	    (uint32_t)(mpt->m_free_queue_dma_addr >> 32));
+	ddi_put32(accessp, &init->ReplyFreeQueueAddress.Low,
+	    (uint32_t)mpt->m_free_queue_dma_addr);
+
+	numbytes = sizeof (*init);
+
+	/*
+	 * Post message via handshake
+	 */
+	if (mptsas_send_handshake_msg(mpt, memp, numbytes, accessp)) {
+		return (DDI_FAILURE);
+	}
+
+	return (DDI_SUCCESS);
+}
+
+static int
+mptsas_do_ioc_init_reply(mptsas_t *mpt, caddr_t memp, int var,
+		ddi_acc_handle_t accessp)
+{
+#ifndef __lock_lint
+	_NOTE(ARGUNUSED(var))
+#endif
+
+	pMpi2IOCInitReply_t	initreply;
+	int			numbytes;
+	uint_t			iocstatus;
+
+	numbytes = sizeof (MPI2_IOC_INIT_REPLY);
+	bzero(memp, numbytes);
+	initreply = (void *)memp;
+
+	/*
+	 * Get reply message via handshake
+	 */
+	if (mptsas_get_handshake_msg(mpt, memp, numbytes, accessp)) {
+		return (DDI_FAILURE);
+	}
+
+	if (iocstatus = ddi_get16(accessp, &initreply->IOCStatus)) {
+		mptsas_log(mpt, CE_WARN, "mptsas_do_ioc_init_reply: "
+		    "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
+		    ddi_get32(accessp, &initreply->IOCLogInfo));
+		return (DDI_FAILURE);
+	}
+
+	if ((ddi_get32(mpt->m_datap, &mpt->m_reg->Doorbell)) &
+	    MPI2_IOC_STATE_OPERATIONAL) {
+		mptsas_log(mpt, CE_NOTE,
+		    "?mpt%d: IOC Operational.\n", mpt->m_instance);
+	} else {
+		return (DDI_FAILURE);
+	}
+
+	return (DDI_SUCCESS);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas_raid.c	Fri Jun 19 20:12:07 2009 +0800
@@ -0,0 +1,590 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Copyright (c) 2000 to 2009, LSI Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms of all code within
+ * this file that is exclusively owned by LSI, with or without
+ * modification, is permitted provided that, in addition to the CDDL 1.0
+ * License requirements, the following conditions are met:
+ *
+ *    Neither the name of the author nor the names of its contributors may be
+ *    used to endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ */
+
+/*
+ * mptsas_raid - This file contains all the RAID related functions for the
+ * MPT interface.
+ */
+
+#if defined(lint) || defined(DEBUG)
+#define	MPTSAS_DEBUG
+#endif
+
+#define	MPI_RAID_VOL_PAGE_0_PHYSDISK_MAX	2
+
+/*
+ * standard header files
+ */
+#include <sys/note.h>
+#include <sys/scsi/scsi.h>
+#include <sys/byteorder.h>
+#include <sys/raidioctl.h>
+
+#pragma pack(1)
+
+#include <sys/scsi/adapters/mpt_sas/mpi/mpi2_type.h>
+#include <sys/scsi/adapters/mpt_sas/mpi/mpi2.h>
+#include <sys/scsi/adapters/mpt_sas/mpi/mpi2_cnfg.h>
+#include <sys/scsi/adapters/mpt_sas/mpi/mpi2_init.h>
+#include <sys/scsi/adapters/mpt_sas/mpi/mpi2_ioc.h>
+
+#pragma pack()
+
+/*
+ * private header files.
+ */
+#include <sys/scsi/adapters/mpt_sas/mptsas_var.h>
+
+static int mptsas_get_raid_wwid(mptsas_t *mpt, mptsas_raidvol_t *raidvol);
+
+extern int mptsas_check_dma_handle(ddi_dma_handle_t handle);
+extern int mptsas_check_acc_handle(ddi_acc_handle_t handle);
+extern mptsas_target_t *mptsas_tgt_alloc(mptsas_hash_table_t *, uint16_t,
+    uint64_t, uint32_t, uint8_t, uint8_t);
+
+static int
+mptsas_raidconf_page_0_cb(mptsas_t *mpt, caddr_t page_memp,
+    ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
+    va_list ap)
+{
+#ifndef __lock_lint
+	_NOTE(ARGUNUSED(ap))
+#endif
+	pMpi2RaidConfigurationPage0_t	raidconfig_page0;
+	pMpi2RaidConfig0ConfigElement_t	element;
+	uint32_t *confignum;
+	int rval = DDI_SUCCESS, i;
+	uint8_t numelements, vol, disk;
+	uint16_t elementtype, voldevhandle;
+	uint16_t etype_vol, etype_pd, etype_hs;
+	uint16_t etype_oce;
+	mptsas_slots_t *slots = mpt->m_active;
+	m_raidconfig_t *raidconfig;
+	uint64_t raidwwn;
+	uint32_t native;
+	mptsas_target_t	*ptgt;
+	uint32_t configindex;
+
+	if (iocstatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) {
+		return (DDI_FAILURE);
+	}
+
+	if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
+		mptsas_log(mpt, CE_WARN, "mptsas_get_raid_conf_page0 "
+		    "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
+		    iocstatus, iocloginfo);
+		rval = DDI_FAILURE;
+		return (rval);
+	}
+	confignum = va_arg(ap,  uint32_t *);
+	configindex = va_arg(ap, uint32_t);
+	raidconfig_page0 = (pMpi2RaidConfigurationPage0_t)page_memp;
+	/*
+	 * Get all RAID configurations.
+	 */
+	etype_vol = MPI2_RAIDCONFIG0_EFLAGS_VOLUME_ELEMENT;
+	etype_pd = MPI2_RAIDCONFIG0_EFLAGS_VOL_PHYS_DISK_ELEMENT;
+	etype_hs = MPI2_RAIDCONFIG0_EFLAGS_HOT_SPARE_ELEMENT;
+	etype_oce = MPI2_RAIDCONFIG0_EFLAGS_OCE_ELEMENT;
+	/*
+	 * Set up page address for next time through.
+	 */
+	*confignum =  ddi_get8(accessp,
+	    &raidconfig_page0->ConfigNum);
+
+	/*
+	 * Point to the right config in the structure.
+	 * Increment the number of valid RAID configs.
+	 */
+	raidconfig = &slots->m_raidconfig[configindex];
+	slots->m_num_raid_configs++;
+
+	/*
+	 * Set the native flag if this is not a foreign
+	 * configuration.
+	 */
+	native = ddi_get32(accessp, &raidconfig_page0->Flags);
+	if (native & MPI2_RAIDCONFIG0_FLAG_FOREIGN_CONFIG) {
+		native = FALSE;
+	} else {
+		native = TRUE;
+	}
+	raidconfig->m_native = (uint8_t)native;
+
+	/*
+	 * Get volume information for the volumes in the
+	 * config.
+	 */
+	numelements = ddi_get8(accessp, &raidconfig_page0->NumElements);
+	vol = 0;
+	disk = 0;
+	element = (pMpi2RaidConfig0ConfigElement_t)
+	    &raidconfig_page0->ConfigElement;
+
+	for (i = 0; i < numelements; i++, element++) {
+		/*
+		 * Get the element type.  Could be Volume,
+		 * PhysDisk, Hot Spare, or Online Capacity
+		 * Expansion PhysDisk.
+		 */
+		elementtype = ddi_get16(accessp, &element->ElementFlags);
+		elementtype &= MPI2_RAIDCONFIG0_EFLAGS_MASK_ELEMENT_TYPE;
+
+		/*
+		 * For volumes, get the RAID settings and the
+		 * WWID.
+		 */
+		if (elementtype == etype_vol) {
+			voldevhandle = ddi_get16(accessp,
+			    &element->VolDevHandle);
+			raidconfig->m_raidvol[vol].m_israid = 1;
+			raidconfig->m_raidvol[vol].
+			    m_raidhandle = voldevhandle;
+			/*
+			 * Get the settings for the raid
+			 * volume.  This includes the
+			 * DevHandles for the disks making up
+			 * the raid volume.
+			 */
+			if (mptsas_get_raid_settings(mpt,
+			    &raidconfig->m_raidvol[vol]))
+				continue;
+
+			/*
+			 * Get the WWID of the RAID volume for
+			 * SAS HBA
+			 */
+			if (mptsas_get_raid_wwid(mpt,
+			    &raidconfig->m_raidvol[vol]))
+				continue;
+
+			raidwwn = raidconfig->m_raidvol[vol].
+			    m_raidwwid;
+
+			/*
+			 * RAID uses phymask of 0.
+			 */
+			ptgt = mptsas_tgt_alloc(&slots->m_tgttbl,
+			    voldevhandle, raidwwn, 0, 0, 0);
+
+			raidconfig->m_raidvol[vol].m_raidtgt =
+			    ptgt;
+
+			/*
+			 * Increment volume index within this
+			 * raid config.
+			 */
+			vol++;
+		} else if ((elementtype == etype_pd) ||
+		    (elementtype == etype_hs) ||
+		    (elementtype == etype_oce)) {
+			/*
+			 * For all other element types, put
+			 * their DevHandles in the phys disk
+			 * list of the config.  These are all
+			 * some variation of a Phys Disk and
+			 * this list is used to keep these
+			 * disks from going online.
+			 */
+			raidconfig->m_physdisk_devhdl[disk] = ddi_get16(accessp,
+			    &element->PhysDiskDevHandle);
+
+			/*
+			 * Increment disk index within this
+			 * raid config.
+			 */
+			disk++;
+		}
+	}
+
+	return (rval);
+}
+
+int
+mptsas_get_raid_info(mptsas_t *mpt)
+{
+	int rval = DDI_SUCCESS;
+	uint32_t confignum, pageaddress;
+	uint8_t configindex;
+	mptsas_slots_t *slots = mpt->m_active;
+
+	ASSERT(mutex_owned(&mpt->m_mutex));
+
+	/*
+	 * Clear all RAID info before starting.
+	 */
+	bzero(slots->m_raidconfig, sizeof (slots->m_raidconfig));
+	slots->m_num_raid_configs = 0;
+
+	configindex = 0;
+	confignum = 0xff;
+	pageaddress = MPI2_RAID_PGAD_FORM_GET_NEXT_CONFIGNUM | confignum;
+	while (rval == DDI_SUCCESS) {
+		/*
+		 * Get the header and config page.  reply contains the reply
+		 * frame, which holds status info for the request.
+		 */
+		rval = mptsas_access_config_page(mpt,
+		    MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
+		    MPI2_CONFIG_EXTPAGETYPE_RAID_CONFIG, 0, pageaddress,
+		    mptsas_raidconf_page_0_cb, &confignum, configindex);
+		configindex++;
+		pageaddress = MPI2_RAID_PGAD_FORM_GET_NEXT_CONFIGNUM |
+		    confignum;
+	}
+
+	return (rval);
+}
+
+static int
+mptsas_raidvol_page_0_cb(mptsas_t *mpt, caddr_t page_memp,
+    ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
+    va_list ap)
+{
+#ifndef __lock_lint
+	_NOTE(ARGUNUSED(ap))
+#endif
+	pMpi2RaidVolPage0_t raidpage;
+	int rval = DDI_SUCCESS, i;
+	mptsas_raidvol_t *raidvol;
+	uint8_t	numdisks, volstate, voltype, physdisknum;
+	uint32_t volsetting;
+	uint32_t statusflags, resync_flag;
+
+	if (iocstatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
+		return (DDI_FAILURE);
+
+	if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
+		mptsas_log(mpt, CE_WARN, "mptsas_raidvol_page0_cb "
+		    "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
+		    iocstatus, iocloginfo);
+		rval = DDI_FAILURE;
+		return (rval);
+	}
+
+	raidvol = va_arg(ap,  mptsas_raidvol_t *);
+
+	raidpage = (pMpi2RaidVolPage0_t)page_memp;
+	volstate = ddi_get8(accessp, &raidpage->VolumeState);
+	volsetting = ddi_get32(accessp,
+	    (uint32_t *)(void *)&raidpage->VolumeSettings);
+	statusflags = ddi_get32(accessp, &raidpage->VolumeStatusFlags);
+	voltype = ddi_get8(accessp, &raidpage->VolumeType);
+
+	raidvol->m_state = volstate;
+	raidvol->m_statusflags = statusflags;
+	/*
+	 * Volume size is not used right now. Set to 0.
+	 */
+	raidvol->m_raidsize = 0;
+	raidvol->m_settings = volsetting;
+	raidvol->m_raidlevel = voltype;
+
+	if (statusflags & MPI2_RAIDVOL0_STATUS_FLAG_QUIESCED) {
+		mptsas_log(mpt, CE_NOTE, "?Volume %d is quiesced\n",
+		    raidvol->m_raidhandle);
+	}
+
+	if (statusflags &
+	    MPI2_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS) {
+		mptsas_log(mpt, CE_NOTE, "?Volume %d is resyncing\n",
+		    raidvol->m_raidhandle);
+	}
+
+	resync_flag = MPI2_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS;
+	switch (volstate) {
+	case MPI2_RAID_VOL_STATE_OPTIMAL:
+		mptsas_log(mpt, CE_NOTE, "?Volume %d is "
+		    "optimal\n", raidvol->m_raidhandle);
+		break;
+	case MPI2_RAID_VOL_STATE_DEGRADED:
+		if ((statusflags & resync_flag) == 0) {
+			mptsas_log(mpt, CE_WARN, "Volume %d "
+			    "is degraded\n",
+			    raidvol->m_raidhandle);
+		}
+		break;
+	case MPI2_RAID_VOL_STATE_FAILED:
+		mptsas_log(mpt, CE_WARN, "Volume %d is "
+		    "failed\n", raidvol->m_raidhandle);
+		break;
+	case MPI2_RAID_VOL_STATE_MISSING:
+		mptsas_log(mpt, CE_WARN, "Volume %d is "
+		    "missing\n", raidvol->m_raidhandle);
+		break;
+	default:
+		break;
+	}
+	numdisks = raidpage->NumPhysDisks;
+	raidvol->m_ndisks = numdisks;
+	for (i = 0; i < numdisks; i++) {
+		physdisknum = raidpage->PhysDisk[i].PhysDiskNum;
+		raidvol->m_disknum[i] = physdisknum;
+		if (mptsas_get_physdisk_settings(mpt, raidvol,
+		    physdisknum))
+			break;
+	}
+	return (rval);
+}
+
+int
+mptsas_get_raid_settings(mptsas_t *mpt, mptsas_raidvol_t *raidvol)
+{
+	int rval = DDI_SUCCESS;
+	uint32_t page_address;
+
+	ASSERT(mutex_owned(&mpt->m_mutex));
+
+	/*
+	 * Get the header and config page.  reply contains the reply frame,
+	 * which holds status info for the request.
+	 */
+	page_address = (MPI2_RAID_VOLUME_PGAD_FORM_MASK &
+	    MPI2_RAID_VOLUME_PGAD_FORM_HANDLE) | raidvol->m_raidhandle;
+	rval = mptsas_access_config_page(mpt,
+	    MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
+	    MPI2_CONFIG_PAGETYPE_RAID_VOLUME, 0, page_address,
+	    mptsas_raidvol_page_0_cb, raidvol);
+
+	return (rval);
+}
+
+static int
+mptsas_raidvol_page_1_cb(mptsas_t *mpt, caddr_t page_memp,
+    ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
+    va_list ap)
+{
+#ifndef __lock_lint
+	_NOTE(ARGUNUSED(ap))
+#endif
+	pMpi2RaidVolPage1_t	raidpage;
+	int			rval = DDI_SUCCESS, i;
+	uint8_t			*sas_addr = NULL;
+	uint8_t			tmp_sas_wwn[SAS_WWN_BYTE_SIZE];
+	uint64_t		*sas_wwn;
+
+	if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
+		mptsas_log(mpt, CE_WARN, "mptsas_raidvol_page_1_cb "
+		    "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
+		    iocstatus, iocloginfo);
+		rval = DDI_FAILURE;
+		return (rval);
+	}
+	sas_wwn = va_arg(ap, uint64_t *);
+
+	raidpage = (pMpi2RaidVolPage1_t)page_memp;
+	sas_addr = (uint8_t *)(&raidpage->WWID);
+	for (i = 0; i < SAS_WWN_BYTE_SIZE; i++) {
+		tmp_sas_wwn[i] = ddi_get8(accessp, sas_addr + i);
+	}
+	bcopy(tmp_sas_wwn, sas_wwn, SAS_WWN_BYTE_SIZE);
+	*sas_wwn = LE_64(*sas_wwn);
+	return (rval);
+}
+
+static int
+mptsas_get_raid_wwid(mptsas_t *mpt, mptsas_raidvol_t *raidvol)
+{
+	int rval = DDI_SUCCESS;
+	uint32_t page_address;
+	uint64_t sas_wwn;
+
+	ASSERT(mutex_owned(&mpt->m_mutex));
+
+	/*
+	 * Get the header and config page.  reply contains the reply frame,
+	 * which holds status info for the request.
+	 */
+	page_address = (MPI2_RAID_VOLUME_PGAD_FORM_MASK &
+	    MPI2_RAID_VOLUME_PGAD_FORM_HANDLE) | raidvol->m_raidhandle;
+	rval = mptsas_access_config_page(mpt,
+	    MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
+	    MPI2_CONFIG_PAGETYPE_RAID_VOLUME, 1, page_address,
+	    mptsas_raidvol_page_1_cb, &sas_wwn);
+
+	/*
+	 * Get the required information from the page.
+	 */
+	if (rval == DDI_SUCCESS) {
+
+		/*
+		 * replace top nibble of WWID of RAID to '3' for OBP
+		 */
+		sas_wwn = MPTSAS_RAID_WWID(sas_wwn);
+		raidvol->m_raidwwid = sas_wwn;
+	}
+
+done:
+	return (rval);
+}
+
+static int
+mptsas_raidphydsk_page_0_cb(mptsas_t *mpt, caddr_t page_memp,
+    ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
+    va_list ap)
+{
+#ifndef __lock_lint
+	_NOTE(ARGUNUSED(ap))
+#endif
+	pMpi2RaidPhysDiskPage0_t	diskpage;
+	int			rval = DDI_SUCCESS;
+	uint16_t		*devhdl;
+	uint8_t			*state;
+
+	if (iocstatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
+		return (DDI_FAILURE);
+
+	if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
+		mptsas_log(mpt, CE_WARN, "mptsas_raidphydsk_page0_cb "
+		    "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
+		    iocstatus, iocloginfo);
+		rval = DDI_FAILURE;
+		return (rval);
+	}
+	devhdl = va_arg(ap, uint16_t *);
+	state = va_arg(ap, uint8_t *);
+	diskpage = (pMpi2RaidPhysDiskPage0_t)page_memp;
+	*devhdl = ddi_get16(accessp, &diskpage->DevHandle);
+	*state = ddi_get8(accessp, &diskpage->PhysDiskState);
+	return (rval);
+}
+
+int
+mptsas_get_physdisk_settings(mptsas_t *mpt, mptsas_raidvol_t *raidvol,
+    uint8_t physdisknum)
+{
+	int			rval = DDI_SUCCESS, i;
+	uint8_t			state;
+	uint16_t		devhdl;
+	uint32_t		page_address;
+
+	ASSERT(mutex_owned(&mpt->m_mutex));
+
+	/*
+	 * Get the header and config page.  reply contains the reply frame,
+	 * which holds status info for the request.
+	 */
+	page_address = (MPI2_PHYSDISK_PGAD_FORM_MASK &
+	    MPI2_PHYSDISK_PGAD_FORM_PHYSDISKNUM) | physdisknum;
+	rval = mptsas_access_config_page(mpt,
+	    MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
+	    MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK, 0, page_address,
+	    mptsas_raidphydsk_page_0_cb, &devhdl, &state);
+
+	/*
+	 * Get the required information from the page.
+	 */
+	if (rval == DDI_SUCCESS) {
+		for (i = 0; i < MPTSAS_MAX_DISKS_IN_VOL; i++) {
+			/* find the correct position in the arrays */
+			if (raidvol->m_disknum[i] == physdisknum)
+				break;
+		}
+		raidvol->m_devhdl[i] = devhdl;
+
+		switch (state) {
+			case MPI2_RAID_PD_STATE_OFFLINE:
+				raidvol->m_diskstatus[i] =
+				    RAID_DISKSTATUS_FAILED;
+				break;
+
+			case MPI2_RAID_PD_STATE_HOT_SPARE:
+			case MPI2_RAID_PD_STATE_NOT_CONFIGURED:
+			case MPI2_RAID_PD_STATE_NOT_COMPATIBLE:
+				break;
+
+			case MPI2_RAID_PD_STATE_DEGRADED:
+			case MPI2_RAID_PD_STATE_OPTIMAL:
+			case MPI2_RAID_PD_STATE_REBUILDING:
+			case MPI2_RAID_PD_STATE_ONLINE:
+			default:
+				raidvol->m_diskstatus[i] =
+				    RAID_DISKSTATUS_GOOD;
+				break;
+		}
+	}
+
+	return (rval);
+}
+
+int
+mptsas_delete_volume(mptsas_t *mpt, uint16_t volid)
+{
+	int		config, i, vol = (-1);
+	mptsas_slots_t	*slots = mpt->m_active;
+
+	for (config = 0; config < slots->m_num_raid_configs; config++) {
+		for (i = 0; i < MPTSAS_MAX_RAIDVOLS; i++) {
+			if (slots->m_raidconfig[config].m_raidvol[i].
+			    m_raidhandle == volid) {
+				vol = i;
+				break;
+			}
+		}
+	}
+
+	if (vol < 0) {
+		mptsas_log(mpt, CE_WARN, "raid doesn't exist at specified "
+		    "target.");
+		return (-1);
+	}
+
+	slots->m_raidconfig[config].m_raidvol[vol].m_israid = 0;
+	slots->m_raidconfig[config].m_raidvol[vol].m_ndisks = 0;
+	for (i = 0; i < MPTSAS_MAX_DISKS_IN_VOL; i++) {
+		slots->m_raidconfig[config].m_raidvol[vol].m_disknum[i] = 0;
+		slots->m_raidconfig[config].m_raidvol[vol].m_devhdl[i] = 0;
+	}
+
+	return (0);
+}
--- a/usr/src/uts/common/io/scsi/impl/scsi_hba.c	Fri Jun 19 18:13:27 2009 +0800
+++ b/usr/src/uts/common/io/scsi/impl/scsi_hba.c	Fri Jun 19 20:12:07 2009 +0800
@@ -4000,6 +4000,7 @@
 		    (strncmp(nameaddr, "iport@", strlen("iport@")) != 0)) {
 			ret = NDI_FAILURE;
 			ndi_devi_exit(self, circ);
+			ddi_prop_free(iports);
 			return (ret);
 		}
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/io/warlock/mptsas.wlcmd	Fri Jun 19 20:12:07 2009 +0800
@@ -0,0 +1,42 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+add	bus_ops::bus_add_eventcall	target	warlock_dummy
+add	bus_ops::bus_config		target  warlock_dummy
+add	bus_ops::bus_get_eventcookie	target  warlock_dummy
+add	bus_ops::bus_intr_ctl		target  warlock_dummy
+add	bus_ops::bus_post_event		target  warlock_dummy
+add	bus_ops::bus_remove_eventcall	target  warlock_dummy
+add	bus_ops::bus_unconfig		target  warlock_dummy
+
+
+for ptr in `funcptrs | grep '^scsi_hba_tran::'`
+do
+        add $ptr target warlock_dummy
+done
+
+root    scsi_hba_bus_power
+ignore  delay 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/sys/scsi/adapters/mpt_sas/mpi/mpi2.h	Fri Jun 19 20:12:07 2009 +0800
@@ -0,0 +1,1112 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2000 to 2009, LSI Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms of all code within
+ * this file that is exclusively owned by LSI, with or without
+ * modification, is permitted provided that, in addition to the CDDL 1.0
+ * License requirements, the following conditions are met:
+ *
+ *    Neither the name of the author nor the names of its contributors may be
+ *    used to endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ */
+
+/*
+ *           Name:  mpi2.h
+ *          Title:  MPI Message independent structures and definitions
+ *                  including System Interface Register Set and
+ *                  scatter/gather formats.
+ *  Creation Date:  June 21, 2006
+ *
+ *  mpi2.h Version:  02.00.11
+ *
+ *  Version History
+ *  ---------------
+ *
+ *  Date      Version   Description
+ *  --------  --------  ------------------------------------------------------
+ *  04-30-07  02.00.00  Corresponds to Fusion-MPT MPI Specification Rev A.
+ *  06-04-07  02.00.01  Bumped MPI2_HEADER_VERSION_UNIT.
+ *  06-26-07  02.00.02  Bumped MPI2_HEADER_VERSION_UNIT.
+ *  08-31-07  02.00.03  Bumped MPI2_HEADER_VERSION_UNIT.
+ *                      Moved ReplyPostHostIndex register to offset 0x6C of the
+ *                      MPI2_SYSTEM_INTERFACE_REGS and modified the define for
+ *                      MPI2_REPLY_POST_HOST_INDEX_OFFSET.
+ *                      Added union of request descriptors.
+ *                      Added union of reply descriptors.
+ *  10-31-07  02.00.04  Bumped MPI2_HEADER_VERSION_UNIT.
+ *                      Added define for MPI2_VERSION_02_00.
+ *                      Fixed the size of the FunctionDependent5 field in the
+ *                      MPI2_DEFAULT_REPLY structure.
+ *  12-18-07  02.00.05  Bumped MPI2_HEADER_VERSION_UNIT.
+ *                      Removed the MPI-defined Fault Codes and extended the
+ *                      product specific codes up to 0xEFFF.
+ *                      Added a sixth key value for the WriteSequence register
+ *                      and changed the flush value to 0x0.
+ *                      Added message function codes for Diagnostic Buffer Post
+ *                      and Diagnsotic Release.
+ *                      New IOCStatus define: MPI2_IOCSTATUS_DIAGNOSTIC_RELEASED
+ *                      Moved MPI2_VERSION_UNION from mpi2_ioc.h.
+ *  02-29-08  02.00.06  Bumped MPI2_HEADER_VERSION_UNIT.
+ *  03-03-08  02.00.07  Bumped MPI2_HEADER_VERSION_UNIT.
+ *  05-21-08  02.00.08  Bumped MPI2_HEADER_VERSION_UNIT.
+ *                      Added #defines for marking a reply descriptor as unused.
+ *  06-27-08  02.00.09  Bumped MPI2_HEADER_VERSION_UNIT.
+ *  10-02-08  02.00.10  Bumped MPI2_HEADER_VERSION_UNIT.
+ *                      Moved LUN field defines from mpi2_init.h.
+ *  01-19-09  02.00.11  Bumped MPI2_HEADER_VERSION_UNIT.
+ *  --------------------------------------------------------------------------
+ */
+
+#ifndef MPI2_H
+#define MPI2_H
+
+
+/*****************************************************************************
+*
+*        MPI Version Definitions
+*
+*****************************************************************************/
+
+#define MPI2_VERSION_MAJOR                  (0x02)
+#define MPI2_VERSION_MINOR                  (0x00)
+#define MPI2_VERSION_MAJOR_MASK             (0xFF00)
+#define MPI2_VERSION_MAJOR_SHIFT            (8)
+#define MPI2_VERSION_MINOR_MASK             (0x00FF)
+#define MPI2_VERSION_MINOR_SHIFT            (0)
+#define MPI2_VERSION ((MPI2_VERSION_MAJOR << MPI2_VERSION_MAJOR_SHIFT) |   \
+                                      MPI2_VERSION_MINOR)
+
+#define MPI2_VERSION_02_00                  (0x0200)
+
+/* versioning for this MPI header set */
+#define MPI2_HEADER_VERSION_UNIT            (0x0B)
+#define MPI2_HEADER_VERSION_DEV             (0x00)
+#define MPI2_HEADER_VERSION_UNIT_MASK       (0xFF00)
+#define MPI2_HEADER_VERSION_UNIT_SHIFT      (8)
+#define MPI2_HEADER_VERSION_DEV_MASK        (0x00FF)
+#define MPI2_HEADER_VERSION_DEV_SHIFT       (0)
+#define MPI2_HEADER_VERSION ((MPI2_HEADER_VERSION_UNIT << 8) | MPI2_HEADER_VERSION_DEV)
+
+
+/*****************************************************************************
+*
+*        IOC State Definitions
+*
+*****************************************************************************/
+
+#define MPI2_IOC_STATE_RESET               (0x00000000)
+#define MPI2_IOC_STATE_READY               (0x10000000)
+#define MPI2_IOC_STATE_OPERATIONAL         (0x20000000)
+#define MPI2_IOC_STATE_FAULT               (0x40000000)
+
+#define MPI2_IOC_STATE_MASK                (0xF0000000)
+#define MPI2_IOC_STATE_SHIFT               (28)
+
+/* Fault state range for prodcut specific codes */
+#define MPI2_FAULT_PRODUCT_SPECIFIC_MIN                 (0x0000)
+#define MPI2_FAULT_PRODUCT_SPECIFIC_MAX                 (0xEFFF)
+
+
+/*****************************************************************************
+*
+*        System Interface Register Definitions
+*
+*****************************************************************************/
+
+typedef volatile struct _MPI2_SYSTEM_INTERFACE_REGS
+{
+    U32         Doorbell;                   /* 0x00 */
+    U32         WriteSequence;              /* 0x04 */
+    U32         HostDiagnostic;             /* 0x08 */
+    U32         Reserved1;                  /* 0x0C */
+    U32         DiagRWData;                 /* 0x10 */
+    U32         DiagRWAddressLow;           /* 0x14 */
+    U32         DiagRWAddressHigh;          /* 0x18 */
+    U32         Reserved2[5];               /* 0x1C */
+    U32         HostInterruptStatus;        /* 0x30 */
+    U32         HostInterruptMask;          /* 0x34 */
+    U32         DCRData;                    /* 0x38 */
+    U32         DCRAddress;                 /* 0x3C */
+    U32         Reserved3[2];               /* 0x40 */
+    U32         ReplyFreeHostIndex;         /* 0x48 */
+    U32         Reserved4[8];               /* 0x4C */
+    U32         ReplyPostHostIndex;         /* 0x6C */
+    U32         Reserved5;                  /* 0x70 */
+    U32         HCBSize;                    /* 0x74 */
+    U32         HCBAddressLow;              /* 0x78 */
+    U32         HCBAddressHigh;             /* 0x7C */
+    U32         Reserved6[16];              /* 0x80 */
+    U32         RequestDescriptorPostLow;   /* 0xC0 */
+    U32         RequestDescriptorPostHigh;  /* 0xC4 */
+    U32         Reserved7[14];              /* 0xC8 */
+} MPI2_SYSTEM_INTERFACE_REGS, MPI2_POINTER PTR_MPI2_SYSTEM_INTERFACE_REGS,
+  Mpi2SystemInterfaceRegs_t, MPI2_POINTER pMpi2SystemInterfaceRegs_t;
+
+/*
+ * Defines for working with the Doorbell register.
+ */
+#define MPI2_DOORBELL_OFFSET                    (0x00000000)
+
+/* IOC --> System values */
+#define MPI2_DOORBELL_USED                      (0x08000000)
+#define MPI2_DOORBELL_WHO_INIT_MASK             (0x07000000)
+#define MPI2_DOORBELL_WHO_INIT_SHIFT            (24)
+#define MPI2_DOORBELL_FAULT_CODE_MASK           (0x0000FFFF)
+#define MPI2_DOORBELL_DATA_MASK                 (0x0000FFFF)
+
+/* System --> IOC values */
+#define MPI2_DOORBELL_FUNCTION_MASK             (0xFF000000)
+#define MPI2_DOORBELL_FUNCTION_SHIFT            (24)
+#define MPI2_DOORBELL_ADD_DWORDS_MASK           (0x00FF0000)
+#define MPI2_DOORBELL_ADD_DWORDS_SHIFT          (16)
+
+
+/*
+ * Defines for the WriteSequence register
+ */
+#define MPI2_WRITE_SEQUENCE_OFFSET              (0x00000004)
+#define MPI2_WRSEQ_KEY_VALUE_MASK               (0x0000000F)
+#define MPI2_WRSEQ_FLUSH_KEY_VALUE              (0x0)
+#define MPI2_WRSEQ_1ST_KEY_VALUE                (0xF)
+#define MPI2_WRSEQ_2ND_KEY_VALUE                (0x4)
+#define MPI2_WRSEQ_3RD_KEY_VALUE                (0xB)
+#define MPI2_WRSEQ_4TH_KEY_VALUE                (0x2)
+#define MPI2_WRSEQ_5TH_KEY_VALUE                (0x7)
+#define MPI2_WRSEQ_6TH_KEY_VALUE                (0xD)
+
+/*
+ * Defines for the HostDiagnostic register
+ */
+#define MPI2_HOST_DIAGNOSTIC_OFFSET             (0x00000008)
+
+#define MPI2_DIAG_BOOT_DEVICE_SELECT_MASK       (0x00001800)
+#define MPI2_DIAG_BOOT_DEVICE_SELECT_DEFAULT    (0x00000000)
+#define MPI2_DIAG_BOOT_DEVICE_SELECT_HCDW       (0x00000800)
+
+#define MPI2_DIAG_CLEAR_FLASH_BAD_SIG           (0x00000400)
+#define MPI2_DIAG_FORCE_HCB_ON_RESET            (0x00000200)
+#define MPI2_DIAG_HCB_MODE                      (0x00000100)
+#define MPI2_DIAG_DIAG_WRITE_ENABLE             (0x00000080)
+#define MPI2_DIAG_FLASH_BAD_SIG                 (0x00000040)
+#define MPI2_DIAG_RESET_HISTORY                 (0x00000020)
+#define MPI2_DIAG_DIAG_RW_ENABLE                (0x00000010)
+#define MPI2_DIAG_RESET_ADAPTER                 (0x00000004)
+#define MPI2_DIAG_HOLD_IOC_RESET                (0x00000002)
+
+/*
+ * Offsets for DiagRWData and address
+ */
+#define MPI2_DIAG_RW_DATA_OFFSET                (0x00000010)
+#define MPI2_DIAG_RW_ADDRESS_LOW_OFFSET         (0x00000014)
+#define MPI2_DIAG_RW_ADDRESS_HIGH_OFFSET        (0x00000018)
+
+/*
+ * Defines for the HostInterruptStatus register
+ */
+#define MPI2_HOST_INTERRUPT_STATUS_OFFSET       (0x00000030)
+#define MPI2_HIS_SYS2IOC_DB_STATUS              (0x80000000)
+#define MPI2_HIS_IOP_DOORBELL_STATUS            MPI2_HIS_SYS2IOC_DB_STATUS
+#define MPI2_HIS_RESET_IRQ_STATUS               (0x40000000)
+#define MPI2_HIS_REPLY_DESCRIPTOR_INTERRUPT     (0x00000008)
+#define MPI2_HIS_IOC2SYS_DB_STATUS              (0x00000001)
+#define MPI2_HIS_DOORBELL_INTERRUPT             MPI2_HIS_IOC2SYS_DB_STATUS
+
+/*
+ * Defines for the HostInterruptMask register
+ */
+#define MPI2_HOST_INTERRUPT_MASK_OFFSET         (0x00000034)
+#define MPI2_HIM_RESET_IRQ_MASK                 (0x40000000)
+#define MPI2_HIM_REPLY_INT_MASK                 (0x00000008)
+#define MPI2_HIM_RIM                            MPI2_HIM_REPLY_INT_MASK
+#define MPI2_HIM_IOC2SYS_DB_MASK                (0x00000001)
+#define MPI2_HIM_DIM                            MPI2_HIM_IOC2SYS_DB_MASK
+
+/*
+ * Offsets for DCRData and address
+ */
+#define MPI2_DCR_DATA_OFFSET                    (0x00000038)
+#define MPI2_DCR_ADDRESS_OFFSET                 (0x0000003C)
+
+/*
+ * Offset for the Reply Free Queue
+ */
+#define MPI2_REPLY_FREE_HOST_INDEX_OFFSET       (0x00000048)
+
+/*
+ * Offset for the Reply Descriptor Post Queue
+ */
+#define MPI2_REPLY_POST_HOST_INDEX_OFFSET       (0x0000006C)
+
+/*
+ * Defines for the HCBSize and address
+ */
+#define MPI2_HCB_SIZE_OFFSET                    (0x00000074)
+#define MPI2_HCB_SIZE_SIZE_MASK                 (0xFFFFF000)
+#define MPI2_HCB_SIZE_HCB_ENABLE                (0x00000001)
+
+#define MPI2_HCB_ADDRESS_LOW_OFFSET             (0x00000078)
+#define MPI2_HCB_ADDRESS_HIGH_OFFSET            (0x0000007C)
+
+/*
+ * Offsets for the Request Queue
+ */
+#define MPI2_REQUEST_DESCRIPTOR_POST_LOW_OFFSET     (0x000000C0)
+#define MPI2_REQUEST_DESCRIPTOR_POST_HIGH_OFFSET    (0x000000C4)
+
+
+/*****************************************************************************
+*
+*        Message Descriptors
+*
+*****************************************************************************/
+
+/* Request Descriptors */
+
+/* Default Request Descriptor */
+typedef struct _MPI2_DEFAULT_REQUEST_DESCRIPTOR
+{
+    U8              RequestFlags;               /* 0x00 */
+    U8              VF_ID;                      /* 0x01 */
+    U16             SMID;                       /* 0x02 */
+    U16             LMID;                       /* 0x04 */
+    U16             DescriptorTypeDependent;    /* 0x06 */
+} MPI2_DEFAULT_REQUEST_DESCRIPTOR,
+  MPI2_POINTER PTR_MPI2_DEFAULT_REQUEST_DESCRIPTOR,
+  Mpi2DefaultRequestDescriptor_t, MPI2_POINTER pMpi2DefaultRequestDescriptor_t;
+
+/* defines for the RequestFlags field */
+#define MPI2_REQ_DESCRIPT_FLAGS_TYPE_MASK               (0x0E)
+#define MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO                 (0x00)
+#define MPI2_REQ_DESCRIPT_FLAGS_SCSI_TARGET             (0x02)
+#define MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY           (0x06)
+#define MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE            (0x08)
+
+#define MPI2_REQ_DESCRIPT_FLAGS_IOC_FIFO_MARKER (0x01)
+
+
+/* High Priority Request Descriptor */
+typedef struct _MPI2_HIGH_PRIORITY_REQUEST_DESCRIPTOR
+{
+    U8              RequestFlags;               /* 0x00 */
+    U8              VF_ID;                      /* 0x01 */
+    U16             SMID;                       /* 0x02 */
+    U16             LMID;                       /* 0x04 */
+    U16             Reserved1;                  /* 0x06 */
+} MPI2_HIGH_PRIORITY_REQUEST_DESCRIPTOR,
+  MPI2_POINTER PTR_MPI2_HIGH_PRIORITY_REQUEST_DESCRIPTOR,
+  Mpi2HighPriorityRequestDescriptor_t,
+  MPI2_POINTER pMpi2HighPriorityRequestDescriptor_t;
+
+
+/* SCSI IO Request Descriptor */
+typedef struct _MPI2_SCSI_IO_REQUEST_DESCRIPTOR
+{
+    U8              RequestFlags;               /* 0x00 */
+    U8              VF_ID;                      /* 0x01 */
+    U16             SMID;                       /* 0x02 */
+    U16             LMID;                       /* 0x04 */
+    U16             DevHandle;                  /* 0x06 */
+} MPI2_SCSI_IO_REQUEST_DESCRIPTOR,
+  MPI2_POINTER PTR_MPI2_SCSI_IO_REQUEST_DESCRIPTOR,
+  Mpi2SCSIIORequestDescriptor_t, MPI2_POINTER pMpi2SCSIIORequestDescriptor_t;
+
+
+/* SCSI Target Request Descriptor */
+typedef struct _MPI2_SCSI_TARGET_REQUEST_DESCRIPTOR
+{
+    U8              RequestFlags;               /* 0x00 */
+    U8              VF_ID;                      /* 0x01 */
+    U16             SMID;                       /* 0x02 */
+    U16             LMID;                       /* 0x04 */
+    U16             IoIndex;                    /* 0x06 */
+} MPI2_SCSI_TARGET_REQUEST_DESCRIPTOR,
+  MPI2_POINTER PTR_MPI2_SCSI_TARGET_REQUEST_DESCRIPTOR,
+  Mpi2SCSITargetRequestDescriptor_t,
+  MPI2_POINTER pMpi2SCSITargetRequestDescriptor_t;
+
+/* union of Request Descriptors */
+typedef union _MPI2_REQUEST_DESCRIPTOR_UNION
+{
+    MPI2_DEFAULT_REQUEST_DESCRIPTOR         Default;
+    MPI2_HIGH_PRIORITY_REQUEST_DESCRIPTOR   HighPriority;
+    MPI2_SCSI_IO_REQUEST_DESCRIPTOR         SCSIIO;
+    MPI2_SCSI_TARGET_REQUEST_DESCRIPTOR     SCSITarget;
+    U64                                     Words;
+} MPI2_REQUEST_DESCRIPTOR_UNION, MPI2_POINTER PTR_MPI2_REQUEST_DESCRIPTOR_UNION,
+  Mpi2RequestDescriptorUnion_t, MPI2_POINTER pMpi2RequestDescriptorUnion_t;
+
+
+/* Reply Descriptors */
+
+/* Default Reply Descriptor */
+typedef struct _MPI2_DEFAULT_REPLY_DESCRIPTOR
+{
+    U8              ReplyFlags;                 /* 0x00 */
+    U8              VF_ID;                      /* 0x01 */
+    U16             DescriptorTypeDependent1;   /* 0x02 */
+    U32             DescriptorTypeDependent2;   /* 0x04 */
+} MPI2_DEFAULT_REPLY_DESCRIPTOR, MPI2_POINTER PTR_MPI2_DEFAULT_REPLY_DESCRIPTOR,
+  Mpi2DefaultReplyDescriptor_t, MPI2_POINTER pMpi2DefaultReplyDescriptor_t;
+
+/* defines for the ReplyFlags field */
+#define MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK               (0x0F)
+#define MPI2_RPY_DESCRIPT_FLAGS_SCSI_IO_SUCCESS         (0x00)
+#define MPI2_RPY_DESCRIPT_FLAGS_ADDRESS_REPLY           (0x01)
+#define MPI2_RPY_DESCRIPT_FLAGS_TARGETASSIST_SUCCESS    (0x02)
+#define MPI2_RPY_DESCRIPT_FLAGS_TARGET_COMMAND_BUFFER   (0x03)
+#define MPI2_RPY_DESCRIPT_FLAGS_UNUSED                  (0x0F)
+
+/* values for marking a reply descriptor as unused */
+#define MPI2_RPY_DESCRIPT_UNUSED_WORD0_MARK             (0xFFFFFFFF)
+#define MPI2_RPY_DESCRIPT_UNUSED_WORD1_MARK             (0xFFFFFFFF)
+
+/* Address Reply Descriptor */
+typedef struct _MPI2_ADDRESS_REPLY_DESCRIPTOR
+{
+    U8              ReplyFlags;                 /* 0x00 */
+    U8              VF_ID;                      /* 0x01 */
+    U16             SMID;                       /* 0x02 */
+    U32             ReplyFrameAddress;          /* 0x04 */
+} MPI2_ADDRESS_REPLY_DESCRIPTOR, MPI2_POINTER PTR_MPI2_ADDRESS_REPLY_DESCRIPTOR,
+  Mpi2AddressReplyDescriptor_t, MPI2_POINTER pMpi2AddressReplyDescriptor_t;
+
+#define MPI2_ADDRESS_REPLY_SMID_INVALID                 (0x00)
+
+
+/* SCSI IO Success Reply Descriptor */
+typedef struct _MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR
+{
+    U8              ReplyFlags;                 /* 0x00 */
+    U8              VF_ID;                      /* 0x01 */
+    U16             SMID;                       /* 0x02 */
+    U16             TaskTag;                    /* 0x04 */
+    U16             DevHandle;                  /* 0x06 */
+} MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR,
+  MPI2_POINTER PTR_MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR,
+  Mpi2SCSIIOSuccessReplyDescriptor_t,
+  MPI2_POINTER pMpi2SCSIIOSuccessReplyDescriptor_t;
+
+
+/* TargetAssist Success Reply Descriptor */
+typedef struct _MPI2_TARGETASSIST_SUCCESS_REPLY_DESCRIPTOR
+{
+    U8              ReplyFlags;                 /* 0x00 */
+    U8              VF_ID;                      /* 0x01 */
+    U16             SMID;                       /* 0x02 */
+    U8              SequenceNumber;             /* 0x04 */
+    U8              Reserved1;                  /* 0x05 */
+    U16             IoIndex;                    /* 0x06 */
+} MPI2_TARGETASSIST_SUCCESS_REPLY_DESCRIPTOR,
+  MPI2_POINTER PTR_MPI2_TARGETASSIST_SUCCESS_REPLY_DESCRIPTOR,
+  Mpi2TargetAssistSuccessReplyDescriptor_t,
+  MPI2_POINTER pMpi2TargetAssistSuccessReplyDescriptor_t;
+
+
+/* Target Command Buffer Reply Descriptor */
+typedef struct _MPI2_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR
+{
+    U8              ReplyFlags;                 /* 0x00 */
+    U8              VF_ID;                      /* 0x01 */
+    U8              VP_ID;                      /* 0x02 */
+    U8              Flags;                      /* 0x03 */
+    U16             InitiatorDevHandle;         /* 0x04 */
+    U16             IoIndex;                    /* 0x06 */
+} MPI2_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR,
+  MPI2_POINTER PTR_MPI2_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR,
+  Mpi2TargetCommandBufferReplyDescriptor_t,
+  MPI2_POINTER pMpi2TargetCommandBufferReplyDescriptor_t;
+
+/* defines for Flags field */
+#define MPI2_RPY_DESCRIPT_TCB_FLAGS_PHYNUM_MASK     (0x3F)
+
+
+/* union of Reply Descriptors */
+typedef union _MPI2_REPLY_DESCRIPTORS_UNION
+{
+    MPI2_DEFAULT_REPLY_DESCRIPTOR               Default;
+    MPI2_ADDRESS_REPLY_DESCRIPTOR               AddressReply;
+    MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR       SCSIIOSuccess;
+    MPI2_TARGETASSIST_SUCCESS_REPLY_DESCRIPTOR  TargetAssistSuccess;
+    MPI2_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR TargetCommandBuffer;
+    U64                                         Words;
+} MPI2_REPLY_DESCRIPTORS_UNION, MPI2_POINTER PTR_MPI2_REPLY_DESCRIPTORS_UNION,
+  Mpi2ReplyDescriptorsUnion_t, MPI2_POINTER pMpi2ReplyDescriptorsUnion_t;
+
+
+
+/*****************************************************************************
+*
+*        Message Functions
+*              0x80 -> 0x8F reserved for private message use per product
+*
+*
+*****************************************************************************/
+
+#define MPI2_FUNCTION_SCSI_IO_REQUEST               (0x00) /* SCSI IO */
+#define MPI2_FUNCTION_SCSI_TASK_MGMT                (0x01) /* SCSI Task Management */
+#define MPI2_FUNCTION_IOC_INIT                      (0x02) /* IOC Init */
+#define MPI2_FUNCTION_IOC_FACTS                     (0x03) /* IOC Facts */
+#define MPI2_FUNCTION_CONFIG                        (0x04) /* Configuration */
+#define MPI2_FUNCTION_PORT_FACTS                    (0x05) /* Port Facts */
+#define MPI2_FUNCTION_PORT_ENABLE                   (0x06) /* Port Enable */
+#define MPI2_FUNCTION_EVENT_NOTIFICATION            (0x07) /* Event Notification */
+#define MPI2_FUNCTION_EVENT_ACK                     (0x08) /* Event Acknowledge */
+#define MPI2_FUNCTION_FW_DOWNLOAD                   (0x09) /* FW Download */
+#define MPI2_FUNCTION_TARGET_ASSIST                 (0x0B) /* Target Assist */
+#define MPI2_FUNCTION_TARGET_STATUS_SEND            (0x0C) /* Target Status Send */
+#define MPI2_FUNCTION_TARGET_MODE_ABORT             (0x0D) /* Target Mode Abort */
+#define MPI2_FUNCTION_FW_UPLOAD                     (0x12) /* FW Upload */
+#define MPI2_FUNCTION_RAID_ACTION                   (0x15) /* RAID Action */
+#define MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH      (0x16) /* SCSI IO RAID Passthrough */
+#define MPI2_FUNCTION_TOOLBOX                       (0x17) /* Toolbox */
+#define MPI2_FUNCTION_SCSI_ENCLOSURE_PROCESSOR      (0x18) /* SCSI Enclosure Processor */
+#define MPI2_FUNCTION_SMP_PASSTHROUGH               (0x1A) /* SMP Passthrough */
+#define MPI2_FUNCTION_SAS_IO_UNIT_CONTROL           (0x1B) /* SAS IO Unit Control */
+#define MPI2_FUNCTION_SATA_PASSTHROUGH              (0x1C) /* SATA Passthrough */
+#define MPI2_FUNCTION_DIAG_BUFFER_POST              (0x1D) /* Diagnostic Buffer Post */
+#define MPI2_FUNCTION_DIAG_RELEASE                  (0x1E) /* Diagnostic Release */
+#define MPI2_FUNCTION_TARGET_CMD_BUF_BASE_POST      (0x24) /* Target Command Buffer Post Base */
+#define MPI2_FUNCTION_TARGET_CMD_BUF_LIST_POST      (0x25) /* Target Command Buffer Post List */
+
+
+
+/* Doorbell functions */
+#define MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET        (0x40)
+/* #define MPI2_FUNCTION_IO_UNIT_RESET                 (0x41) */
+#define MPI2_FUNCTION_HANDSHAKE                     (0x42)
+
+
+/*****************************************************************************
+*
+*        IOC Status Values
+*
+*****************************************************************************/
+
+/* mask for IOCStatus status value */
+#define MPI2_IOCSTATUS_MASK                     (0x7FFF)
+
+/****************************************************************************
+*  Common IOCStatus values for all replies
+****************************************************************************/
+
+#define MPI2_IOCSTATUS_SUCCESS                      (0x0000)
+#define MPI2_IOCSTATUS_INVALID_FUNCTION             (0x0001)
+#define MPI2_IOCSTATUS_BUSY                         (0x0002)
+#define MPI2_IOCSTATUS_INVALID_SGL                  (0x0003)
+#define MPI2_IOCSTATUS_INTERNAL_ERROR               (0x0004)
+#define MPI2_IOCSTATUS_INVALID_VPID                 (0x0005)
+#define MPI2_IOCSTATUS_INSUFFICIENT_RESOURCES       (0x0006)
+#define MPI2_IOCSTATUS_INVALID_FIELD                (0x0007)
+#define MPI2_IOCSTATUS_INVALID_STATE                (0x0008)
+#define MPI2_IOCSTATUS_OP_STATE_NOT_SUPPORTED       (0x0009)
+
+/****************************************************************************
+*  Config IOCStatus values
+****************************************************************************/
+
+#define MPI2_IOCSTATUS_CONFIG_INVALID_ACTION        (0x0020)
+#define MPI2_IOCSTATUS_CONFIG_INVALID_TYPE          (0x0021)
+#define MPI2_IOCSTATUS_CONFIG_INVALID_PAGE          (0x0022)
+#define MPI2_IOCSTATUS_CONFIG_INVALID_DATA          (0x0023)
+#define MPI2_IOCSTATUS_CONFIG_NO_DEFAULTS           (0x0024)
+#define MPI2_IOCSTATUS_CONFIG_CANT_COMMIT           (0x0025)
+
+/****************************************************************************
+*  SCSI IO Reply
+****************************************************************************/
+
+#define MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR         (0x0040)
+#define MPI2_IOCSTATUS_SCSI_INVALID_DEVHANDLE       (0x0042)
+#define MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE        (0x0043)
+#define MPI2_IOCSTATUS_SCSI_DATA_OVERRUN            (0x0044)
+#define MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN           (0x0045)
+#define MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR           (0x0046)
+#define MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR          (0x0047)
+#define MPI2_IOCSTATUS_SCSI_TASK_TERMINATED         (0x0048)
+#define MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH       (0x0049)
+#define MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED        (0x004A)
+#define MPI2_IOCSTATUS_SCSI_IOC_TERMINATED          (0x004B)
+#define MPI2_IOCSTATUS_SCSI_EXT_TERMINATED          (0x004C)
+
+/****************************************************************************
+*  For use by SCSI Initiator and SCSI Target end-to-end data protection
+****************************************************************************/
+
+#define MPI2_IOCSTATUS_EEDP_GUARD_ERROR             (0x004D)
+#define MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR           (0x004E)
+#define MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR           (0x004F)
+
+/****************************************************************************
+*  SCSI Target values
+****************************************************************************/
+
+#define MPI2_IOCSTATUS_TARGET_INVALID_IO_INDEX      (0x0062)
+#define MPI2_IOCSTATUS_TARGET_ABORTED               (0x0063)
+#define MPI2_IOCSTATUS_TARGET_NO_CONN_RETRYABLE     (0x0064)
+#define MPI2_IOCSTATUS_TARGET_NO_CONNECTION         (0x0065)
+#define MPI2_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH   (0x006A)
+#define MPI2_IOCSTATUS_TARGET_DATA_OFFSET_ERROR     (0x006D)
+#define MPI2_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA   (0x006E)
+#define MPI2_IOCSTATUS_TARGET_IU_TOO_SHORT          (0x006F)
+#define MPI2_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT       (0x0070)
+#define MPI2_IOCSTATUS_TARGET_NAK_RECEIVED          (0x0071)
+
+/****************************************************************************
+*  Serial Attached SCSI values
+****************************************************************************/
+
+#define MPI2_IOCSTATUS_SAS_SMP_REQUEST_FAILED       (0x0090)
+#define MPI2_IOCSTATUS_SAS_SMP_DATA_OVERRUN         (0x0091)
+
+/****************************************************************************
+*  Diagnostic Buffer Post / Diagnostic Release values
+****************************************************************************/
+
+#define MPI2_IOCSTATUS_DIAGNOSTIC_RELEASED          (0x00A0)
+
+
+/****************************************************************************
+*  IOCStatus flag to indicate that log info is available
+****************************************************************************/
+
+#define MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE  (0x8000)
+
+/****************************************************************************
+*  IOCLogInfo Types
+****************************************************************************/
+
+#define MPI2_IOCLOGINFO_TYPE_MASK               (0xF0000000)
+#define MPI2_IOCLOGINFO_TYPE_SHIFT              (28)
+#define MPI2_IOCLOGINFO_TYPE_NONE               (0x0)
+#define MPI2_IOCLOGINFO_TYPE_SCSI               (0x1)
+#define MPI2_IOCLOGINFO_TYPE_FC                 (0x2)
+#define MPI2_IOCLOGINFO_TYPE_SAS                (0x3)
+#define MPI2_IOCLOGINFO_TYPE_ISCSI              (0x4)
+#define MPI2_IOCLOGINFO_LOG_DATA_MASK           (0x0FFFFFFF)
+
+
+/*****************************************************************************
+*
+*        Standard Message Structures
+*
+*****************************************************************************/
+
+/****************************************************************************
+* Request Message Header for all request messages
+****************************************************************************/
+
+typedef struct _MPI2_REQUEST_HEADER
+{
+    U16             FunctionDependent1;         /* 0x00 */
+    U8              ChainOffset;                /* 0x02 */
+    U8              Function;                   /* 0x03 */
+    U16             FunctionDependent2;         /* 0x04 */
+    U8              FunctionDependent3;         /* 0x06 */
+    U8              MsgFlags;                   /* 0x07 */
+    U8              VP_ID;                      /* 0x08 */
+    U8              VF_ID;                      /* 0x09 */
+    U16             Reserved1;                  /* 0x0A */
+} MPI2_REQUEST_HEADER, MPI2_POINTER PTR_MPI2_REQUEST_HEADER,
+  MPI2RequestHeader_t, MPI2_POINTER pMPI2RequestHeader_t;
+
+
+/****************************************************************************
+*  Default Reply
+****************************************************************************/
+
+typedef struct _MPI2_DEFAULT_REPLY
+{
+    U16             FunctionDependent1;         /* 0x00 */
+    U8              MsgLength;                  /* 0x02 */
+    U8              Function;                   /* 0x03 */
+    U16             FunctionDependent2;         /* 0x04 */
+    U8              FunctionDependent3;         /* 0x06 */
+    U8              MsgFlags;                   /* 0x07 */
+    U8              VP_ID;                      /* 0x08 */
+    U8              VF_ID;                      /* 0x09 */
+    U16             Reserved1;                  /* 0x0A */
+    U16             FunctionDependent5;         /* 0x0C */
+    U16             IOCStatus;                  /* 0x0E */
+    U32             IOCLogInfo;                 /* 0x10 */
+} MPI2_DEFAULT_REPLY, MPI2_POINTER PTR_MPI2_DEFAULT_REPLY,
+  MPI2DefaultReply_t, MPI2_POINTER pMPI2DefaultReply_t;
+
+
+/* common version structure/union used in messages and configuration pages */
+
+typedef struct _MPI2_VERSION_STRUCT
+{
+    U8                      Dev;                        /* 0x00 */
+    U8                      Unit;                       /* 0x01 */
+    U8                      Minor;                      /* 0x02 */
+    U8                      Major;                      /* 0x03 */
+} MPI2_VERSION_STRUCT;
+
+typedef union _MPI2_VERSION_UNION
+{
+    MPI2_VERSION_STRUCT     Struct;
+    U32                     Word;
+} MPI2_VERSION_UNION;
+
+
+/* LUN field defines, common to many structures */
+#define MPI2_LUN_FIRST_LEVEL_ADDRESSING             (0x0000FFFF)
+#define MPI2_LUN_SECOND_LEVEL_ADDRESSING            (0xFFFF0000)
+#define MPI2_LUN_THIRD_LEVEL_ADDRESSING             (0x0000FFFF)
+#define MPI2_LUN_FOURTH_LEVEL_ADDRESSING            (0xFFFF0000)
+#define MPI2_LUN_LEVEL_1_WORD                       (0xFF00)
+#define MPI2_LUN_LEVEL_1_DWORD                      (0x0000FF00)
+
+
+/*****************************************************************************
+*
+*        Fusion-MPT MPI Scatter Gather Elements
+*
+*****************************************************************************/
+
+/****************************************************************************
+*  MPI Simple Element structures
+****************************************************************************/
+
+typedef struct _MPI2_SGE_SIMPLE32
+{
+    U32                     FlagsLength;
+    U32                     Address;
+} MPI2_SGE_SIMPLE32, MPI2_POINTER PTR_MPI2_SGE_SIMPLE32,
+  Mpi2SGESimple32_t, MPI2_POINTER pMpi2SGESimple32_t;
+
+typedef struct _MPI2_SGE_SIMPLE64
+{
+    U32                     FlagsLength;
+    U64                     Address;
+} MPI2_SGE_SIMPLE64, MPI2_POINTER PTR_MPI2_SGE_SIMPLE64,
+  Mpi2SGESimple64_t, MPI2_POINTER pMpi2SGESimple64_t;
+
+typedef struct _MPI2_SGE_SIMPLE_UNION
+{
+    U32                     FlagsLength;
+    union
+    {
+        U32                 Address32;
+        U64                 Address64;
+    } u;
+} MPI2_SGE_SIMPLE_UNION, MPI2_POINTER PTR_MPI2_SGE_SIMPLE_UNION,
+  Mpi2SGESimpleUnion_t, MPI2_POINTER pMpi2SGESimpleUnion_t;
+
+
+/****************************************************************************
+*  MPI Chain Element structures
+****************************************************************************/
+
+typedef struct _MPI2_SGE_CHAIN32
+{
+    U16                     Length;
+    U8                      NextChainOffset;
+    U8                      Flags;
+    U32                     Address;
+} MPI2_SGE_CHAIN32, MPI2_POINTER PTR_MPI2_SGE_CHAIN32,
+  Mpi2SGEChain32_t, MPI2_POINTER pMpi2SGEChain32_t;
+
+typedef struct _MPI2_SGE_CHAIN64
+{
+    U16                     Length;
+    U8                      NextChainOffset;
+    U8                      Flags;
+    U64                     Address;
+} MPI2_SGE_CHAIN64, MPI2_POINTER PTR_MPI2_SGE_CHAIN64,
+  Mpi2SGEChain64_t, MPI2_POINTER pMpi2SGEChain64_t;
+
+typedef struct _MPI2_SGE_CHAIN_UNION
+{
+    U16                     Length;
+    U8                      NextChainOffset;
+    U8                      Flags;
+    union
+    {
+        U32                 Address32;
+        U64                 Address64;
+    } u;
+} MPI2_SGE_CHAIN_UNION, MPI2_POINTER PTR_MPI2_SGE_CHAIN_UNION,
+  Mpi2SGEChainUnion_t, MPI2_POINTER pMpi2SGEChainUnion_t;
+
+
+/****************************************************************************
+*  MPI Transaction Context Element structures
+****************************************************************************/
+
+typedef struct _MPI2_SGE_TRANSACTION32
+{
+    U8                      Reserved;
+    U8                      ContextSize;
+    U8                      DetailsLength;
+    U8                      Flags;
+    U32                     TransactionContext[1];
+    U32                     TransactionDetails[1];
+} MPI2_SGE_TRANSACTION32, MPI2_POINTER PTR_MPI2_SGE_TRANSACTION32,
+  Mpi2SGETransaction32_t, MPI2_POINTER pMpi2SGETransaction32_t;
+
+typedef struct _MPI2_SGE_TRANSACTION64
+{
+    U8                      Reserved;
+    U8                      ContextSize;
+    U8                      DetailsLength;
+    U8                      Flags;
+    U32                     TransactionContext[2];
+    U32                     TransactionDetails[1];
+} MPI2_SGE_TRANSACTION64, MPI2_POINTER PTR_MPI2_SGE_TRANSACTION64,
+  Mpi2SGETransaction64_t, MPI2_POINTER pMpi2SGETransaction64_t;
+
+typedef struct _MPI2_SGE_TRANSACTION96
+{
+    U8                      Reserved;
+    U8                      ContextSize;
+    U8                      DetailsLength;
+    U8                      Flags;
+    U32                     TransactionContext[3];
+    U32                     TransactionDetails[1];
+} MPI2_SGE_TRANSACTION96, MPI2_POINTER PTR_MPI2_SGE_TRANSACTION96,
+  Mpi2SGETransaction96_t, MPI2_POINTER pMpi2SGETransaction96_t;
+
+typedef struct _MPI2_SGE_TRANSACTION128
+{
+    U8                      Reserved;
+    U8                      ContextSize;
+    U8                      DetailsLength;
+    U8                      Flags;
+    U32                     TransactionContext[4];
+    U32                     TransactionDetails[1];
+} MPI2_SGE_TRANSACTION128, MPI2_POINTER PTR_MPI2_SGE_TRANSACTION128,
+  Mpi2SGETransaction_t128, MPI2_POINTER pMpi2SGETransaction_t128;
+
+typedef struct _MPI2_SGE_TRANSACTION_UNION
+{
+    U8                      Reserved;
+    U8                      ContextSize;
+    U8                      DetailsLength;
+    U8                      Flags;
+    union
+    {
+        U32                 TransactionContext32[1];
+        U32                 TransactionContext64[2];
+        U32                 TransactionContext96[3];
+        U32                 TransactionContext128[4];
+    } u;
+    U32                     TransactionDetails[1];
+} MPI2_SGE_TRANSACTION_UNION, MPI2_POINTER PTR_MPI2_SGE_TRANSACTION_UNION,
+  Mpi2SGETransactionUnion_t, MPI2_POINTER pMpi2SGETransactionUnion_t;
+
+
+/****************************************************************************
+*  MPI SGE union for IO SGL's
+****************************************************************************/
+
+typedef struct _MPI2_MPI_SGE_IO_UNION
+{
+    union
+    {
+        MPI2_SGE_SIMPLE_UNION   Simple;
+        MPI2_SGE_CHAIN_UNION    Chain;
+    } u;
+} MPI2_MPI_SGE_IO_UNION, MPI2_POINTER PTR_MPI2_MPI_SGE_IO_UNION,
+  Mpi2MpiSGEIOUnion_t, MPI2_POINTER pMpi2MpiSGEIOUnion_t;
+
+
+/****************************************************************************
+*  MPI SGE union for SGL's with Simple and Transaction elements
+****************************************************************************/
+
+typedef struct _MPI2_SGE_TRANS_SIMPLE_UNION
+{
+    union
+    {
+        MPI2_SGE_SIMPLE_UNION       Simple;
+        MPI2_SGE_TRANSACTION_UNION  Transaction;
+    } u;
+} MPI2_SGE_TRANS_SIMPLE_UNION, MPI2_POINTER PTR_MPI2_SGE_TRANS_SIMPLE_UNION,
+  Mpi2SGETransSimpleUnion_t, MPI2_POINTER pMpi2SGETransSimpleUnion_t;
+
+
+/****************************************************************************
+*  All MPI SGE types union
+****************************************************************************/
+
+typedef struct _MPI2_MPI_SGE_UNION
+{
+    union
+    {
+        MPI2_SGE_SIMPLE_UNION       Simple;
+        MPI2_SGE_CHAIN_UNION        Chain;
+        MPI2_SGE_TRANSACTION_UNION  Transaction;
+    } u;
+} MPI2_MPI_SGE_UNION, MPI2_POINTER PTR_MPI2_MPI_SGE_UNION,
+  Mpi2MpiSgeUnion_t, MPI2_POINTER pMpi2MpiSgeUnion_t;
+
+
+/****************************************************************************
+*  MPI SGE field definition and masks
+****************************************************************************/
+
+/* Flags field bit definitions */
+
+#define MPI2_SGE_FLAGS_LAST_ELEMENT             (0x80)
+#define MPI2_SGE_FLAGS_END_OF_BUFFER            (0x40)
+#define MPI2_SGE_FLAGS_ELEMENT_TYPE_MASK        (0x30)
+#define MPI2_SGE_FLAGS_LOCAL_ADDRESS            (0x08)
+#define MPI2_SGE_FLAGS_DIRECTION                (0x04)
+#define MPI2_SGE_FLAGS_ADDRESS_SIZE             (0x02)
+#define MPI2_SGE_FLAGS_END_OF_LIST              (0x01)
+
+#define MPI2_SGE_FLAGS_SHIFT                    (24)
+
+#define MPI2_SGE_LENGTH_MASK                    (0x00FFFFFF)
+#define MPI2_SGE_CHAIN_LENGTH_MASK              (0x0000FFFF)
+
+/* Element Type */
+
+#define MPI2_SGE_FLAGS_TRANSACTION_ELEMENT      (0x00)
+#define MPI2_SGE_FLAGS_SIMPLE_ELEMENT           (0x10)
+#define MPI2_SGE_FLAGS_CHAIN_ELEMENT            (0x30)
+#define MPI2_SGE_FLAGS_ELEMENT_MASK             (0x30)
+
+/* Address location */
+
+#define MPI2_SGE_FLAGS_SYSTEM_ADDRESS           (0x00)
+
+/* Direction */
+
+#define MPI2_SGE_FLAGS_IOC_TO_HOST              (0x00)
+#define MPI2_SGE_FLAGS_HOST_TO_IOC              (0x04)
+
+/* Address Size */
+
+#define MPI2_SGE_FLAGS_32_BIT_ADDRESSING        (0x00)
+#define MPI2_SGE_FLAGS_64_BIT_ADDRESSING        (0x02)
+
+/* Context Size */
+
+#define MPI2_SGE_FLAGS_32_BIT_CONTEXT           (0x00)
+#define MPI2_SGE_FLAGS_64_BIT_CONTEXT           (0x02)
+#define MPI2_SGE_FLAGS_96_BIT_CONTEXT           (0x04)
+#define MPI2_SGE_FLAGS_128_BIT_CONTEXT          (0x06)
+
+#define MPI2_SGE_CHAIN_OFFSET_MASK              (0x00FF0000)
+#define MPI2_SGE_CHAIN_OFFSET_SHIFT             (16)
+
+/****************************************************************************
+*  MPI SGE operation Macros
+****************************************************************************/
+
+/* SIMPLE FlagsLength manipulations... */
+#define MPI2_SGE_SET_FLAGS(f)          ((U32)(f) << MPI2_SGE_FLAGS_SHIFT)
+#define MPI2_SGE_GET_FLAGS(f)          (((f) & ~MPI2_SGE_LENGTH_MASK) >> MPI2_SGE_FLAGS_SHIFT)
+#define MPI2_SGE_LENGTH(f)             ((f) & MPI2_SGE_LENGTH_MASK)
+#define MPI2_SGE_CHAIN_LENGTH(f)       ((f) & MPI2_SGE_CHAIN_LENGTH_MASK)
+
+#define MPI2_SGE_SET_FLAGS_LENGTH(f,l) (MPI2_SGE_SET_FLAGS(f) | MPI2_SGE_LENGTH(l))
+
+#define MPI2_pSGE_GET_FLAGS(psg)            MPI2_SGE_GET_FLAGS((psg)->FlagsLength)
+#define MPI2_pSGE_GET_LENGTH(psg)           MPI2_SGE_LENGTH((psg)->FlagsLength)
+#define MPI2_pSGE_SET_FLAGS_LENGTH(psg,f,l) (psg)->FlagsLength = MPI2_SGE_SET_FLAGS_LENGTH(f,l)
+
+/* CAUTION - The following are READ-MODIFY-WRITE! */
+#define MPI2_pSGE_SET_FLAGS(psg,f)      (psg)->FlagsLength |= MPI2_SGE_SET_FLAGS(f)
+#define MPI2_pSGE_SET_LENGTH(psg,l)     (psg)->FlagsLength |= MPI2_SGE_LENGTH(l)
+
+#define MPI2_GET_CHAIN_OFFSET(x)    ((x & MPI2_SGE_CHAIN_OFFSET_MASK) >> MPI2_SGE_CHAIN_OFFSET_SHIFT)
+
+
+/*****************************************************************************
+*
+*        Fusion-MPT IEEE Scatter Gather Elements
+*
+*****************************************************************************/
+
+/****************************************************************************
+*  IEEE Simple Element structures
+****************************************************************************/
+
+typedef struct _MPI2_IEEE_SGE_SIMPLE32
+{
+    U32                     Address;
+    U32                     FlagsLength;
+} MPI2_IEEE_SGE_SIMPLE32, MPI2_POINTER PTR_MPI2_IEEE_SGE_SIMPLE32,
+  Mpi2IeeeSgeSimple32_t, MPI2_POINTER pMpi2IeeeSgeSimple32_t;
+
+typedef struct _MPI2_IEEE_SGE_SIMPLE64
+{
+    U64                     Address;
+    U32                     Length;
+    U16                     Reserved1;
+    U8                      Reserved2;
+    U8                      Flags;
+} MPI2_IEEE_SGE_SIMPLE64, MPI2_POINTER PTR_MPI2_IEEE_SGE_SIMPLE64,
+  Mpi2IeeeSgeSimple64_t, MPI2_POINTER pMpi2IeeeSgeSimple64_t;
+
+typedef union _MPI2_IEEE_SGE_SIMPLE_UNION
+{
+    MPI2_IEEE_SGE_SIMPLE32  Simple32;
+    MPI2_IEEE_SGE_SIMPLE64  Simple64;
+} MPI2_IEEE_SGE_SIMPLE_UNION, MPI2_POINTER PTR_MPI2_IEEE_SGE_SIMPLE_UNION,
+  Mpi2IeeeSgeSimpleUnion_t, MPI2_POINTER pMpi2IeeeSgeSimpleUnion_t;
+
+
+/****************************************************************************
+*  IEEE Chain Element structures
+****************************************************************************/
+
+typedef MPI2_IEEE_SGE_SIMPLE32  MPI2_IEEE_SGE_CHAIN32;
+
+typedef MPI2_IEEE_SGE_SIMPLE64  MPI2_IEEE_SGE_CHAIN64;
+
+typedef union _MPI2_IEEE_SGE_CHAIN_UNION
+{
+    MPI2_IEEE_SGE_CHAIN32   Chain32;
+    MPI2_IEEE_SGE_CHAIN64   Chain64;
+} MPI2_IEEE_SGE_CHAIN_UNION, MPI2_POINTER PTR_MPI2_IEEE_SGE_CHAIN_UNION,
+  Mpi2IeeeSgeChainUnion_t, MPI2_POINTER pMpi2IeeeSgeChainUnion_t;
+
+
+/****************************************************************************
+*  All IEEE SGE types union
+****************************************************************************/
+
+typedef struct _MPI2_IEEE_SGE_UNION
+{
+    union
+    {
+        MPI2_IEEE_SGE_SIMPLE_UNION  Simple;
+        MPI2_IEEE_SGE_CHAIN_UNION   Chain;
+    } u;
+} MPI2_IEEE_SGE_UNION, MPI2_POINTER PTR_MPI2_IEEE_SGE_UNION,
+  Mpi2IeeeSgeUnion_t, MPI2_POINTER pMpi2IeeeSgeUnion_t;
+
+
+/****************************************************************************
+*  IEEE SGE field definitions and masks
+****************************************************************************/
+
+/* Flags field bit definitions */
+
+#define MPI2_IEEE_SGE_FLAGS_ELEMENT_TYPE_MASK   (0x80)
+
+#define MPI2_IEEE32_SGE_FLAGS_SHIFT             (24)
+
+#define MPI2_IEEE32_SGE_LENGTH_MASK             (0x00FFFFFF)
+
+/* Element Type */
+
+#define MPI2_IEEE_SGE_FLAGS_SIMPLE_ELEMENT      (0x00)
+#define MPI2_IEEE_SGE_FLAGS_CHAIN_ELEMENT       (0x80)
+
+/* Data Location Address Space */
+
+#define MPI2_IEEE_SGE_FLAGS_ADDR_MASK           (0x03)
+#define MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR         (0x00)
+#define MPI2_IEEE_SGE_FLAGS_IOCDDR_ADDR         (0x01)
+#define MPI2_IEEE_SGE_FLAGS_IOCPLB_ADDR         (0x02)
+#define MPI2_IEEE_SGE_FLAGS_IOCPLBNTA_ADDR      (0x03)
+
+
+/****************************************************************************
+*  IEEE SGE operation Macros
+****************************************************************************/
+
+/* SIMPLE FlagsLength manipulations... */
+#define MPI2_IEEE32_SGE_SET_FLAGS(f)     ((U32)(f) << MPI2_IEEE32_SGE_FLAGS_SHIFT)
+#define MPI2_IEEE32_SGE_GET_FLAGS(f)     (((f) & ~MPI2_IEEE32_SGE_LENGTH_MASK) >> MPI2_IEEE32_SGE_FLAGS_SHIFT)
+#define MPI2_IEEE32_SGE_LENGTH(f)        ((f) & MPI2_IEEE32_SGE_LENGTH_MASK)
+
+#define MPI2_IEEE32_SGE_SET_FLAGS_LENGTH(f, l)      (MPI2_IEEE32_SGE_SET_FLAGS(f) | MPI2_IEEE32_SGE_LENGTH(l))
+
+#define MPI2_IEEE32_pSGE_GET_FLAGS(psg)             MPI2_IEEE32_SGE_GET_FLAGS((psg)->FlagsLength)
+#define MPI2_IEEE32_pSGE_GET_LENGTH(psg)            MPI2_IEEE32_SGE_LENGTH((psg)->FlagsLength)
+#define MPI2_IEEE32_pSGE_SET_FLAGS_LENGTH(psg,f,l)  (psg)->FlagsLength = MPI2_IEEE32_SGE_SET_FLAGS_LENGTH(f,l)
+
+/* CAUTION - The following are READ-MODIFY-WRITE! */
+#define MPI2_IEEE32_pSGE_SET_FLAGS(psg,f)    (psg)->FlagsLength |= MPI2_IEEE32_SGE_SET_FLAGS(f)
+#define MPI2_IEEE32_pSGE_SET_LENGTH(psg,l)   (psg)->FlagsLength |= MPI2_IEEE32_SGE_LENGTH(l)
+
+
+
+
+/*****************************************************************************
+*
+*        Fusion-MPT MPI/IEEE Scatter Gather Unions
+*
+*****************************************************************************/
+
+typedef union _MPI2_SIMPLE_SGE_UNION
+{
+    MPI2_SGE_SIMPLE_UNION       MpiSimple;
+    MPI2_IEEE_SGE_SIMPLE_UNION  IeeeSimple;
+} MPI2_SIMPLE_SGE_UNION, MPI2_POINTER PTR_MPI2_SIMPLE_SGE_UNION,
+  Mpi2SimpleSgeUntion_t, MPI2_POINTER pMpi2SimpleSgeUntion_t;
+
+
+typedef union _MPI2_SGE_IO_UNION
+{
+    MPI2_SGE_SIMPLE_UNION       MpiSimple;
+    MPI2_SGE_CHAIN_UNION        MpiChain;
+    MPI2_IEEE_SGE_SIMPLE_UNION  IeeeSimple;
+    MPI2_IEEE_SGE_CHAIN_UNION   IeeeChain;
+} MPI2_SGE_IO_UNION, MPI2_POINTER PTR_MPI2_SGE_IO_UNION,
+  Mpi2SGEIOUnion_t, MPI2_POINTER pMpi2SGEIOUnion_t;
+
+
+/****************************************************************************
+*
+*  Values for SGLFlags field, used in many request messages with an SGL
+*
+****************************************************************************/
+
+/* values for MPI SGL Data Location Address Space subfield */
+#define MPI2_SGLFLAGS_ADDRESS_SPACE_MASK            (0x0C)
+#define MPI2_SGLFLAGS_SYSTEM_ADDRESS_SPACE          (0x00)
+#define MPI2_SGLFLAGS_IOCDDR_ADDRESS_SPACE          (0x04)
+#define MPI2_SGLFLAGS_IOCPLB_ADDRESS_SPACE          (0x08)
+#define MPI2_SGLFLAGS_IOCPLBNTA_ADDRESS_SPACE       (0x0C)
+/* values for SGL Type subfield */
+#define MPI2_SGLFLAGS_SGL_TYPE_MASK                 (0x03)
+#define MPI2_SGLFLAGS_SGL_TYPE_MPI                  (0x00)
+#define MPI2_SGLFLAGS_SGL_TYPE_IEEE32               (0x01)
+#define MPI2_SGLFLAGS_SGL_TYPE_IEEE64               (0x02)
+
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/sys/scsi/adapters/mpt_sas/mpi/mpi2_cnfg.h	Fri Jun 19 20:12:07 2009 +0800
@@ -0,0 +1,2196 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2000 to 2009, LSI Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms of all code within
+ * this file that is exclusively owned by LSI, with or without
+ * modification, is permitted provided that, in addition to the CDDL 1.0
+ * License requirements, the following conditions are met:
+ *
+ *    Neither the name of the author nor the names of its contributors may be
+ *    used to endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ */
+
+/*
+ *           Name:  mpi2_cnfg.h
+ *          Title:  MPI Configuration messages and pages
+ *  Creation Date:  November 10, 2006
+ *
+ *    mpi2_cnfg.h Version:  02.00.10
+ *
+ *  Version History
+ *  ---------------
+ *
+ *  Date      Version   Description
+ *  --------  --------  ------------------------------------------------------
+ *  04-30-07  02.00.00  Corresponds to Fusion-MPT MPI Specification Rev A.
+ *  06-04-07  02.00.01  Added defines for SAS IO Unit Page 2 PhyFlags.
+ *                      Added Manufacturing Page 11.
+ *                      Added MPI2_SAS_EXPANDER0_FLAGS_CONNECTOR_END_DEVICE
+ *                      define.
+ *  06-26-07  02.00.02  Adding generic structure for product-specific
+ *                      Manufacturing pages: MPI2_CONFIG_PAGE_MANUFACTURING_PS.
+ *                      Rework of BIOS Page 2 configuration page.
+ *                      Fixed MPI2_BIOSPAGE2_BOOT_DEVICE to be a union of the
+ *                      forms.
+ *                      Added configuration pages IOC Page 8 and Driver
+ *                      Persistent Mapping Page 0.
+ *  08-31-07  02.00.03  Modified configuration pages dealing with Integrated
+ *                      RAID (Manufacturing Page 4, RAID Volume Pages 0 and 1,
+ *                      RAID Physical Disk Pages 0 and 1, RAID Configuration
+ *                      Page 0).
+ *                      Added new value for AccessStatus field of SAS Device
+ *                      Page 0 (_SATA_NEEDS_INITIALIZATION).
+ *  10-31-07  02.00.04  Added missing SEPDevHandle field to
+ *                      MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0.
+ *  12-18-07  02.00.05  Modified IO Unit Page 0 to use 32-bit version fields for
+ *                      NVDATA.
+ *                      Modified IOC Page 7 to use masks and added field for
+ *                      SASBroadcastPrimitiveMasks.
+ *                      Added MPI2_CONFIG_PAGE_BIOS_4.
+ *                      Added MPI2_CONFIG_PAGE_LOG_0.
+ *  02-29-08  02.00.06  Modified various names to make them 32-character unique.
+ *                      Added SAS Device IDs.
+ *                      Updated Integrated RAID configuration pages including
+ *                      Manufacturing Page 4, IOC Page 6, and RAID Configuration
+ *                      Page 0.
+ *  05-21-08  02.00.07  Added define MPI2_MANPAGE4_MIX_SSD_SAS_SATA.
+ *                      Added define MPI2_MANPAGE4_PHYSDISK_128MB_COERCION.
+ *                      Fixed define MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING.
+ *                      Added missing MaxNumRoutedSasAddresses field to
+ *                      MPI2_CONFIG_PAGE_EXPANDER_0.
+ *                      Added SAS Port Page 0.
+ *                      Modified structure layout for
+ *                      MPI2_CONFIG_PAGE_DRIVER_MAPPING_0.
+ *  06-27-08  02.00.08  Changed MPI2_CONFIG_PAGE_RD_PDISK_1 to use
+ *                      MPI2_RAID_PHYS_DISK1_PATH_MAX to size the array.
+ *  10-02-08  02.00.09  Changed MPI2_RAID_PGAD_CONFIGNUM_MASK from 0x0000FFFF
+ *                      to 0x000000FF.
+ *                      Added two new values for the Physical Disk Coercion Size
+ *                      bits in the Flags field of Manufacturing Page 4.
+ *                      Added product-specific Manufacturing pages 16 to 31.
+ *                      Modified Flags bits for controlling write cache on SATA
+ *                      drives in IO Unit Page 1.
+ *                      Added new bit to AdditionalControlFlags of SAS IO Unit
+ *                      Page 1 to control Invalid Topology Correction.
+ *                      Added additional defines for RAID Volume Page 0
+ *                      VolumeStatusFlags field.
+ *                      Modified meaning of RAID Volume Page 0 VolumeSettings
+ *                      define for auto-configure of hot-swap drives.
+ *                      Added SupportedPhysDisks field to RAID Volume Page 1 and
+ *                      added related defines.
+ *                      Added PhysDiskAttributes field (and related defines) to
+ *                      RAID Physical Disk Page 0.
+ *                      Added MPI2_SAS_PHYINFO_PHY_VACANT define.
+ *                      Added three new DiscoveryStatus bits for SAS IO Unit
+ *                      Page 0 and SAS Expander Page 0.
+ *                      Removed multiplexing information from SAS IO Unit pages.
+ *                      Added BootDeviceWaitTime field to SAS IO Unit Page 4.
+ *                      Removed Zone Address Resolved bit from PhyInfo and from
+ *                      Expander Page 0 Flags field.
+ *                      Added two new AccessStatus values to SAS Device Page 0
+ *                      for indicating routing problems. Added 3 reserved words
+ *                      to this page.
+ *  01-19-09  02.00.10  Fixed defines for GPIOVal field of IO Unit Page 3.
+ *                      Inserted missing reserved field into structure for IOC
+ *                      Page 6.
+ *                      Added more pending task bits to RAID Volume Page 0
+ *                      VolumeStatusFlags defines.
+ *                      Added MPI2_PHYSDISK0_STATUS_FLAG_NOT_CERTIFIED define.
+ *                      Added a new DiscoveryStatus bit for SAS IO Unit Page 0
+ *                      and SAS Expander Page 0 to flag a downstream initiator
+ *                      when in simplified routing mode.
+ *                      Removed SATA Init Failure defines for DiscoveryStatus
+ *                      fields of SAS IO Unit Page 0 and SAS Expander Page 0.
+ *                      Added MPI2_SAS_DEVICE0_ASTATUS_DEVICE_BLOCKED define.
+ *                      Added PortGroups, DmaGroup, and ControlGroup fields to
+ *                      SAS Device Page 0.
+ *  --------------------------------------------------------------------------
+ */
+
+#ifndef MPI2_CNFG_H
+#define MPI2_CNFG_H
+
+/*****************************************************************************
+*   Configuration Page Header and defines
+*****************************************************************************/
+
+/* Config Page Header */
+typedef struct _MPI2_CONFIG_PAGE_HEADER
+{
+    U8                 PageVersion;                /* 0x00 */
+    U8                 PageLength;                 /* 0x01 */
+    U8                 PageNumber;                 /* 0x02 */
+    U8                 PageType;                   /* 0x03 */
+} MPI2_CONFIG_PAGE_HEADER, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_HEADER,
+  Mpi2ConfigPageHeader_t, MPI2_POINTER pMpi2ConfigPageHeader_t;
+
+typedef union _MPI2_CONFIG_PAGE_HEADER_UNION
+{
+   MPI2_CONFIG_PAGE_HEADER  Struct;
+   U8                       Bytes[4];
+   U16                      Word16[2];
+   U32                      Word32;
+} MPI2_CONFIG_PAGE_HEADER_UNION, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_HEADER_UNION,
+  Mpi2ConfigPageHeaderUnion, MPI2_POINTER pMpi2ConfigPageHeaderUnion;
+
+/* Extended Config Page Header */
+typedef struct _MPI2_CONFIG_EXTENDED_PAGE_HEADER
+{
+    U8                  PageVersion;                /* 0x00 */
+    U8                  Reserved1;                  /* 0x01 */
+    U8                  PageNumber;                 /* 0x02 */
+    U8                  PageType;                   /* 0x03 */
+    U16                 ExtPageLength;              /* 0x04 */
+    U8                  ExtPageType;                /* 0x06 */
+    U8                  Reserved2;                  /* 0x07 */
+} MPI2_CONFIG_EXTENDED_PAGE_HEADER,
+  MPI2_POINTER PTR_MPI2_CONFIG_EXTENDED_PAGE_HEADER,
+  Mpi2ConfigExtendedPageHeader_t, MPI2_POINTER pMpi2ConfigExtendedPageHeader_t;
+
+typedef union _MPI2_CONFIG_EXT_PAGE_HEADER_UNION
+{
+   MPI2_CONFIG_PAGE_HEADER          Struct;
+   MPI2_CONFIG_EXTENDED_PAGE_HEADER Ext;
+   U8                               Bytes[8];
+   U16                              Word16[4];
+   U32                              Word32[2];
+} MPI2_CONFIG_EXT_PAGE_HEADER_UNION, MPI2_POINTER PTR_MPI2_CONFIG_EXT_PAGE_HEADER_UNION,
+  Mpi2ConfigPageExtendedHeaderUnion, MPI2_POINTER pMpi2ConfigPageExtendedHeaderUnion;
+
+
+/* PageType field values */
+#define MPI2_CONFIG_PAGEATTR_READ_ONLY              (0x00)
+#define MPI2_CONFIG_PAGEATTR_CHANGEABLE             (0x10)
+#define MPI2_CONFIG_PAGEATTR_PERSISTENT             (0x20)
+#define MPI2_CONFIG_PAGEATTR_MASK                   (0xF0)
+
+#define MPI2_CONFIG_PAGETYPE_IO_UNIT                (0x00)
+#define MPI2_CONFIG_PAGETYPE_IOC                    (0x01)
+#define MPI2_CONFIG_PAGETYPE_BIOS                   (0x02)
+#define MPI2_CONFIG_PAGETYPE_RAID_VOLUME            (0x08)
+#define MPI2_CONFIG_PAGETYPE_MANUFACTURING          (0x09)
+#define MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK          (0x0A)
+#define MPI2_CONFIG_PAGETYPE_EXTENDED               (0x0F)
+#define MPI2_CONFIG_PAGETYPE_MASK                   (0x0F)
+
+#define MPI2_CONFIG_TYPENUM_MASK                    (0x0FFF)
+
+
+/* ExtPageType field values */
+#define MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT         (0x10)
+#define MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER        (0x11)
+#define MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE          (0x12)
+#define MPI2_CONFIG_EXTPAGETYPE_SAS_PHY             (0x13)
+#define MPI2_CONFIG_EXTPAGETYPE_LOG                 (0x14)
+#define MPI2_CONFIG_EXTPAGETYPE_ENCLOSURE           (0x15)
+#define MPI2_CONFIG_EXTPAGETYPE_RAID_CONFIG         (0x16)
+#define MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING      (0x17)
+#define MPI2_CONFIG_EXTPAGETYPE_SAS_PORT            (0x18)
+
+
+/*****************************************************************************
+*   PageAddress defines
+*****************************************************************************/
+
+/* RAID Volume PageAddress format */
+#define MPI2_RAID_VOLUME_PGAD_FORM_MASK             (0xF0000000)
+#define MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE  (0x00000000)
+#define MPI2_RAID_VOLUME_PGAD_FORM_HANDLE           (0x10000000)
+
+#define MPI2_RAID_VOLUME_PGAD_HANDLE_MASK           (0x0000FFFF)
+
+
+/* RAID Physical Disk PageAddress format */
+#define MPI2_PHYSDISK_PGAD_FORM_MASK                    (0xF0000000)
+#define MPI2_PHYSDISK_PGAD_FORM_GET_NEXT_PHYSDISKNUM    (0x00000000)
+#define MPI2_PHYSDISK_PGAD_FORM_PHYSDISKNUM             (0x10000000)
+#define MPI2_PHYSDISK_PGAD_FORM_DEVHANDLE               (0x20000000)
+
+#define MPI2_PHYSDISK_PGAD_PHYSDISKNUM_MASK             (0x000000FF)
+#define MPI2_PHYSDISK_PGAD_DEVHANDLE_MASK               (0x0000FFFF)
+
+
+/* SAS Expander PageAddress format */
+#define MPI2_SAS_EXPAND_PGAD_FORM_MASK              (0xF0000000)
+#define MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL     (0x00000000)
+#define MPI2_SAS_EXPAND_PGAD_FORM_HNDL_PHY_NUM      (0x10000000)
+#define MPI2_SAS_EXPAND_PGAD_FORM_HNDL              (0x20000000)
+
+#define MPI2_SAS_EXPAND_PGAD_HANDLE_MASK            (0x0000FFFF)
+#define MPI2_SAS_EXPAND_PGAD_PHYNUM_MASK            (0x00FF0000)
+#define MPI2_SAS_EXPAND_PGAD_PHYNUM_SHIFT           (16)
+
+
+/* SAS Device PageAddress format */
+#define MPI2_SAS_DEVICE_PGAD_FORM_MASK              (0xF0000000)
+#define MPI2_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE   (0x00000000)
+#define MPI2_SAS_DEVICE_PGAD_FORM_HANDLE            (0x20000000)
+
+#define MPI2_SAS_DEVICE_PGAD_HANDLE_MASK            (0x0000FFFF)
+
+
+/* SAS PHY PageAddress format */
+#define MPI2_SAS_PHY_PGAD_FORM_MASK                 (0xF0000000)
+#define MPI2_SAS_PHY_PGAD_FORM_PHY_NUMBER           (0x00000000)
+#define MPI2_SAS_PHY_PGAD_FORM_PHY_TBL_INDEX        (0x10000000)
+
+#define MPI2_SAS_PHY_PGAD_PHY_NUMBER_MASK           (0x000000FF)
+#define MPI2_SAS_PHY_PGAD_PHY_TBL_INDEX_MASK        (0x0000FFFF)
+
+
+/* SAS Port PageAddress format */
+#define MPI2_SASPORT_PGAD_FORM_MASK                 (0xF0000000)
+#define MPI2_SASPORT_PGAD_FORM_GET_NEXT_PORT        (0x00000000)
+#define MPI2_SASPORT_PGAD_FORM_PORT_NUM             (0x10000000)
+
+#define MPI2_SASPORT_PGAD_PORTNUMBER_MASK           (0x00000FFF)
+
+
+/* SAS Enclosure PageAddress format */
+#define MPI2_SAS_ENCLOS_PGAD_FORM_MASK              (0xF0000000)
+#define MPI2_SAS_ENCLOS_PGAD_FORM_GET_NEXT_HANDLE   (0x00000000)
+#define MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE            (0x10000000)
+
+#define MPI2_SAS_ENCLOS_PGAD_HANDLE_MASK            (0x0000FFFF)
+
+
+/* RAID Configuration PageAddress format */
+#define MPI2_RAID_PGAD_FORM_MASK                    (0xF0000000)
+#define MPI2_RAID_PGAD_FORM_GET_NEXT_CONFIGNUM      (0x00000000)
+#define MPI2_RAID_PGAD_FORM_CONFIGNUM               (0x10000000)
+#define MPI2_RAID_PGAD_FORM_ACTIVE_CONFIG           (0x20000000)
+
+#define MPI2_RAID_PGAD_CONFIGNUM_MASK               (0x000000FF)
+
+
+/* Driver Persistent Mapping PageAddress format */
+#define MPI2_DPM_PGAD_FORM_MASK                     (0xF0000000)
+#define MPI2_DPM_PGAD_FORM_ENTRY_RANGE              (0x00000000)
+
+#define MPI2_DPM_PGAD_ENTRY_COUNT_MASK              (0x0FFF0000)
+#define MPI2_DPM_PGAD_ENTRY_COUNT_SHIFT             (16)
+#define MPI2_DPM_PGAD_START_ENTRY_MASK              (0x0000FFFF)
+
+
+/****************************************************************************
+*   Configuration messages
+****************************************************************************/
+
+/* Configuration Request Message */
+typedef struct _MPI2_CONFIG_REQUEST
+{
+    U8                      Action;                     /* 0x00 */
+    U8                      SGLFlags;                   /* 0x01 */
+    U8                      ChainOffset;                /* 0x02 */
+    U8                      Function;                   /* 0x03 */
+    U16                     ExtPageLength;              /* 0x04 */
+    U8                      ExtPageType;                /* 0x06 */
+    U8                      MsgFlags;                   /* 0x07 */
+    U8                      VP_ID;                      /* 0x08 */
+    U8                      VF_ID;                      /* 0x09 */
+    U16                     Reserved1;                  /* 0x0A */
+    U32                     Reserved2;                  /* 0x0C */
+    U32                     Reserved3;                  /* 0x10 */
+    MPI2_CONFIG_PAGE_HEADER Header;                     /* 0x14 */
+    U32                     PageAddress;                /* 0x18 */
+    MPI2_SGE_IO_UNION       PageBufferSGE;              /* 0x1C */
+} MPI2_CONFIG_REQUEST, MPI2_POINTER PTR_MPI2_CONFIG_REQUEST,
+  Mpi2ConfigRequest_t, MPI2_POINTER pMpi2ConfigRequest_t;
+
+/* values for the Action field */
+#define MPI2_CONFIG_ACTION_PAGE_HEADER              (0x00)
+#define MPI2_CONFIG_ACTION_PAGE_READ_CURRENT        (0x01)
+#define MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT       (0x02)
+#define MPI2_CONFIG_ACTION_PAGE_DEFAULT             (0x03)
+#define MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM         (0x04)
+#define MPI2_CONFIG_ACTION_PAGE_READ_DEFAULT        (0x05)
+#define MPI2_CONFIG_ACTION_PAGE_READ_NVRAM          (0x06)
+#define MPI2_CONFIG_ACTION_PAGE_GET_CHANGEABLE      (0x07)
+
+/* values for SGLFlags field are in the SGL section of mpi2.h */
+
+
+/* Config Reply Message */
+typedef struct _MPI2_CONFIG_REPLY
+{
+    U8                      Action;                     /* 0x00 */
+    U8                      SGLFlags;                   /* 0x01 */
+    U8                      MsgLength;                  /* 0x02 */
+    U8                      Function;                   /* 0x03 */
+    U16                     ExtPageLength;              /* 0x04 */
+    U8                      ExtPageType;                /* 0x06 */
+    U8                      MsgFlags;                   /* 0x07 */
+    U8                      VP_ID;                      /* 0x08 */
+    U8                      VF_ID;                      /* 0x09 */
+    U16                     Reserved1;                  /* 0x0A */
+    U16                     Reserved2;                  /* 0x0C */
+    U16                     IOCStatus;                  /* 0x0E */
+    U32                     IOCLogInfo;                 /* 0x10 */
+    MPI2_CONFIG_PAGE_HEADER Header;                     /* 0x14 */
+} MPI2_CONFIG_REPLY, MPI2_POINTER PTR_MPI2_CONFIG_REPLY,
+  Mpi2ConfigReply_t, MPI2_POINTER pMpi2ConfigReply_t;
+
+
+
+/*****************************************************************************
+*
+*               C o n f i g u r a t i o n    P a g e s
+*
+*****************************************************************************/
+
+/****************************************************************************
+*   Manufacturing Config pages
+****************************************************************************/
+
+#define MPI2_MFGPAGE_VENDORID_LSI                   (0x1000)
+
+/* SAS */
+#define MPI2_MFGPAGE_DEVID_SAS2004                  (0x0070)
+#define MPI2_MFGPAGE_DEVID_SAS2008                  (0x0072)
+#define MPI2_MFGPAGE_DEVID_SAS2108_1                (0x0074)
+#define MPI2_MFGPAGE_DEVID_SAS2108_2                (0x0076)
+#define MPI2_MFGPAGE_DEVID_SAS2108_3                (0x0077)
+#define MPI2_MFGPAGE_DEVID_SAS2116_1                (0x0064)
+#define MPI2_MFGPAGE_DEVID_SAS2116_2                (0x0065)
+
+
+/* Manufacturing Page 0 */
+
+typedef struct _MPI2_CONFIG_PAGE_MAN_0
+{
+    MPI2_CONFIG_PAGE_HEADER Header;                     /* 0x00 */
+    U8                      ChipName[16];               /* 0x04 */
+    U8                      ChipRevision[8];            /* 0x14 */
+    U8                      BoardName[16];              /* 0x1C */
+    U8                      BoardAssembly[16];          /* 0x2C */
+    U8                      BoardTracerNumber[16];      /* 0x3C */
+} MPI2_CONFIG_PAGE_MAN_0,
+  MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_0,
+  Mpi2ManufacturingPage0_t, MPI2_POINTER pMpi2ManufacturingPage0_t;
+
+#define MPI2_MANUFACTURING0_PAGEVERSION                (0x00)
+
+
+/* Manufacturing Page 1 */
+
+typedef struct _MPI2_CONFIG_PAGE_MAN_1
+{
+    MPI2_CONFIG_PAGE_HEADER Header;                     /* 0x00 */
+    U8                      VPD[256];                   /* 0x04 */
+} MPI2_CONFIG_PAGE_MAN_1,
+  MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_1,
+  Mpi2ManufacturingPage1_t, MPI2_POINTER pMpi2ManufacturingPage1_t;
+
+#define MPI2_MANUFACTURING1_PAGEVERSION                (0x00)
+
+
+typedef struct _MPI2_CHIP_REVISION_ID
+{
+    U16 DeviceID;                                       /* 0x00 */
+    U8  PCIRevisionID;                                  /* 0x02 */
+    U8  Reserved;                                       /* 0x03 */
+} MPI2_CHIP_REVISION_ID, MPI2_POINTER PTR_MPI2_CHIP_REVISION_ID,
+  Mpi2ChipRevisionId_t, MPI2_POINTER pMpi2ChipRevisionId_t;
+
+
+/* Manufacturing Page 2 */
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check Header.PageLength at runtime.
+ */
+#ifndef MPI2_MAN_PAGE_2_HW_SETTINGS_WORDS
+#define MPI2_MAN_PAGE_2_HW_SETTINGS_WORDS   (1)
+#endif
+
+typedef struct _MPI2_CONFIG_PAGE_MAN_2
+{
+    MPI2_CONFIG_PAGE_HEADER Header;                     /* 0x00 */
+    MPI2_CHIP_REVISION_ID   ChipId;                     /* 0x04 */
+    U32                     HwSettings[MPI2_MAN_PAGE_2_HW_SETTINGS_WORDS];/* 0x08 */
+} MPI2_CONFIG_PAGE_MAN_2,
+  MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_2,
+  Mpi2ManufacturingPage2_t, MPI2_POINTER pMpi2ManufacturingPage2_t;
+
+#define MPI2_MANUFACTURING2_PAGEVERSION                 (0x00)
+
+
+/* Manufacturing Page 3 */
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check Header.PageLength at runtime.
+ */
+#ifndef MPI2_MAN_PAGE_3_INFO_WORDS
+#define MPI2_MAN_PAGE_3_INFO_WORDS          (1)
+#endif
+
+typedef struct _MPI2_CONFIG_PAGE_MAN_3
+{
+    MPI2_CONFIG_PAGE_HEADER             Header;         /* 0x00 */
+    MPI2_CHIP_REVISION_ID               ChipId;         /* 0x04 */
+    U32                                 Info[MPI2_MAN_PAGE_3_INFO_WORDS];/* 0x08 */
+} MPI2_CONFIG_PAGE_MAN_3,
+  MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_3,
+  Mpi2ManufacturingPage3_t, MPI2_POINTER pMpi2ManufacturingPage3_t;
+
+#define MPI2_MANUFACTURING3_PAGEVERSION                 (0x00)
+
+
+/* Manufacturing Page 4 */
+
+typedef struct _MPI2_MANPAGE4_PWR_SAVE_SETTINGS
+{
+    U8                          PowerSaveFlags;                 /* 0x00 */
+    U8                          InternalOperationsSleepTime;    /* 0x01 */
+    U8                          InternalOperationsRunTime;      /* 0x02 */
+    U8                          HostIdleTime;                   /* 0x03 */
+} MPI2_MANPAGE4_PWR_SAVE_SETTINGS,
+  MPI2_POINTER PTR_MPI2_MANPAGE4_PWR_SAVE_SETTINGS,
+  Mpi2ManPage4PwrSaveSettings_t, MPI2_POINTER pMpi2ManPage4PwrSaveSettings_t;
+
+/* defines for the PowerSaveFlags field */
+#define MPI2_MANPAGE4_MASK_POWERSAVE_MODE               (0x03)
+#define MPI2_MANPAGE4_POWERSAVE_MODE_DISABLED           (0x00)
+#define MPI2_MANPAGE4_CUSTOM_POWERSAVE_MODE             (0x01)
+#define MPI2_MANPAGE4_FULL_POWERSAVE_MODE               (0x02)
+
+typedef struct _MPI2_CONFIG_PAGE_MAN_4
+{
+    MPI2_CONFIG_PAGE_HEADER             Header;                 /* 0x00 */
+    U32                                 Reserved1;              /* 0x04 */
+    U32                                 Flags;                  /* 0x08 */
+    U8                                  InquirySize;            /* 0x0C */
+    U8                                  Reserved2;              /* 0x0D */
+    U16                                 Reserved3;              /* 0x0E */
+    U8                                  InquiryData[56];        /* 0x10 */
+    U32                                 RAID0VolumeSettings;    /* 0x48 */
+    U32                                 RAID1EVolumeSettings;   /* 0x4C */
+    U32                                 RAID1VolumeSettings;    /* 0x50 */
+    U32                                 RAID10VolumeSettings;   /* 0x54 */
+    U32                                 Reserved4;              /* 0x58 */
+    U32                                 Reserved5;              /* 0x5C */
+    MPI2_MANPAGE4_PWR_SAVE_SETTINGS     PowerSaveSettings;      /* 0x60 */
+    U8                                  MaxOCEDisks;            /* 0x64 */
+    U8                                  ResyncRate;             /* 0x65 */
+    U16                                 DataScrubDuration;      /* 0x66 */
+    U8                                  MaxHotSpares;           /* 0x68 */
+    U8                                  MaxPhysDisksPerVol;     /* 0x69 */
+    U8                                  MaxPhysDisks;           /* 0x6A */
+    U8                                  MaxVolumes;             /* 0x6B */
+} MPI2_CONFIG_PAGE_MAN_4,
+  MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_4,
+  Mpi2ManufacturingPage4_t, MPI2_POINTER pMpi2ManufacturingPage4_t;
+
+#define MPI2_MANUFACTURING4_PAGEVERSION                 (0x0A)
+
+/* Manufacturing Page 4 Flags field */
+#define MPI2_MANPAGE4_METADATA_SIZE_MASK                (0x00030000)
+#define MPI2_MANPAGE4_METADATA_512MB                    (0x00000000)
+
+#define MPI2_MANPAGE4_MIX_SSD_SAS_SATA                  (0x00008000)
+#define MPI2_MANPAGE4_MIX_SSD_AND_NON_SSD               (0x00004000)
+#define MPI2_MANPAGE4_HIDE_PHYSDISK_NON_IR              (0x00002000)
+
+#define MPI2_MANPAGE4_MASK_PHYSDISK_COERCION            (0x00001C00)
+#define MPI2_MANPAGE4_PHYSDISK_COERCION_1GB             (0x00000000)
+#define MPI2_MANPAGE4_PHYSDISK_128MB_COERCION           (0x00000400)
+#define MPI2_MANPAGE4_PHYSDISK_ADAPTIVE_COERCION        (0x00000800)
+#define MPI2_MANPAGE4_PHYSDISK_ZERO_COERCION            (0x00000C00)
+
+#define MPI2_MANPAGE4_MASK_BAD_BLOCK_MARKING            (0x00000300)
+#define MPI2_MANPAGE4_DEFAULT_BAD_BLOCK_MARKING         (0x00000000)
+#define MPI2_MANPAGE4_TABLE_BAD_BLOCK_MARKING           (0x00000100)
+#define MPI2_MANPAGE4_WRITE_LONG_BAD_BLOCK_MARKING      (0x00000200)
+
+#define MPI2_MANPAGE4_FORCE_OFFLINE_FAILOVER            (0x00000080)
+#define MPI2_MANPAGE4_RAID10_DISABLE                    (0x00000040)
+#define MPI2_MANPAGE4_RAID1E_DISABLE                    (0x00000020)
+#define MPI2_MANPAGE4_RAID1_DISABLE                     (0x00000010)
+#define MPI2_MANPAGE4_RAID0_DISABLE                     (0x00000008)
+#define MPI2_MANPAGE4_IR_MODEPAGE8_DISABLE              (0x00000004)
+#define MPI2_MANPAGE4_IM_RESYNC_CACHE_ENABLE            (0x00000002)
+#define MPI2_MANPAGE4_IR_NO_MIX_SAS_SATA                (0x00000001)
+
+
+/* Manufacturing Page 5 */
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check Header.PageLength or NumPhys at runtime.
+ */
+#ifndef MPI2_MAN_PAGE_5_PHY_ENTRIES
+#define MPI2_MAN_PAGE_5_PHY_ENTRIES         (1)
+#endif
+
+typedef struct _MPI2_MANUFACTURING5_ENTRY
+{
+    U64                                 WWID;           /* 0x00 */
+    U64                                 DeviceName;     /* 0x08 */
+} MPI2_MANUFACTURING5_ENTRY, MPI2_POINTER PTR_MPI2_MANUFACTURING5_ENTRY,
+  Mpi2Manufacturing5Entry_t, MPI2_POINTER pMpi2Manufacturing5Entry_t;
+
+typedef struct _MPI2_CONFIG_PAGE_MAN_5
+{
+    MPI2_CONFIG_PAGE_HEADER             Header;         /* 0x00 */
+    U8                                  NumPhys;        /* 0x04 */
+    U8                                  Reserved1;      /* 0x05 */
+    U16                                 Reserved2;      /* 0x06 */
+    U32                                 Reserved3;      /* 0x08 */
+    U32                                 Reserved4;      /* 0x0C */
+    MPI2_MANUFACTURING5_ENTRY           Phy[MPI2_MAN_PAGE_5_PHY_ENTRIES];/* 0x08 */
+} MPI2_CONFIG_PAGE_MAN_5,
+  MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_5,
+  Mpi2ManufacturingPage5_t, MPI2_POINTER pMpi2ManufacturingPage5_t;
+
+#define MPI2_MANUFACTURING5_PAGEVERSION                 (0x03)
+
+
+/* Manufacturing Page 6 */
+
+typedef struct _MPI2_CONFIG_PAGE_MAN_6
+{
+    MPI2_CONFIG_PAGE_HEADER         Header;             /* 0x00 */
+    U32                             ProductSpecificInfo;/* 0x04 */
+} MPI2_CONFIG_PAGE_MAN_6,
+  MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_6,
+  Mpi2ManufacturingPage6_t, MPI2_POINTER pMpi2ManufacturingPage6_t;
+
+#define MPI2_MANUFACTURING6_PAGEVERSION                 (0x00)
+
+
+/* Manufacturing Page 7 */
+
+typedef struct _MPI2_MANPAGE7_CONNECTOR_INFO
+{
+    U32                         Pinout;                 /* 0x00 */
+    U8                          Connector[16];          /* 0x04 */
+    U8                          Location;               /* 0x14 */
+    U8                          Reserved1;              /* 0x15 */
+    U16                         Slot;                   /* 0x16 */
+    U32                         Reserved2;              /* 0x18 */
+} MPI2_MANPAGE7_CONNECTOR_INFO, MPI2_POINTER PTR_MPI2_MANPAGE7_CONNECTOR_INFO,
+  Mpi2ManPage7ConnectorInfo_t, MPI2_POINTER pMpi2ManPage7ConnectorInfo_t;
+
+/* defines for the Pinout field */
+#define MPI2_MANPAGE7_PINOUT_SFF_8484_L4                (0x00080000)
+#define MPI2_MANPAGE7_PINOUT_SFF_8484_L3                (0x00040000)
+#define MPI2_MANPAGE7_PINOUT_SFF_8484_L2                (0x00020000)
+#define MPI2_MANPAGE7_PINOUT_SFF_8484_L1                (0x00010000)
+#define MPI2_MANPAGE7_PINOUT_SFF_8470_L4                (0x00000800)
+#define MPI2_MANPAGE7_PINOUT_SFF_8470_L3                (0x00000400)
+#define MPI2_MANPAGE7_PINOUT_SFF_8470_L2                (0x00000200)
+#define MPI2_MANPAGE7_PINOUT_SFF_8470_L1                (0x00000100)
+#define MPI2_MANPAGE7_PINOUT_SFF_8482                   (0x00000002)
+#define MPI2_MANPAGE7_PINOUT_CONNECTION_UNKNOWN         (0x00000001)
+
+/* defines for the Location field */
+#define MPI2_MANPAGE7_LOCATION_UNKNOWN                  (0x01)
+#define MPI2_MANPAGE7_LOCATION_INTERNAL                 (0x02)
+#define MPI2_MANPAGE7_LOCATION_EXTERNAL                 (0x04)
+#define MPI2_MANPAGE7_LOCATION_SWITCHABLE               (0x08)
+#define MPI2_MANPAGE7_LOCATION_AUTO                     (0x10)
+#define MPI2_MANPAGE7_LOCATION_NOT_PRESENT              (0x20)
+#define MPI2_MANPAGE7_LOCATION_NOT_CONNECTED            (0x80)
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check NumPhys at runtime.
+ */
+#ifndef MPI2_MANPAGE7_CONNECTOR_INFO_MAX
+#define MPI2_MANPAGE7_CONNECTOR_INFO_MAX  (1)
+#endif
+
+typedef struct _MPI2_CONFIG_PAGE_MAN_7
+{
+    MPI2_CONFIG_PAGE_HEADER         Header;             /* 0x00 */
+    U32                             Reserved1;          /* 0x04 */
+    U32                             Reserved2;          /* 0x08 */
+    U32                             Flags;              /* 0x0C */
+    U8                              EnclosureName[16];  /* 0x10 */
+    U8                              NumPhys;            /* 0x20 */
+    U8                              Reserved3;          /* 0x21 */
+    U16                             Reserved4;          /* 0x22 */
+    MPI2_MANPAGE7_CONNECTOR_INFO    ConnectorInfo[MPI2_MANPAGE7_CONNECTOR_INFO_MAX]; /* 0x24 */
+} MPI2_CONFIG_PAGE_MAN_7,
+  MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_7,
+  Mpi2ManufacturingPage7_t, MPI2_POINTER pMpi2ManufacturingPage7_t;
+
+#define MPI2_MANUFACTURING7_PAGEVERSION                 (0x00)
+
+/* defines for the Flags field */
+#define MPI2_MANPAGE7_FLAG_USE_SLOT_INFO                (0x00000001)
+
+
+/*
+ * Generic structure to use for product-specific manufacturing pages
+ * (currently Manufacturing Page 8 through Manufacturing Page 31).
+ */
+
+typedef struct _MPI2_CONFIG_PAGE_MAN_PS
+{
+    MPI2_CONFIG_PAGE_HEADER         Header;             /* 0x00 */
+    U32                             ProductSpecificInfo;/* 0x04 */
+} MPI2_CONFIG_PAGE_MAN_PS,
+  MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_PS,
+  Mpi2ManufacturingPagePS_t, MPI2_POINTER pMpi2ManufacturingPagePS_t;
+
+#define MPI2_MANUFACTURING8_PAGEVERSION                 (0x00)
+#define MPI2_MANUFACTURING9_PAGEVERSION                 (0x00)
+#define MPI2_MANUFACTURING10_PAGEVERSION                (0x00)
+#define MPI2_MANUFACTURING11_PAGEVERSION                (0x00)
+#define MPI2_MANUFACTURING12_PAGEVERSION                (0x00)
+#define MPI2_MANUFACTURING13_PAGEVERSION                (0x00)
+#define MPI2_MANUFACTURING14_PAGEVERSION                (0x00)
+#define MPI2_MANUFACTURING15_PAGEVERSION                (0x00)
+#define MPI2_MANUFACTURING16_PAGEVERSION                (0x00)
+#define MPI2_MANUFACTURING17_PAGEVERSION                (0x00)
+#define MPI2_MANUFACTURING18_PAGEVERSION                (0x00)
+#define MPI2_MANUFACTURING19_PAGEVERSION                (0x00)
+#define MPI2_MANUFACTURING20_PAGEVERSION                (0x00)
+#define MPI2_MANUFACTURING21_PAGEVERSION                (0x00)
+#define MPI2_MANUFACTURING22_PAGEVERSION                (0x00)
+#define MPI2_MANUFACTURING23_PAGEVERSION                (0x00)
+#define MPI2_MANUFACTURING24_PAGEVERSION                (0x00)
+#define MPI2_MANUFACTURING25_PAGEVERSION                (0x00)
+#define MPI2_MANUFACTURING26_PAGEVERSION                (0x00)
+#define MPI2_MANUFACTURING27_PAGEVERSION                (0x00)
+#define MPI2_MANUFACTURING28_PAGEVERSION                (0x00)
+#define MPI2_MANUFACTURING29_PAGEVERSION                (0x00)
+#define MPI2_MANUFACTURING30_PAGEVERSION                (0x00)
+#define MPI2_MANUFACTURING31_PAGEVERSION                (0x00)
+
+
+/****************************************************************************
+*   IO Unit Config Pages
+****************************************************************************/
+
+/* IO Unit Page 0 */
+
+typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_0
+{
+    MPI2_CONFIG_PAGE_HEADER Header;                     /* 0x00 */
+    U64                     UniqueValue;                /* 0x04 */
+    MPI2_VERSION_UNION      NvdataVersionDefault;       /* 0x08 */
+    MPI2_VERSION_UNION      NvdataVersionPersistent;    /* 0x0A */
+} MPI2_CONFIG_PAGE_IO_UNIT_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_0,
+  Mpi2IOUnitPage0_t, MPI2_POINTER pMpi2IOUnitPage0_t;
+
+#define MPI2_IOUNITPAGE0_PAGEVERSION                    (0x02)
+
+
+/* IO Unit Page 1 */
+
+typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_1
+{
+    MPI2_CONFIG_PAGE_HEADER Header;                     /* 0x00 */
+    U32                     Flags;                      /* 0x04 */
+} MPI2_CONFIG_PAGE_IO_UNIT_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_1,
+  Mpi2IOUnitPage1_t, MPI2_POINTER pMpi2IOUnitPage1_t;
+
+#define MPI2_IOUNITPAGE1_PAGEVERSION                    (0x04)
+
+/* IO Unit Page 1 Flags defines */
+#define MPI2_IOUNITPAGE1_MASK_SATA_WRITE_CACHE          (0x00000600)
+#define MPI2_IOUNITPAGE1_ENABLE_SATA_WRITE_CACHE        (0x00000000)
+#define MPI2_IOUNITPAGE1_DISABLE_SATA_WRITE_CACHE       (0x00000200)
+#define MPI2_IOUNITPAGE1_UNCHANGED_SATA_WRITE_CACHE     (0x00000400)
+#define MPI2_IOUNITPAGE1_NATIVE_COMMAND_Q_DISABLE       (0x00000100)
+#define MPI2_IOUNITPAGE1_DISABLE_IR                     (0x00000040)
+#define MPI2_IOUNITPAGE1_DISABLE_TASK_SET_FULL_HANDLING (0x00000020)
+#define MPI2_IOUNITPAGE1_IR_USE_STATIC_VOLUME_ID        (0x00000004)
+#define MPI2_IOUNITPAGE1_MULTI_PATHING                  (0x00000002)
+#define MPI2_IOUNITPAGE1_SINGLE_PATHING                 (0x00000000)
+
+
+/* IO Unit Page 3 */
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check Header.PageLength at runtime.
+ */
+#ifndef MPI2_IO_UNIT_PAGE_3_GPIO_VAL_MAX
+#define MPI2_IO_UNIT_PAGE_3_GPIO_VAL_MAX    (1)
+#endif
+
+typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_3
+{
+    MPI2_CONFIG_PAGE_HEADER Header;                                   /* 0x00 */
+    U8                      GPIOCount;                                /* 0x04 */
+    U8                      Reserved1;                                /* 0x05 */
+    U16                     Reserved2;                                /* 0x06 */
+    U16                     GPIOVal[MPI2_IO_UNIT_PAGE_3_GPIO_VAL_MAX];/* 0x08 */
+} MPI2_CONFIG_PAGE_IO_UNIT_3, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_3,
+  Mpi2IOUnitPage3_t, MPI2_POINTER pMpi2IOUnitPage3_t;
+
+#define MPI2_IOUNITPAGE3_PAGEVERSION                    (0x01)
+
+/* defines for IO Unit Page 3 GPIOVal field */
+#define MPI2_IOUNITPAGE3_GPIO_FUNCTION_MASK             (0xFFFC)
+#define MPI2_IOUNITPAGE3_GPIO_FUNCTION_SHIFT            (2)
+#define MPI2_IOUNITPAGE3_GPIO_SETTING_OFF               (0x0000)
+#define MPI2_IOUNITPAGE3_GPIO_SETTING_ON                (0x0001)
+
+
+/****************************************************************************
+*   IOC Config Pages
+****************************************************************************/
+
+/* IOC Page 0 */
+
+typedef struct _MPI2_CONFIG_PAGE_IOC_0
+{
+    MPI2_CONFIG_PAGE_HEADER Header;                     /* 0x00 */
+    U32                     Reserved1;                  /* 0x04 */
+    U32                     Reserved2;                  /* 0x08 */
+    U16                     VendorID;                   /* 0x0C */
+    U16                     DeviceID;                   /* 0x0E */
+    U8                      RevisionID;                 /* 0x10 */
+    U8                      Reserved3;                  /* 0x11 */
+    U16                     Reserved4;                  /* 0x12 */
+    U32                     ClassCode;                  /* 0x14 */
+    U16                     SubsystemVendorID;          /* 0x18 */
+    U16                     SubsystemID;                /* 0x1A */
+} MPI2_CONFIG_PAGE_IOC_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IOC_0,
+  Mpi2IOCPage0_t, MPI2_POINTER pMpi2IOCPage0_t;
+
+#define MPI2_IOCPAGE0_PAGEVERSION                       (0x02)
+
+
+/* IOC Page 1 */
+
+typedef struct _MPI2_CONFIG_PAGE_IOC_1
+{
+    MPI2_CONFIG_PAGE_HEADER Header;                     /* 0x00 */
+    U32                     Flags;                      /* 0x04 */
+    U32                     CoalescingTimeout;          /* 0x08 */
+    U8                      CoalescingDepth;            /* 0x0C */
+    U8                      PCISlotNum;                 /* 0x0D */
+    U8                      PCIBusNum;                  /* 0x0E */
+    U8                      PCIDomainSegment;           /* 0x0F */
+    U32                     Reserved1;                  /* 0x10 */
+    U32                     Reserved2;                  /* 0x14 */
+} MPI2_CONFIG_PAGE_IOC_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IOC_1,
+  Mpi2IOCPage1_t, MPI2_POINTER pMpi2IOCPage1_t;
+
+#define MPI2_IOCPAGE1_PAGEVERSION                       (0x05)
+
+/* defines for IOC Page 1 Flags field */
+#define MPI2_IOCPAGE1_REPLY_COALESCING                  (0x00000001)
+
+#define MPI2_IOCPAGE1_PCISLOTNUM_UNKNOWN                (0xFF)
+#define MPI2_IOCPAGE1_PCIBUSNUM_UNKNOWN                 (0xFF)
+#define MPI2_IOCPAGE1_PCIDOMAIN_UNKNOWN                 (0xFF)
+
+/* IOC Page 6 */
+
+typedef struct _MPI2_CONFIG_PAGE_IOC_6
+{
+    MPI2_CONFIG_PAGE_HEADER Header;                         /* 0x00 */
+    U32                     CapabilitiesFlags;              /* 0x04 */
+    U8                      MaxDrivesRAID0;                 /* 0x08 */
+    U8                      MaxDrivesRAID1;                 /* 0x09 */
+    U8                      MaxDrivesRAID1E;                /* 0x0A */
+    U8                      MaxDrivesRAID10;                /* 0x0B */
+    U8                      MinDrivesRAID0;                 /* 0x0C */
+    U8                      MinDrivesRAID1;                 /* 0x0D */
+    U8                      MinDrivesRAID1E;                /* 0x0E */
+    U8                      MinDrivesRAID10;                /* 0x0F */
+    U32                     Reserved1;                      /* 0x10 */
+    U8                      MaxGlobalHotSpares;             /* 0x14 */
+    U8                      MaxPhysDisks;                   /* 0x15 */
+    U8                      MaxVolumes;                     /* 0x16 */
+    U8                      MaxConfigs;                     /* 0x17 */
+    U8                      MaxOCEDisks;                    /* 0x18 */
+    U8                      Reserved2;                      /* 0x19 */
+    U16                     Reserved3;                      /* 0x1A */
+    U32                     SupportedStripeSizeMapRAID0;    /* 0x1C */
+    U32                     SupportedStripeSizeMapRAID1E;   /* 0x20 */
+    U32                     SupportedStripeSizeMapRAID10;   /* 0x24 */
+    U32                     Reserved4;                      /* 0x28 */
+    U32                     Reserved5;                      /* 0x2C */
+    U16                     DefaultMetadataSize;            /* 0x30 */
+    U16                     Reserved6;                      /* 0x32 */
+    U16                     MaxBadBlockTableEntries;        /* 0x34 */
+    U16                     Reserved7;                      /* 0x36 */
+    U32                     IRNvsramVersion;                /* 0x38 */
+} MPI2_CONFIG_PAGE_IOC_6, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IOC_6,
+  Mpi2IOCPage6_t, MPI2_POINTER pMpi2IOCPage6_t;
+
+#define MPI2_IOCPAGE6_PAGEVERSION                       (0x04)
+
+/* defines for IOC Page 6 CapabilitiesFlags */
+#define MPI2_IOCPAGE6_CAP_FLAGS_RAID10_SUPPORT          (0x00000010)
+#define MPI2_IOCPAGE6_CAP_FLAGS_RAID1_SUPPORT           (0x00000008)
+#define MPI2_IOCPAGE6_CAP_FLAGS_RAID1E_SUPPORT          (0x00000004)
+#define MPI2_IOCPAGE6_CAP_FLAGS_RAID0_SUPPORT           (0x00000002)
+#define MPI2_IOCPAGE6_CAP_FLAGS_GLOBAL_HOT_SPARE        (0x00000001)
+
+
+/* IOC Page 7 */
+
+#define MPI2_IOCPAGE7_EVENTMASK_WORDS       (4)
+
+typedef struct _MPI2_CONFIG_PAGE_IOC_7
+{
+    MPI2_CONFIG_PAGE_HEADER Header;                     /* 0x00 */
+    U32                     Reserved1;                  /* 0x04 */
+    U32                     EventMasks[MPI2_IOCPAGE7_EVENTMASK_WORDS];/* 0x08 */
+    U16                     SASBroadcastPrimitiveMasks; /* 0x18 */
+    U16                     Reserved2;                  /* 0x1A */
+    U32                     Reserved3;                  /* 0x1C */
+} MPI2_CONFIG_PAGE_IOC_7, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IOC_7,
+  Mpi2IOCPage7_t, MPI2_POINTER pMpi2IOCPage7_t;
+
+#define MPI2_IOCPAGE7_PAGEVERSION                       (0x01)
+
+
+/* IOC Page 8 */
+
+typedef struct _MPI2_CONFIG_PAGE_IOC_8
+{
+    MPI2_CONFIG_PAGE_HEADER Header;                     /* 0x00 */
+    U8                      NumDevsPerEnclosure;        /* 0x04 */
+    U8                      Reserved1;                  /* 0x05 */
+    U16                     Reserved2;                  /* 0x06 */
+    U16                     MaxPersistentEntries;       /* 0x08 */
+    U16                     MaxNumPhysicalMappedIDs;    /* 0x0A */
+    U16                     Flags;                      /* 0x0C */
+    U16                     Reserved3;                  /* 0x0E */
+    U16                     IRVolumeMappingFlags;       /* 0x10 */
+    U16                     Reserved4;                  /* 0x12 */
+    U32                     Reserved5;                  /* 0x14 */
+} MPI2_CONFIG_PAGE_IOC_8, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IOC_8,
+  Mpi2IOCPage8_t, MPI2_POINTER pMpi2IOCPage8_t;
+
+#define MPI2_IOCPAGE8_PAGEVERSION                       (0x00)
+
+/* defines for IOC Page 8 Flags field */
+#define MPI2_IOCPAGE8_FLAGS_DA_START_SLOT_1             (0x00000020)
+#define MPI2_IOCPAGE8_FLAGS_RESERVED_TARGETID_0         (0x00000010)
+
+#define MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE           (0x0000000E)
+#define MPI2_IOCPAGE8_FLAGS_DEVICE_PERSISTENCE_MAPPING  (0x00000000)
+#define MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING      (0x00000002)
+
+#define MPI2_IOCPAGE8_FLAGS_DISABLE_PERSISTENT_MAPPING  (0x00000001)
+#define MPI2_IOCPAGE8_FLAGS_ENABLE_PERSISTENT_MAPPING   (0x00000000)
+
+/* defines for IOC Page 8 IRVolumeMappingFlags */
+#define MPI2_IOCPAGE8_IRFLAGS_MASK_VOLUME_MAPPING_MODE  (0x00000003)
+#define MPI2_IOCPAGE8_IRFLAGS_LOW_VOLUME_MAPPING        (0x00000000)
+#define MPI2_IOCPAGE8_IRFLAGS_HIGH_VOLUME_MAPPING       (0x00000001)
+
+
+/****************************************************************************
+*   BIOS Config Pages
+****************************************************************************/
+
+/* BIOS Page 1 */
+
+typedef struct _MPI2_CONFIG_PAGE_BIOS_1
+{
+    MPI2_CONFIG_PAGE_HEADER Header;                     /* 0x00 */
+    U32                     BiosOptions;                /* 0x04 */
+    U32                     IOCSettings;                /* 0x08 */
+    U32                     Reserved1;                  /* 0x0C */
+    U32                     DeviceSettings;             /* 0x10 */
+    U16                     NumberOfDevices;            /* 0x14 */
+    U16                     Reserved2;                  /* 0x16 */
+    U16                     IOTimeoutBlockDevicesNonRM; /* 0x18 */
+    U16                     IOTimeoutSequential;        /* 0x1A */
+    U16                     IOTimeoutOther;             /* 0x1C */
+    U16                     IOTimeoutBlockDevicesRM;    /* 0x1E */
+} MPI2_CONFIG_PAGE_BIOS_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_BIOS_1,
+  Mpi2BiosPage1_t, MPI2_POINTER pMpi2BiosPage1_t;
+
+#define MPI2_BIOSPAGE1_PAGEVERSION                      (0x04)
+
+/* values for BIOS Page 1 BiosOptions field */
+#define MPI2_BIOSPAGE1_OPTIONS_DISABLE_BIOS             (0x00000001)
+
+/* values for BIOS Page 1 IOCSettings field */
+#define MPI2_BIOSPAGE1_IOCSET_MASK_BOOT_PREFERENCE      (0x00030000)
+#define MPI2_BIOSPAGE1_IOCSET_ENCLOSURE_SLOT_BOOT       (0x00000000)
+#define MPI2_BIOSPAGE1_IOCSET_SAS_ADDRESS_BOOT          (0x00010000)
+
+#define MPI2_BIOSPAGE1_IOCSET_MASK_RM_SETTING           (0x000000C0)
+#define MPI2_BIOSPAGE1_IOCSET_NONE_RM_SETTING           (0x00000000)
+#define MPI2_BIOSPAGE1_IOCSET_BOOT_RM_SETTING           (0x00000040)
+#define MPI2_BIOSPAGE1_IOCSET_MEDIA_RM_SETTING          (0x00000080)
+
+#define MPI2_BIOSPAGE1_IOCSET_MASK_ADAPTER_SUPPORT      (0x00000030)
+#define MPI2_BIOSPAGE1_IOCSET_NO_SUPPORT                (0x00000000)
+#define MPI2_BIOSPAGE1_IOCSET_BIOS_SUPPORT              (0x00000010)
+#define MPI2_BIOSPAGE1_IOCSET_OS_SUPPORT                (0x00000020)
+#define MPI2_BIOSPAGE1_IOCSET_ALL_SUPPORT               (0x00000030)
+
+#define MPI2_BIOSPAGE1_IOCSET_ALTERNATE_CHS             (0x00000008)
+
+/* values for BIOS Page 1 DeviceSettings field */
+#define MPI2_BIOSPAGE1_DEVSET_DISABLE_SMART_POLLING     (0x00000010)
+#define MPI2_BIOSPAGE1_DEVSET_DISABLE_SEQ_LUN           (0x00000008)
+#define MPI2_BIOSPAGE1_DEVSET_DISABLE_RM_LUN            (0x00000004)
+#define MPI2_BIOSPAGE1_DEVSET_DISABLE_NON_RM_LUN        (0x00000002)
+#define MPI2_BIOSPAGE1_DEVSET_DISABLE_OTHER_LUN         (0x00000001)
+
+
+/* BIOS Page 2 */
+
+typedef struct _MPI2_BOOT_DEVICE_ADAPTER_ORDER
+{
+    U32         Reserved1;                              /* 0x00 */
+    U32         Reserved2;                              /* 0x04 */
+    U32         Reserved3;                              /* 0x08 */
+    U32         Reserved4;                              /* 0x0C */
+    U32         Reserved5;                              /* 0x10 */
+    U32         Reserved6;                              /* 0x14 */
+} MPI2_BOOT_DEVICE_ADAPTER_ORDER,
+  MPI2_POINTER PTR_MPI2_BOOT_DEVICE_ADAPTER_ORDER,
+  Mpi2BootDeviceAdapterOrder_t, MPI2_POINTER pMpi2BootDeviceAdapterOrder_t;
+
+typedef struct _MPI2_BOOT_DEVICE_SAS_WWID
+{
+    U64         SASAddress;                             /* 0x00 */
+    U8          LUN[8];                                 /* 0x08 */
+    U32         Reserved1;                              /* 0x10 */
+    U32         Reserved2;                              /* 0x14 */
+} MPI2_BOOT_DEVICE_SAS_WWID, MPI2_POINTER PTR_MPI2_BOOT_DEVICE_SAS_WWID,
+  Mpi2BootDeviceSasWwid_t, MPI2_POINTER pMpi2BootDeviceSasWwid_t;
+
+typedef struct _MPI2_BOOT_DEVICE_ENCLOSURE_SLOT
+{
+    U64         EnclosureLogicalID;                     /* 0x00 */
+    U32         Reserved1;                              /* 0x08 */
+    U32         Reserved2;                              /* 0x0C */
+    U16         SlotNumber;                             /* 0x10 */
+    U16         Reserved3;                              /* 0x12 */
+    U32         Reserved4;                              /* 0x14 */
+} MPI2_BOOT_DEVICE_ENCLOSURE_SLOT,
+  MPI2_POINTER PTR_MPI2_BOOT_DEVICE_ENCLOSURE_SLOT,
+  Mpi2BootDeviceEnclosureSlot_t, MPI2_POINTER pMpi2BootDeviceEnclosureSlot_t;
+
+typedef struct _MPI2_BOOT_DEVICE_DEVICE_NAME
+{
+    U64         DeviceName;                             /* 0x00 */
+    U8          LUN[8];                                 /* 0x08 */
+    U32         Reserved1;                              /* 0x10 */
+    U32         Reserved2;                              /* 0x14 */
+} MPI2_BOOT_DEVICE_DEVICE_NAME, MPI2_POINTER PTR_MPI2_BOOT_DEVICE_DEVICE_NAME,
+  Mpi2BootDeviceDeviceName_t, MPI2_POINTER pMpi2BootDeviceDeviceName_t;
+
+typedef union _MPI2_MPI2_BIOSPAGE2_BOOT_DEVICE
+{
+    MPI2_BOOT_DEVICE_ADAPTER_ORDER  AdapterOrder;
+    MPI2_BOOT_DEVICE_SAS_WWID       SasWwid;
+    MPI2_BOOT_DEVICE_ENCLOSURE_SLOT EnclosureSlot;
+    MPI2_BOOT_DEVICE_DEVICE_NAME    DeviceName;
+} MPI2_BIOSPAGE2_BOOT_DEVICE, MPI2_POINTER PTR_MPI2_BIOSPAGE2_BOOT_DEVICE,
+  Mpi2BiosPage2BootDevice_t, MPI2_POINTER pMpi2BiosPage2BootDevice_t;
+
+typedef struct _MPI2_CONFIG_PAGE_BIOS_2
+{
+    MPI2_CONFIG_PAGE_HEADER     Header;                 /* 0x00 */
+    U32                         Reserved1;              /* 0x04 */
+    U32                         Reserved2;              /* 0x08 */
+    U32                         Reserved3;              /* 0x0C */
+    U32                         Reserved4;              /* 0x10 */
+    U32                         Reserved5;              /* 0x14 */
+    U32                         Reserved6;              /* 0x18 */
+    U8                          ReqBootDeviceForm;      /* 0x1C */
+    U8                          Reserved7;              /* 0x1D */
+    U16                         Reserved8;              /* 0x1E */
+    MPI2_BIOSPAGE2_BOOT_DEVICE  RequestedBootDevice;    /* 0x20 */
+    U8                          ReqAltBootDeviceForm;   /* 0x38 */
+    U8                          Reserved9;              /* 0x39 */
+    U16                         Reserved10;             /* 0x3A */
+    MPI2_BIOSPAGE2_BOOT_DEVICE  RequestedAltBootDevice; /* 0x3C */
+    U8                          CurrentBootDeviceForm;  /* 0x58 */
+    U8                          Reserved11;             /* 0x59 */
+    U16                         Reserved12;             /* 0x5A */
+    MPI2_BIOSPAGE2_BOOT_DEVICE  CurrentBootDevice;      /* 0x58 */
+} MPI2_CONFIG_PAGE_BIOS_2, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_BIOS_2,
+  Mpi2BiosPage2_t, MPI2_POINTER pMpi2BiosPage2_t;
+
+#define MPI2_BIOSPAGE2_PAGEVERSION                      (0x04)
+
+/* values for BIOS Page 2 BootDeviceForm fields */
+#define MPI2_BIOSPAGE2_FORM_MASK                        (0x0F)
+#define MPI2_BIOSPAGE2_FORM_NO_DEVICE_SPECIFIED         (0x00)
+#define MPI2_BIOSPAGE2_FORM_SAS_WWID                    (0x05)
+#define MPI2_BIOSPAGE2_FORM_ENCLOSURE_SLOT              (0x06)
+#define MPI2_BIOSPAGE2_FORM_DEVICE_NAME                 (0x07)
+
+
+/* BIOS Page 3 */
+
+typedef struct _MPI2_ADAPTER_INFO
+{
+    U8      PciBusNumber;                               /* 0x00 */
+    U8      PciDeviceAndFunctionNumber;                 /* 0x01 */
+    U16     AdapterFlags;                               /* 0x02 */
+} MPI2_ADAPTER_INFO, MPI2_POINTER PTR_MPI2_ADAPTER_INFO,
+  Mpi2AdapterInfo_t, MPI2_POINTER pMpi2AdapterInfo_t;
+
+#define MPI2_ADAPTER_INFO_FLAGS_EMBEDDED                (0x0001)
+#define MPI2_ADAPTER_INFO_FLAGS_INIT_STATUS             (0x0002)
+
+typedef struct _MPI2_CONFIG_PAGE_BIOS_3
+{
+    MPI2_CONFIG_PAGE_HEADER Header;                     /* 0x00 */
+    U32                     GlobalFlags;                /* 0x04 */
+    U32                     BiosVersion;                /* 0x08 */
+    MPI2_ADAPTER_INFO       AdapterOrder[4];            /* 0x0C */
+    U32                     Reserved1;                  /* 0x1C */
+} MPI2_CONFIG_PAGE_BIOS_3, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_BIOS_3,
+  Mpi2BiosPage3_t, MPI2_POINTER pMpi2BiosPage3_t;
+
+#define MPI2_BIOSPAGE3_PAGEVERSION                      (0x00)
+
+/* values for BIOS Page 3 GlobalFlags */
+#define MPI2_BIOSPAGE3_FLAGS_PAUSE_ON_ERROR             (0x00000002)
+#define MPI2_BIOSPAGE3_FLAGS_VERBOSE_ENABLE             (0x00000004)
+#define MPI2_BIOSPAGE3_FLAGS_HOOK_INT_40_DISABLE        (0x00000010)
+
+#define MPI2_BIOSPAGE3_FLAGS_DEV_LIST_DISPLAY_MASK      (0x000000E0)
+#define MPI2_BIOSPAGE3_FLAGS_INSTALLED_DEV_DISPLAY      (0x00000000)
+#define MPI2_BIOSPAGE3_FLAGS_ADAPTER_DISPLAY            (0x00000020)
+#define MPI2_BIOSPAGE3_FLAGS_ADAPTER_DEV_DISPLAY        (0x00000040)
+
+
+/* BIOS Page 4 */
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check Header.PageLength or NumPhys at runtime.
+ */
+#ifndef MPI2_BIOS_PAGE_4_PHY_ENTRIES
+#define MPI2_BIOS_PAGE_4_PHY_ENTRIES        (1)
+#endif
+
+typedef struct _MPI2_BIOS4_ENTRY
+{
+    U64                     ReassignmentWWID;       /* 0x00 */
+    U64                     ReassignmentDeviceName; /* 0x08 */
+} MPI2_BIOS4_ENTRY, MPI2_POINTER PTR_MPI2_BIOS4_ENTRY,
+  Mpi2MBios4Entry_t, MPI2_POINTER pMpi2Bios4Entry_t;
+
+typedef struct _MPI2_CONFIG_PAGE_BIOS_4
+{
+    MPI2_CONFIG_PAGE_HEADER Header;                             /* 0x00 */
+    U8                      NumPhys;                            /* 0x04 */
+    U8                      Reserved1;                          /* 0x05 */
+    U16                     Reserved2;                          /* 0x06 */
+    MPI2_BIOS4_ENTRY        Phy[MPI2_BIOS_PAGE_4_PHY_ENTRIES];  /* 0x08 */
+} MPI2_CONFIG_PAGE_BIOS_4, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_BIOS_4,
+  Mpi2BiosPage4_t, MPI2_POINTER pMpi2BiosPage4_t;
+
+#define MPI2_BIOSPAGE4_PAGEVERSION                      (0x01)
+
+
+/****************************************************************************
+*   RAID Volume Config Pages
+****************************************************************************/
+
+/* RAID Volume Page 0 */
+
+typedef struct _MPI2_RAIDVOL0_PHYS_DISK
+{
+    U8                      RAIDSetNum;                 /* 0x00 */
+    U8                      PhysDiskMap;                /* 0x01 */
+    U8                      PhysDiskNum;                /* 0x02 */
+    U8                      Reserved;                   /* 0x03 */
+} MPI2_RAIDVOL0_PHYS_DISK, MPI2_POINTER PTR_MPI2_RAIDVOL0_PHYS_DISK,
+  Mpi2RaidVol0PhysDisk_t, MPI2_POINTER pMpi2RaidVol0PhysDisk_t;
+
+/* defines for the PhysDiskMap field */
+#define MPI2_RAIDVOL0_PHYSDISK_PRIMARY                  (0x01)
+#define MPI2_RAIDVOL0_PHYSDISK_SECONDARY                (0x02)
+
+typedef struct _MPI2_RAIDVOL0_SETTINGS
+{
+    U16                     Settings;                   /* 0x00 */
+    U8                      HotSparePool;               /* 0x01 */
+    U8                      Reserved;                   /* 0x02 */
+} MPI2_RAIDVOL0_SETTINGS, MPI2_POINTER PTR_MPI2_RAIDVOL0_SETTINGS,
+  Mpi2RaidVol0Settings_t, MPI2_POINTER pMpi2RaidVol0Settings_t;
+
+/* RAID Volume Page 0 HotSparePool defines, also used in RAID Physical Disk */
+#define MPI2_RAID_HOT_SPARE_POOL_0                      (0x01)
+#define MPI2_RAID_HOT_SPARE_POOL_1                      (0x02)
+#define MPI2_RAID_HOT_SPARE_POOL_2                      (0x04)
+#define MPI2_RAID_HOT_SPARE_POOL_3                      (0x08)
+#define MPI2_RAID_HOT_SPARE_POOL_4                      (0x10)
+#define MPI2_RAID_HOT_SPARE_POOL_5                      (0x20)
+#define MPI2_RAID_HOT_SPARE_POOL_6                      (0x40)
+#define MPI2_RAID_HOT_SPARE_POOL_7                      (0x80)
+
+/* RAID Volume Page 0 VolumeSettings defines */
+#define MPI2_RAIDVOL0_SETTING_USE_PRODUCT_ID_SUFFIX     (0x0008)
+#define MPI2_RAIDVOL0_SETTING_AUTO_CONFIG_HSWAP_DISABLE (0x0004)
+
+#define MPI2_RAIDVOL0_SETTING_MASK_WRITE_CACHING        (0x0003)
+#define MPI2_RAIDVOL0_SETTING_UNCHANGED                 (0x0000)
+#define MPI2_RAIDVOL0_SETTING_DISABLE_WRITE_CACHING     (0x0001)
+#define MPI2_RAIDVOL0_SETTING_ENABLE_WRITE_CACHING      (0x0002)
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check Header.PageLength at runtime.
+ */
+#ifndef MPI2_RAID_VOL_PAGE_0_PHYSDISK_MAX
+#define MPI2_RAID_VOL_PAGE_0_PHYSDISK_MAX       (1)
+#endif
+
+typedef struct _MPI2_CONFIG_PAGE_RAID_VOL_0
+{
+    MPI2_CONFIG_PAGE_HEADER Header;                     /* 0x00 */
+    U16                     DevHandle;                  /* 0x04 */
+    U8                      VolumeState;                /* 0x06 */
+    U8                      VolumeType;                 /* 0x07 */
+    U32                     VolumeStatusFlags;          /* 0x08 */
+    MPI2_RAIDVOL0_SETTINGS  VolumeSettings;             /* 0x0C */
+    U64                     MaxLBA;                     /* 0x10 */
+    U32                     StripeSize;                 /* 0x18 */
+    U16                     BlockSize;                  /* 0x1C */
+    U16                     Reserved1;                  /* 0x1E */
+    U8                      SupportedPhysDisks;         /* 0x20 */
+    U8                      ResyncRate;                 /* 0x21 */
+    U16                     DataScrubDuration;          /* 0x22 */
+    U8                      NumPhysDisks;               /* 0x24 */
+    U8                      Reserved2;                  /* 0x25 */
+    U8                      Reserved3;                  /* 0x26 */
+    U8                      InactiveStatus;             /* 0x27 */
+    MPI2_RAIDVOL0_PHYS_DISK PhysDisk[MPI2_RAID_VOL_PAGE_0_PHYSDISK_MAX]; /* 0x28 */
+} MPI2_CONFIG_PAGE_RAID_VOL_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_RAID_VOL_0,
+  Mpi2RaidVolPage0_t, MPI2_POINTER pMpi2RaidVolPage0_t;
+
+#define MPI2_RAIDVOLPAGE0_PAGEVERSION           (0x0A)
+
+/* values for RAID VolumeState */
+#define MPI2_RAID_VOL_STATE_MISSING                         (0x00)
+#define MPI2_RAID_VOL_STATE_FAILED                          (0x01)
+#define MPI2_RAID_VOL_STATE_INITIALIZING                    (0x02)
+#define MPI2_RAID_VOL_STATE_ONLINE                          (0x03)
+#define MPI2_RAID_VOL_STATE_DEGRADED                        (0x04)
+#define MPI2_RAID_VOL_STATE_OPTIMAL                         (0x05)
+
+/* values for RAID VolumeType */
+#define MPI2_RAID_VOL_TYPE_RAID0                            (0x00)
+#define MPI2_RAID_VOL_TYPE_RAID1E                           (0x01)
+#define MPI2_RAID_VOL_TYPE_RAID1                            (0x02)
+#define MPI2_RAID_VOL_TYPE_RAID10                           (0x05)
+#define MPI2_RAID_VOL_TYPE_UNKNOWN                          (0xFF)
+
+/* values for RAID Volume Page 0 VolumeStatusFlags field */
+#define MPI2_RAIDVOL0_STATUS_FLAG_PENDING_RESYNC            (0x02000000)
+#define MPI2_RAIDVOL0_STATUS_FLAG_BACKG_INIT_PENDING        (0x01000000)
+#define MPI2_RAIDVOL0_STATUS_FLAG_MDC_PENDING               (0x00800000)
+#define MPI2_RAIDVOL0_STATUS_FLAG_USER_CONSIST_PENDING      (0x00400000)
+#define MPI2_RAIDVOL0_STATUS_FLAG_MAKE_DATA_CONSISTENT      (0x00200000)
+#define MPI2_RAIDVOL0_STATUS_FLAG_DATA_SCRUB                (0x00100000)
+#define MPI2_RAIDVOL0_STATUS_FLAG_CONSISTENCY_CHECK         (0x00080000)
+#define MPI2_RAIDVOL0_STATUS_FLAG_CAPACITY_EXPANSION        (0x00040000)
+#define MPI2_RAIDVOL0_STATUS_FLAG_BACKGROUND_INIT           (0x00020000)
+#define MPI2_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS        (0x00010000)
+#define MPI2_RAIDVOL0_STATUS_FLAG_OCE_ALLOWED               (0x00000040)
+#define MPI2_RAIDVOL0_STATUS_FLAG_BGI_COMPLETE              (0x00000020)
+#define MPI2_RAIDVOL0_STATUS_FLAG_1E_OFFSET_MIRROR          (0x00000000)
+#define MPI2_RAIDVOL0_STATUS_FLAG_1E_ADJACENT_MIRROR        (0x00000010)
+#define MPI2_RAIDVOL0_STATUS_FLAG_BAD_BLOCK_TABLE_FULL      (0x00000008)
+#define MPI2_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE           (0x00000004)
+#define MPI2_RAIDVOL0_STATUS_FLAG_QUIESCED                  (0x00000002)
+#define MPI2_RAIDVOL0_STATUS_FLAG_ENABLED                   (0x00000001)
+
+/* values for RAID Volume Page 0 SupportedPhysDisks field */
+#define MPI2_RAIDVOL0_SUPPORT_SOLID_STATE_DISKS             (0x08)
+#define MPI2_RAIDVOL0_SUPPORT_HARD_DISKS                    (0x04)
+#define MPI2_RAIDVOL0_SUPPORT_SAS_PROTOCOL                  (0x02)
+#define MPI2_RAIDVOL0_SUPPORT_SATA_PROTOCOL                 (0x01)
+
+/* values for RAID Volume Page 0 InactiveStatus field */
+#define MPI2_RAIDVOLPAGE0_UNKNOWN_INACTIVE                  (0x00)
+#define MPI2_RAIDVOLPAGE0_STALE_METADATA_INACTIVE           (0x01)
+#define MPI2_RAIDVOLPAGE0_FOREIGN_VOLUME_INACTIVE           (0x02)
+#define MPI2_RAIDVOLPAGE0_INSUFFICIENT_RESOURCE_INACTIVE    (0x03)
+#define MPI2_RAIDVOLPAGE0_CLONE_VOLUME_INACTIVE             (0x04)
+#define MPI2_RAIDVOLPAGE0_INSUFFICIENT_METADATA_INACTIVE    (0x05)
+#define MPI2_RAIDVOLPAGE0_PREVIOUSLY_DELETED                (0x06)
+
+
+/* RAID Volume Page 1 */
+
+typedef struct _MPI2_CONFIG_PAGE_RAID_VOL_1
+{
+    MPI2_CONFIG_PAGE_HEADER Header;                     /* 0x00 */
+    U16                     DevHandle;                  /* 0x04 */
+    U16                     Reserved0;                  /* 0x06 */
+    U8                      GUID[24];                   /* 0x08 */
+    U8                      Name[16];                   /* 0x20 */
+    U64                     WWID;                       /* 0x30 */
+    U32                     Reserved1;                  /* 0x38 */
+    U32                     Reserved2;                  /* 0x3C */
+} MPI2_CONFIG_PAGE_RAID_VOL_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_RAID_VOL_1,
+  Mpi2RaidVolPage1_t, MPI2_POINTER pMpi2RaidVolPage1_t;
+
+#define MPI2_RAIDVOLPAGE1_PAGEVERSION           (0x03)
+
+
+/****************************************************************************
+*   RAID Physical Disk Config Pages
+****************************************************************************/
+
+/* RAID Physical Disk Page 0 */
+
+typedef struct _MPI2_RAIDPHYSDISK0_SETTINGS
+{
+    U16                     Reserved1;                  /* 0x00 */
+    U8                      HotSparePool;               /* 0x02 */
+    U8                      Reserved2;                  /* 0x03 */
+} MPI2_RAIDPHYSDISK0_SETTINGS, MPI2_POINTER PTR_MPI2_RAIDPHYSDISK0_SETTINGS,
+  Mpi2RaidPhysDisk0Settings_t, MPI2_POINTER pMpi2RaidPhysDisk0Settings_t;
+
+/* use MPI2_RAID_HOT_SPARE_POOL_ defines for the HotSparePool field */
+
+typedef struct _MPI2_RAIDPHYSDISK0_INQUIRY_DATA
+{
+    U8                      VendorID[8];                /* 0x00 */
+    U8                      ProductID[16];              /* 0x08 */
+    U8                      ProductRevLevel[4];         /* 0x18 */
+    U8                      SerialNum[32];              /* 0x1C */
+} MPI2_RAIDPHYSDISK0_INQUIRY_DATA,
+  MPI2_POINTER PTR_MPI2_RAIDPHYSDISK0_INQUIRY_DATA,
+  Mpi2RaidPhysDisk0InquiryData_t, MPI2_POINTER pMpi2RaidPhysDisk0InquiryData_t;
+
+typedef struct _MPI2_CONFIG_PAGE_RD_PDISK_0
+{
+    MPI2_CONFIG_PAGE_HEADER         Header;                     /* 0x00 */
+    U16                             DevHandle;                  /* 0x04 */
+    U8                              Reserved1;                  /* 0x06 */
+    U8                              PhysDiskNum;                /* 0x07 */
+    MPI2_RAIDPHYSDISK0_SETTINGS     PhysDiskSettings;           /* 0x08 */
+    U32                             Reserved2;                  /* 0x0C */
+    MPI2_RAIDPHYSDISK0_INQUIRY_DATA InquiryData;                /* 0x10 */
+    U32                             Reserved3;                  /* 0x4C */
+    U8                              PhysDiskState;              /* 0x50 */
+    U8                              OfflineReason;              /* 0x51 */
+    U8                              IncompatibleReason;         /* 0x52 */
+    U8                              PhysDiskAttributes;         /* 0x53 */
+    U32                             PhysDiskStatusFlags;        /* 0x54 */
+    U64                             DeviceMaxLBA;               /* 0x58 */
+    U64                             HostMaxLBA;                 /* 0x60 */
+    U64                             CoercedMaxLBA;              /* 0x68 */
+    U16                             BlockSize;                  /* 0x70 */
+    U16                             Reserved5;                  /* 0x72 */
+    U32                             Reserved6;                  /* 0x74 */
+} MPI2_CONFIG_PAGE_RD_PDISK_0,
+  MPI2_POINTER PTR_MPI2_CONFIG_PAGE_RD_PDISK_0,
+  Mpi2RaidPhysDiskPage0_t, MPI2_POINTER pMpi2RaidPhysDiskPage0_t;
+
+#define MPI2_RAIDPHYSDISKPAGE0_PAGEVERSION          (0x05)
+
+/* PhysDiskState defines */
+#define MPI2_RAID_PD_STATE_NOT_CONFIGURED               (0x00)
+#define MPI2_RAID_PD_STATE_NOT_COMPATIBLE               (0x01)
+#define MPI2_RAID_PD_STATE_OFFLINE                      (0x02)
+#define MPI2_RAID_PD_STATE_ONLINE                       (0x03)
+#define MPI2_RAID_PD_STATE_HOT_SPARE                    (0x04)
+#define MPI2_RAID_PD_STATE_DEGRADED                     (0x05)
+#define MPI2_RAID_PD_STATE_REBUILDING                   (0x06)
+#define MPI2_RAID_PD_STATE_OPTIMAL                      (0x07)
+
+/* OfflineReason defines */
+#define MPI2_PHYSDISK0_ONLINE                           (0x00)
+#define MPI2_PHYSDISK0_OFFLINE_MISSING                  (0x01)
+#define MPI2_PHYSDISK0_OFFLINE_FAILED                   (0x03)
+#define MPI2_PHYSDISK0_OFFLINE_INITIALIZING             (0x04)
+#define MPI2_PHYSDISK0_OFFLINE_REQUESTED                (0x05)
+#define MPI2_PHYSDISK0_OFFLINE_FAILED_REQUESTED         (0x06)
+#define MPI2_PHYSDISK0_OFFLINE_OTHER                    (0xFF)
+
+/* IncompatibleReason defines */
+#define MPI2_PHYSDISK0_COMPATIBLE                       (0x00)
+#define MPI2_PHYSDISK0_INCOMPATIBLE_PROTOCOL            (0x01)
+#define MPI2_PHYSDISK0_INCOMPATIBLE_BLOCKSIZE           (0x02)
+#define MPI2_PHYSDISK0_INCOMPATIBLE_MAX_LBA             (0x03)
+#define MPI2_PHYSDISK0_INCOMPATIBLE_SATA_EXTENDED_CMD   (0x04)
+#define MPI2_PHYSDISK0_INCOMPATIBLE_REMOVEABLE_MEDIA    (0x05)
+#define MPI2_PHYSDISK0_INCOMPATIBLE_UNKNOWN             (0xFF)
+
+/* PhysDiskAttributes defines */
+#define MPI2_PHYSDISK0_ATTRIB_SOLID_STATE_DRIVE         (0x08)
+#define MPI2_PHYSDISK0_ATTRIB_HARD_DISK_DRIVE           (0x04)
+#define MPI2_PHYSDISK0_ATTRIB_SAS_PROTOCOL              (0x02)
+#define MPI2_PHYSDISK0_ATTRIB_SATA_PROTOCOL             (0x01)
+
+/* PhysDiskStatusFlags defines */
+#define MPI2_PHYSDISK0_STATUS_FLAG_NOT_CERTIFIED        (0x00000040)
+#define MPI2_PHYSDISK0_STATUS_FLAG_OCE_TARGET           (0x00000020)
+#define MPI2_PHYSDISK0_STATUS_FLAG_WRITE_CACHE_ENABLED  (0x00000010)
+#define MPI2_PHYSDISK0_STATUS_FLAG_OPTIMAL_PREVIOUS     (0x00000000)
+#define MPI2_PHYSDISK0_STATUS_FLAG_NOT_OPTIMAL_PREVIOUS (0x00000008)
+#define MPI2_PHYSDISK0_STATUS_FLAG_INACTIVE_VOLUME      (0x00000004)
+#define MPI2_PHYSDISK0_STATUS_FLAG_QUIESCED             (0x00000002)
+#define MPI2_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC          (0x00000001)
+
+
+/* RAID Physical Disk Page 1 */
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check Header.PageLength or NumPhysDiskPaths at runtime.
+ */
+#ifndef MPI2_RAID_PHYS_DISK1_PATH_MAX
+#define MPI2_RAID_PHYS_DISK1_PATH_MAX   (1)
+#endif
+
+typedef struct _MPI2_RAIDPHYSDISK1_PATH
+{
+    U16             DevHandle;          /* 0x00 */
+    U16             Reserved1;          /* 0x02 */
+    U64             WWID;               /* 0x04 */
+    U64             OwnerWWID;          /* 0x0C */
+    U8              OwnerIdentifier;    /* 0x14 */
+    U8              Reserved2;          /* 0x15 */
+    U16             Flags;              /* 0x16 */
+} MPI2_RAIDPHYSDISK1_PATH, MPI2_POINTER PTR_MPI2_RAIDPHYSDISK1_PATH,
+  Mpi2RaidPhysDisk1Path_t, MPI2_POINTER pMpi2RaidPhysDisk1Path_t;
+
+/* RAID Physical Disk Page 1 Physical Disk Path Flags field defines */
+#define MPI2_RAID_PHYSDISK1_FLAG_PRIMARY        (0x0004)
+#define MPI2_RAID_PHYSDISK1_FLAG_BROKEN         (0x0002)
+#define MPI2_RAID_PHYSDISK1_FLAG_INVALID        (0x0001)
+
+typedef struct _MPI2_CONFIG_PAGE_RD_PDISK_1
+{
+    MPI2_CONFIG_PAGE_HEADER         Header;                     /* 0x00 */
+    U8                              NumPhysDiskPaths;           /* 0x04 */
+    U8                              PhysDiskNum;                /* 0x05 */
+    U16                             Reserved1;                  /* 0x06 */
+    U32                             Reserved2;                  /* 0x08 */
+    MPI2_RAIDPHYSDISK1_PATH         PhysicalDiskPath[MPI2_RAID_PHYS_DISK1_PATH_MAX];/* 0x0C */
+} MPI2_CONFIG_PAGE_RD_PDISK_1,
+  MPI2_POINTER PTR_MPI2_CONFIG_PAGE_RD_PDISK_1,
+  Mpi2RaidPhysDiskPage1_t, MPI2_POINTER pMpi2RaidPhysDiskPage1_t;
+
+#define MPI2_RAIDPHYSDISKPAGE1_PAGEVERSION          (0x02)
+
+
+/****************************************************************************
+*   values for fields used by several types of SAS Config Pages
+****************************************************************************/
+
+/* values for NegotiatedLinkRates fields */
+#define MPI2_SAS_NEG_LINK_RATE_MASK_LOGICAL             (0xF0)
+#define MPI2_SAS_NEG_LINK_RATE_SHIFT_LOGICAL            (4)
+#define MPI2_SAS_NEG_LINK_RATE_MASK_PHYSICAL            (0x0F)
+/* link rates used for Negotiated Physical and Logical Link Rate */
+#define MPI2_SAS_NEG_LINK_RATE_UNKNOWN_LINK_RATE        (0x00)
+#define MPI2_SAS_NEG_LINK_RATE_PHY_DISABLED             (0x01)
+#define MPI2_SAS_NEG_LINK_RATE_NEGOTIATION_FAILED       (0x02)
+#define MPI2_SAS_NEG_LINK_RATE_SATA_OOB_COMPLETE        (0x03)
+#define MPI2_SAS_NEG_LINK_RATE_PORT_SELECTOR            (0x04)
+#define MPI2_SAS_NEG_LINK_RATE_SMP_RESET_IN_PROGRESS    (0x05)
+#define MPI2_SAS_NEG_LINK_RATE_1_5                      (0x08)
+#define MPI2_SAS_NEG_LINK_RATE_3_0                      (0x09)
+#define MPI2_SAS_NEG_LINK_RATE_6_0                      (0x0A)
+
+
+/* values for AttachedPhyInfo fields */
+#define MPI2_SAS_APHYINFO_INSIDE_ZPSDS_PERSISTENT       (0x00000040)
+#define MPI2_SAS_APHYINFO_REQUESTED_INSIDE_ZPSDS        (0x00000020)
+#define MPI2_SAS_APHYINFO_BREAK_REPLY_CAPABLE           (0x00000010)
+
+#define MPI2_SAS_APHYINFO_REASON_MASK                   (0x0000000F)
+#define MPI2_SAS_APHYINFO_REASON_UNKNOWN                (0x00000000)
+#define MPI2_SAS_APHYINFO_REASON_POWER_ON               (0x00000001)
+#define MPI2_SAS_APHYINFO_REASON_HARD_RESET             (0x00000002)
+#define MPI2_SAS_APHYINFO_REASON_SMP_PHY_CONTROL        (0x00000003)
+#define MPI2_SAS_APHYINFO_REASON_LOSS_OF_SYNC           (0x00000004)
+#define MPI2_SAS_APHYINFO_REASON_MULTIPLEXING_SEQ       (0x00000005)
+#define MPI2_SAS_APHYINFO_REASON_IT_NEXUS_LOSS_TIMER    (0x00000006)
+#define MPI2_SAS_APHYINFO_REASON_BREAK_TIMEOUT          (0x00000007)
+#define MPI2_SAS_APHYINFO_REASON_PHY_TEST_STOPPED       (0x00000008)
+
+
+/* values for PhyInfo fields */
+#define MPI2_SAS_PHYINFO_PHY_VACANT                     (0x80000000)
+#define MPI2_SAS_PHYINFO_CHANGED_REQ_INSIDE_ZPSDS       (0x04000000)
+#define MPI2_SAS_PHYINFO_INSIDE_ZPSDS_PERSISTENT        (0x02000000)
+#define MPI2_SAS_PHYINFO_REQ_INSIDE_ZPSDS               (0x01000000)
+#define MPI2_SAS_PHYINFO_ZONE_GROUP_PERSISTENT          (0x00400000)
+#define MPI2_SAS_PHYINFO_INSIDE_ZPSDS                   (0x00200000)
+#define MPI2_SAS_PHYINFO_ZONING_ENABLED                 (0x00100000)
+
+#define MPI2_SAS_PHYINFO_REASON_MASK                    (0x000F0000)
+#define MPI2_SAS_PHYINFO_REASON_UNKNOWN                 (0x00000000)
+#define MPI2_SAS_PHYINFO_REASON_POWER_ON                (0x00010000)
+#define MPI2_SAS_PHYINFO_REASON_HARD_RESET              (0x00020000)
+#define MPI2_SAS_PHYINFO_REASON_SMP_PHY_CONTROL         (0x00030000)
+#define MPI2_SAS_PHYINFO_REASON_LOSS_OF_SYNC            (0x00040000)
+#define MPI2_SAS_PHYINFO_REASON_MULTIPLEXING_SEQ        (0x00050000)
+#define MPI2_SAS_PHYINFO_REASON_IT_NEXUS_LOSS_TIMER     (0x00060000)
+#define MPI2_SAS_PHYINFO_REASON_BREAK_TIMEOUT           (0x00070000)
+#define MPI2_SAS_PHYINFO_REASON_PHY_TEST_STOPPED        (0x00080000)
+
+#define MPI2_SAS_PHYINFO_MULTIPLEXING_SUPPORTED         (0x00008000)
+#define MPI2_SAS_PHYINFO_SATA_PORT_ACTIVE               (0x00004000)
+#define MPI2_SAS_PHYINFO_SATA_PORT_SELECTOR_PRESENT     (0x00002000)
+#define MPI2_SAS_PHYINFO_VIRTUAL_PHY                    (0x00001000)
+
+#define MPI2_SAS_PHYINFO_MASK_PARTIAL_PATHWAY_TIME      (0x00000F00)
+#define MPI2_SAS_PHYINFO_SHIFT_PARTIAL_PATHWAY_TIME     (8)
+
+#define MPI2_SAS_PHYINFO_MASK_ROUTING_ATTRIBUTE         (0x000000F0)
+#define MPI2_SAS_PHYINFO_DIRECT_ROUTING                 (0x00000000)
+#define MPI2_SAS_PHYINFO_SUBTRACTIVE_ROUTING            (0x00000010)
+#define MPI2_SAS_PHYINFO_TABLE_ROUTING                  (0x00000020)
+
+
+/* values for SAS ProgrammedLinkRate fields */
+#define MPI2_SAS_PRATE_MAX_RATE_MASK                    (0xF0)
+#define MPI2_SAS_PRATE_MAX_RATE_NOT_PROGRAMMABLE        (0x00)
+#define MPI2_SAS_PRATE_MAX_RATE_1_5                     (0x80)
+#define MPI2_SAS_PRATE_MAX_RATE_3_0                     (0x90)
+#define MPI2_SAS_PRATE_MAX_RATE_6_0                     (0xA0)
+#define MPI2_SAS_PRATE_MIN_RATE_MASK                    (0x0F)
+#define MPI2_SAS_PRATE_MIN_RATE_NOT_PROGRAMMABLE        (0x00)
+#define MPI2_SAS_PRATE_MIN_RATE_1_5                     (0x08)
+#define MPI2_SAS_PRATE_MIN_RATE_3_0                     (0x09)
+#define MPI2_SAS_PRATE_MIN_RATE_6_0                     (0x0A)
+
+
+/* values for SAS HwLinkRate fields */
+#define MPI2_SAS_HWRATE_MAX_RATE_MASK                   (0xF0)
+#define MPI2_SAS_HWRATE_MAX_RATE_1_5                    (0x80)
+#define MPI2_SAS_HWRATE_MAX_RATE_3_0                    (0x90)
+#define MPI2_SAS_HWRATE_MAX_RATE_6_0                    (0xA0)
+#define MPI2_SAS_HWRATE_MIN_RATE_MASK                   (0x0F)
+#define MPI2_SAS_HWRATE_MIN_RATE_1_5                    (0x08)
+#define MPI2_SAS_HWRATE_MIN_RATE_3_0                    (0x09)
+#define MPI2_SAS_HWRATE_MIN_RATE_6_0                    (0x0A)
+
+
+
+/****************************************************************************
+*   SAS IO Unit Config Pages
+****************************************************************************/
+
+/* SAS IO Unit Page 0 */
+
+typedef struct _MPI2_SAS_IO_UNIT0_PHY_DATA
+{
+    U8          Port;                   /* 0x00 */
+    U8          PortFlags;              /* 0x01 */
+    U8          PhyFlags;               /* 0x02 */
+    U8          NegotiatedLinkRate;     /* 0x03 */
+    U32         ControllerPhyDeviceInfo;/* 0x04 */
+    U16         AttachedDevHandle;      /* 0x08 */
+    U16         ControllerDevHandle;    /* 0x0A */
+    U32         DiscoveryStatus;        /* 0x0C */
+    U32         Reserved;               /* 0x10 */
+} MPI2_SAS_IO_UNIT0_PHY_DATA, MPI2_POINTER PTR_MPI2_SAS_IO_UNIT0_PHY_DATA,
+  Mpi2SasIOUnit0PhyData_t, MPI2_POINTER pMpi2SasIOUnit0PhyData_t;
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check Header.ExtPageLength or NumPhys at runtime.
+ */
+#ifndef MPI2_SAS_IOUNIT0_PHY_MAX
+#define MPI2_SAS_IOUNIT0_PHY_MAX        (1)
+#endif
+
+typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_0
+{
+    MPI2_CONFIG_EXTENDED_PAGE_HEADER    Header;                             /* 0x00 */
+    U32                                 Reserved1;                          /* 0x08 */
+    U8                                  NumPhys;                            /* 0x0C */
+    U8                                  Reserved2;                          /* 0x0D */
+    U16                                 Reserved3;                          /* 0x0E */
+    MPI2_SAS_IO_UNIT0_PHY_DATA          PhyData[MPI2_SAS_IOUNIT0_PHY_MAX];  /* 0x10 */
+} MPI2_CONFIG_PAGE_SASIOUNIT_0,
+  MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_0,
+  Mpi2SasIOUnitPage0_t, MPI2_POINTER pMpi2SasIOUnitPage0_t;
+
+#define MPI2_SASIOUNITPAGE0_PAGEVERSION                     (0x05)
+
+/* values for SAS IO Unit Page 0 PortFlags */
+#define MPI2_SASIOUNIT0_PORTFLAGS_DISCOVERY_IN_PROGRESS     (0x08)
+#define MPI2_SASIOUNIT0_PORTFLAGS_AUTO_PORT_CONFIG          (0x01)
+
+/* values for SAS IO Unit Page 0 PhyFlags */
+#define MPI2_SASIOUNIT0_PHYFLAGS_ZONING_ENABLED             (0x10)
+#define MPI2_SASIOUNIT0_PHYFLAGS_PHY_DISABLED               (0x08)
+
+/* use MPI2_SAS_NEG_LINK_RATE_ defines for the NegotiatedLinkRate field */
+
+/* see mpi2_sas.h for values for SAS IO Unit Page 0 ControllerPhyDeviceInfo values */
+
+/* values for SAS IO Unit Page 0 DiscoveryStatus */
+#define MPI2_SASIOUNIT0_DS_MAX_ENCLOSURES_EXCEED            (0x80000000)
+#define MPI2_SASIOUNIT0_DS_MAX_EXPANDERS_EXCEED             (0x40000000)
+#define MPI2_SASIOUNIT0_DS_MAX_DEVICES_EXCEED               (0x20000000)
+#define MPI2_SASIOUNIT0_DS_MAX_TOPO_PHYS_EXCEED             (0x10000000)
+#define MPI2_SASIOUNIT0_DS_DOWNSTREAM_INITIATOR             (0x08000000)
+#define MPI2_SASIOUNIT0_DS_MULTI_SUBTRACTIVE_SUBTRACTIVE    (0x00008000)
+#define MPI2_SASIOUNIT0_DS_EXP_MULTI_SUBTRACTIVE            (0x00004000)
+#define MPI2_SASIOUNIT0_DS_MULTI_PORT_DOMAIN                (0x00002000)
+#define MPI2_SASIOUNIT0_DS_TABLE_TO_SUBTRACTIVE_LINK        (0x00001000)
+#define MPI2_SASIOUNIT0_DS_UNSUPPORTED_DEVICE               (0x00000800)
+#define MPI2_SASIOUNIT0_DS_TABLE_LINK                       (0x00000400)
+#define MPI2_SASIOUNIT0_DS_SUBTRACTIVE_LINK                 (0x00000200)
+#define MPI2_SASIOUNIT0_DS_SMP_CRC_ERROR                    (0x00000100)
+#define MPI2_SASIOUNIT0_DS_SMP_FUNCTION_FAILED              (0x00000080)
+#define MPI2_SASIOUNIT0_DS_INDEX_NOT_EXIST                  (0x00000040)
+#define MPI2_SASIOUNIT0_DS_OUT_ROUTE_ENTRIES                (0x00000020)
+#define MPI2_SASIOUNIT0_DS_SMP_TIMEOUT                      (0x00000010)
+#define MPI2_SASIOUNIT0_DS_MULTIPLE_PORTS                   (0x00000004)
+#define MPI2_SASIOUNIT0_DS_UNADDRESSABLE_DEVICE             (0x00000002)
+#define MPI2_SASIOUNIT0_DS_LOOP_DETECTED                    (0x00000001)
+
+
+/* SAS IO Unit Page 1 */
+
+typedef struct _MPI2_SAS_IO_UNIT1_PHY_DATA
+{
+    U8          Port;                       /* 0x00 */
+    U8          PortFlags;                  /* 0x01 */
+    U8          PhyFlags;                   /* 0x02 */
+    U8          MaxMinLinkRate;             /* 0x03 */
+    U32         ControllerPhyDeviceInfo;    /* 0x04 */
+    U16         MaxTargetPortConnectTime;   /* 0x08 */
+    U16         Reserved1;                  /* 0x0A */
+} MPI2_SAS_IO_UNIT1_PHY_DATA, MPI2_POINTER PTR_MPI2_SAS_IO_UNIT1_PHY_DATA,
+  Mpi2SasIOUnit1PhyData_t, MPI2_POINTER pMpi2SasIOUnit1PhyData_t;
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check Header.ExtPageLength or NumPhys at runtime.
+ */
+#ifndef MPI2_SAS_IOUNIT1_PHY_MAX
+#define MPI2_SAS_IOUNIT1_PHY_MAX        (1)
+#endif
+
+typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_1
+{
+    MPI2_CONFIG_EXTENDED_PAGE_HEADER    Header;                             /* 0x00 */
+    U16                                 ControlFlags;                       /* 0x08 */
+    U16                                 SASNarrowMaxQueueDepth;             /* 0x0A */
+    U16                                 AdditionalControlFlags;             /* 0x0C */
+    U16                                 SASWideMaxQueueDepth;               /* 0x0E */
+    U8                                  NumPhys;                            /* 0x10 */
+    U8                                  SATAMaxQDepth;                      /* 0x11 */
+    U8                                  ReportDeviceMissingDelay;           /* 0x12 */
+    U8                                  IODeviceMissingDelay;               /* 0x13 */
+    MPI2_SAS_IO_UNIT1_PHY_DATA          PhyData[MPI2_SAS_IOUNIT1_PHY_MAX];  /* 0x14 */
+} MPI2_CONFIG_PAGE_SASIOUNIT_1,
+  MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_1,
+  Mpi2SasIOUnitPage1_t, MPI2_POINTER pMpi2SasIOUnitPage1_t;
+
+#define MPI2_SASIOUNITPAGE1_PAGEVERSION     (0x09)
+
+/* values for SAS IO Unit Page 1 ControlFlags */
+#define MPI2_SASIOUNIT1_CONTROL_DEVICE_SELF_TEST                    (0x8000)
+#define MPI2_SASIOUNIT1_CONTROL_SATA_3_0_MAX                        (0x4000)
+#define MPI2_SASIOUNIT1_CONTROL_SATA_1_5_MAX                        (0x2000)
+#define MPI2_SASIOUNIT1_CONTROL_SATA_SW_PRESERVE                    (0x1000)
+
+#define MPI2_SASIOUNIT1_CONTROL_MASK_DEV_SUPPORT                    (0x0600)
+#define MPI2_SASIOUNIT1_CONTROL_SHIFT_DEV_SUPPORT                   (9)
+#define MPI2_SASIOUNIT1_CONTROL_DEV_SUPPORT_BOTH                    (0x0)
+#define MPI2_SASIOUNIT1_CONTROL_DEV_SAS_SUPPORT                     (0x1)
+#define MPI2_SASIOUNIT1_CONTROL_DEV_SATA_SUPPORT                    (0x2)
+
+#define MPI2_SASIOUNIT1_CONTROL_SATA_48BIT_LBA_REQUIRED             (0x0080)
+#define MPI2_SASIOUNIT1_CONTROL_SATA_SMART_REQUIRED                 (0x0040)
+#define MPI2_SASIOUNIT1_CONTROL_SATA_NCQ_REQUIRED                   (0x0020)
+#define MPI2_SASIOUNIT1_CONTROL_SATA_FUA_REQUIRED                   (0x0010)
+#define MPI2_SASIOUNIT1_CONTROL_TABLE_SUBTRACTIVE_ILLEGAL           (0x0008)
+#define MPI2_SASIOUNIT1_CONTROL_SUBTRACTIVE_ILLEGAL                 (0x0004)
+#define MPI2_SASIOUNIT1_CONTROL_FIRST_LVL_DISC_ONLY                 (0x0002)
+#define MPI2_SASIOUNIT1_CONTROL_CLEAR_AFFILIATION                   (0x0001)
+
+/* values for SAS IO Unit Page 1 AdditionalControlFlags */
+#define MPI2_SASIOUNIT1_ACONTROL_MULTI_PORT_DOMAIN_ILLEGAL          (0x0080)
+#define MPI2_SASIOUNIT1_ACONTROL_SATA_ASYNCHROUNOUS_NOTIFICATION    (0x0040)
+#define MPI2_SASIOUNIT1_ACONTROL_INVALID_TOPOLOGY_CORRECTION        (0x0020)
+#define MPI2_SASIOUNIT1_ACONTROL_PORT_ENABLE_ONLY_SATA_LINK_RESET   (0x0010)
+#define MPI2_SASIOUNIT1_ACONTROL_OTHER_AFFILIATION_SATA_LINK_RESET  (0x0008)
+#define MPI2_SASIOUNIT1_ACONTROL_SELF_AFFILIATION_SATA_LINK_RESET   (0x0004)
+#define MPI2_SASIOUNIT1_ACONTROL_NO_AFFILIATION_SATA_LINK_RESET     (0x0002)
+#define MPI2_SASIOUNIT1_ACONTROL_ALLOW_TABLE_TO_TABLE               (0x0001)
+
+/* defines for SAS IO Unit Page 1 ReportDeviceMissingDelay */
+#define MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK                 (0x7F)
+#define MPI2_SASIOUNIT1_REPORT_MISSING_UNIT_16                      (0x80)
+
+/* values for SAS IO Unit Page 1 PortFlags */
+#define MPI2_SASIOUNIT1_PORT_FLAGS_AUTO_PORT_CONFIG                 (0x01)
+
+/* values for SAS IO Unit Page 2 PhyFlags */
+#define MPI2_SASIOUNIT1_PHYFLAGS_ZONING_ENABLE                      (0x10)
+#define MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE                        (0x08)
+
+/* values for SAS IO Unit Page 0 MaxMinLinkRate */
+#define MPI2_SASIOUNIT1_MAX_RATE_MASK                               (0xF0)
+#define MPI2_SASIOUNIT1_MAX_RATE_1_5                                (0x80)
+#define MPI2_SASIOUNIT1_MAX_RATE_3_0                                (0x90)
+#define MPI2_SASIOUNIT1_MAX_RATE_6_0                                (0xA0)
+#define MPI2_SASIOUNIT1_MIN_RATE_MASK                               (0x0F)
+#define MPI2_SASIOUNIT1_MIN_RATE_1_5                                (0x08)
+#define MPI2_SASIOUNIT1_MIN_RATE_3_0                                (0x09)
+#define MPI2_SASIOUNIT1_MIN_RATE_6_0                                (0x0A)
+
+/* see mpi2_sas.h for values for SAS IO Unit Page 1 ControllerPhyDeviceInfo values */
+
+
+/* SAS IO Unit Page 4 */
+
+typedef struct _MPI2_SAS_IOUNIT4_SPINUP_GROUP
+{
+    U8          MaxTargetSpinup;            /* 0x00 */
+    U8          SpinupDelay;                /* 0x01 */
+    U16         Reserved1;                  /* 0x02 */
+} MPI2_SAS_IOUNIT4_SPINUP_GROUP, MPI2_POINTER PTR_MPI2_SAS_IOUNIT4_SPINUP_GROUP,
+  Mpi2SasIOUnit4SpinupGroup_t, MPI2_POINTER pMpi2SasIOUnit4SpinupGroup_t;
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * four and check Header.ExtPageLength or NumPhys at runtime.
+ */
+#ifndef MPI2_SAS_IOUNIT4_PHY_MAX
+#define MPI2_SAS_IOUNIT4_PHY_MAX        (4)
+#endif
+
+typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_4
+{
+    MPI2_CONFIG_EXTENDED_PAGE_HEADER    Header;                         /* 0x00 */
+    MPI2_SAS_IOUNIT4_SPINUP_GROUP       SpinupGroupParameters[4];       /* 0x08 */
+    U32                                 Reserved1;                      /* 0x18 */
+    U32                                 Reserved2;                      /* 0x1C */
+    U32                                 Reserved3;                      /* 0x20 */
+    U8                                  BootDeviceWaitTime;             /* 0x24 */
+    U8                                  Reserved4;                      /* 0x25 */
+    U16                                 Reserved5;                      /* 0x26 */
+    U8                                  NumPhys;                        /* 0x28 */
+    U8                                  PEInitialSpinupDelay;           /* 0x29 */
+    U8                                  PEReplyDelay;                   /* 0x2A */
+    U8                                  Flags;                          /* 0x2B */
+    U8                                  PHY[MPI2_SAS_IOUNIT4_PHY_MAX];  /* 0x2C */
+} MPI2_CONFIG_PAGE_SASIOUNIT_4,
+  MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_4,
+  Mpi2SasIOUnitPage4_t, MPI2_POINTER pMpi2SasIOUnitPage4_t;
+
+#define MPI2_SASIOUNITPAGE4_PAGEVERSION     (0x02)
+
+/* defines for Flags field */
+#define MPI2_SASIOUNIT4_FLAGS_AUTO_PORTENABLE               (0x01)
+
+/* defines for PHY field */
+#define MPI2_SASIOUNIT4_PHY_SPINUP_GROUP_MASK               (0x03)
+
+
+/****************************************************************************
+*   SAS Expander Config Pages
+****************************************************************************/
+
+/* SAS Expander Page 0 */
+
+typedef struct _MPI2_CONFIG_PAGE_EXPANDER_0
+{
+    MPI2_CONFIG_EXTENDED_PAGE_HEADER    Header;                     /* 0x00 */
+    U8                                  PhysicalPort;               /* 0x08 */
+    U8                                  ReportGenLength;            /* 0x09 */
+    U16                                 EnclosureHandle;            /* 0x0A */
+    U64                                 SASAddress;                 /* 0x0C */
+    U32                                 DiscoveryStatus;            /* 0x14 */
+    U16                                 DevHandle;                  /* 0x18 */
+    U16                                 ParentDevHandle;            /* 0x1A */
+    U16                                 ExpanderChangeCount;        /* 0x1C */
+    U16                                 ExpanderRouteIndexes;       /* 0x1E */
+    U8                                  NumPhys;                    /* 0x20 */
+    U8                                  SASLevel;                   /* 0x21 */
+    U16                                 Flags;                      /* 0x22 */
+    U16                                 STPBusInactivityTimeLimit;  /* 0x24 */
+    U16                                 STPMaxConnectTimeLimit;     /* 0x26 */
+    U16                                 STP_SMP_NexusLossTime;      /* 0x28 */
+    U16                                 MaxNumRoutedSasAddresses;   /* 0x2A */
+    U64                                 ActiveZoneManagerSASAddress;/* 0x2C */
+    U16                                 ZoneLockInactivityLimit;    /* 0x34 */
+    U16                                 Reserved1;                  /* 0x36 */
+} MPI2_CONFIG_PAGE_EXPANDER_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_EXPANDER_0,
+  Mpi2ExpanderPage0_t, MPI2_POINTER pMpi2ExpanderPage0_t;
+
+#define MPI2_SASEXPANDER0_PAGEVERSION       (0x05)
+
+/* values for SAS Expander Page 0 DiscoveryStatus field */
+#define MPI2_SAS_EXPANDER0_DS_MAX_ENCLOSURES_EXCEED         (0x80000000)
+#define MPI2_SAS_EXPANDER0_DS_MAX_EXPANDERS_EXCEED          (0x40000000)
+#define MPI2_SAS_EXPANDER0_DS_MAX_DEVICES_EXCEED            (0x20000000)
+#define MPI2_SAS_EXPANDER0_DS_MAX_TOPO_PHYS_EXCEED          (0x10000000)
+#define MPI2_SAS_EXPANDER0_DS_DOWNSTREAM_INITIATOR          (0x08000000)
+#define MPI2_SAS_EXPANDER0_DS_MULTI_SUBTRACTIVE_SUBTRACTIVE (0x00008000)
+#define MPI2_SAS_EXPANDER0_DS_EXP_MULTI_SUBTRACTIVE         (0x00004000)
+#define MPI2_SAS_EXPANDER0_DS_MULTI_PORT_DOMAIN             (0x00002000)
+#define MPI2_SAS_EXPANDER0_DS_TABLE_TO_SUBTRACTIVE_LINK     (0x00001000)
+#define MPI2_SAS_EXPANDER0_DS_UNSUPPORTED_DEVICE            (0x00000800)
+#define MPI2_SAS_EXPANDER0_DS_TABLE_LINK                    (0x00000400)
+#define MPI2_SAS_EXPANDER0_DS_SUBTRACTIVE_LINK              (0x00000200)
+#define MPI2_SAS_EXPANDER0_DS_SMP_CRC_ERROR                 (0x00000100)
+#define MPI2_SAS_EXPANDER0_DS_SMP_FUNCTION_FAILED           (0x00000080)
+#define MPI2_SAS_EXPANDER0_DS_INDEX_NOT_EXIST               (0x00000040)
+#define MPI2_SAS_EXPANDER0_DS_OUT_ROUTE_ENTRIES             (0x00000020)
+#define MPI2_SAS_EXPANDER0_DS_SMP_TIMEOUT                   (0x00000010)
+#define MPI2_SAS_EXPANDER0_DS_MULTIPLE_PORTS                (0x00000004)
+#define MPI2_SAS_EXPANDER0_DS_UNADDRESSABLE_DEVICE          (0x00000002)
+#define MPI2_SAS_EXPANDER0_DS_LOOP_DETECTED                 (0x00000001)
+
+/* values for SAS Expander Page 0 Flags field */
+#define MPI2_SAS_EXPANDER0_FLAGS_ZONE_LOCKED                (0x1000)
+#define MPI2_SAS_EXPANDER0_FLAGS_SUPPORTED_PHYSICAL_PRES    (0x0800)
+#define MPI2_SAS_EXPANDER0_FLAGS_ASSERTED_PHYSICAL_PRES     (0x0400)
+#define MPI2_SAS_EXPANDER0_FLAGS_ZONING_SUPPORT             (0x0200)
+#define MPI2_SAS_EXPANDER0_FLAGS_ENABLED_ZONING             (0x0100)
+#define MPI2_SAS_EXPANDER0_FLAGS_TABLE_TO_TABLE_SUPPORT     (0x0080)
+#define MPI2_SAS_EXPANDER0_FLAGS_CONNECTOR_END_DEVICE       (0x0010)
+#define MPI2_SAS_EXPANDER0_FLAGS_OTHERS_CONFIG              (0x0004)
+#define MPI2_SAS_EXPANDER0_FLAGS_CONFIG_IN_PROGRESS         (0x0002)
+#define MPI2_SAS_EXPANDER0_FLAGS_ROUTE_TABLE_CONFIG         (0x0001)
+
+
+/* SAS Expander Page 1 */
+
+typedef struct _MPI2_CONFIG_PAGE_EXPANDER_1
+{
+    MPI2_CONFIG_EXTENDED_PAGE_HEADER    Header;                     /* 0x00 */
+    U8                                  PhysicalPort;               /* 0x08 */
+    U8                                  Reserved1;                  /* 0x09 */
+    U16                                 Reserved2;                  /* 0x0A */
+    U8                                  NumPhys;                    /* 0x0C */
+    U8                                  Phy;                        /* 0x0D */
+    U16                                 NumTableEntriesProgrammed;  /* 0x0E */
+    U8                                  ProgrammedLinkRate;         /* 0x10 */
+    U8                                  HwLinkRate;                 /* 0x11 */
+    U16                                 AttachedDevHandle;          /* 0x12 */
+    U32                                 PhyInfo;                    /* 0x14 */
+    U32                                 AttachedDeviceInfo;         /* 0x18 */
+    U16                                 ExpanderDevHandle;          /* 0x1C */
+    U8                                  ChangeCount;                /* 0x1E */
+    U8                                  NegotiatedLinkRate;         /* 0x1F */
+    U8                                  PhyIdentifier;              /* 0x20 */
+    U8                                  AttachedPhyIdentifier;      /* 0x21 */
+    U8                                  Reserved3;                  /* 0x22 */
+    U8                                  DiscoveryInfo;              /* 0x23 */
+    U32                                 AttachedPhyInfo;            /* 0x24 */
+    U8                                  ZoneGroup;                  /* 0x28 */
+    U8                                  SelfConfigStatus;           /* 0x29 */
+    U16                                 Reserved4;                  /* 0x2A */
+} MPI2_CONFIG_PAGE_EXPANDER_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_EXPANDER_1,
+  Mpi2ExpanderPage1_t, MPI2_POINTER pMpi2ExpanderPage1_t;
+
+#define MPI2_SASEXPANDER1_PAGEVERSION       (0x02)
+
+/* use MPI2_SAS_PRATE_ defines for the ProgrammedLinkRate field */
+
+/* use MPI2_SAS_HWRATE_ defines for the HwLinkRate field */
+
+/* use MPI2_SAS_PHYINFO_ for the PhyInfo field */
+
+/* see mpi2_sas.h for the MPI2_SAS_DEVICE_INFO_ defines used for the AttachedDeviceInfo field */
+
+/* use MPI2_SAS_NEG_LINK_RATE_ defines for the NegotiatedLinkRate field */
+
+/* use MPI2_SAS_APHYINFO_ defines for AttachedPhyInfo field */
+
+/* values for SAS Expander Page 1 DiscoveryInfo field */
+#define MPI2_SAS_EXPANDER1_DISCINFO_BAD_PHY_DISABLED    (0x04)
+#define MPI2_SAS_EXPANDER1_DISCINFO_LINK_STATUS_CHANGE  (0x02)
+#define MPI2_SAS_EXPANDER1_DISCINFO_NO_ROUTING_ENTRIES  (0x01)
+
+
+/****************************************************************************
+*   SAS Device Config Pages
+****************************************************************************/
+
+/* SAS Device Page 0 */
+
+typedef struct _MPI2_CONFIG_PAGE_SAS_DEV_0
+{
+    MPI2_CONFIG_EXTENDED_PAGE_HEADER    Header;                 /* 0x00 */
+    U16                                 Slot;                   /* 0x08 */
+    U16                                 EnclosureHandle;        /* 0x0A */
+    U64                                 SASAddress;             /* 0x0C */
+    U16                                 ParentDevHandle;        /* 0x14 */
+    U8                                  PhyNum;                 /* 0x16 */
+    U8                                  AccessStatus;           /* 0x17 */
+    U16                                 DevHandle;              /* 0x18 */
+    U8                                  AttachedPhyIdentifier;  /* 0x1A */
+    U8                                  ZoneGroup;              /* 0x1B */
+    U32                                 DeviceInfo;             /* 0x1C */
+    U16                                 Flags;                  /* 0x20 */
+    U8                                  PhysicalPort;           /* 0x22 */
+    U8                                  MaxPortConnections;     /* 0x23 */
+    U64                                 DeviceName;             /* 0x24 */
+    U8                                  PortGroups;             /* 0x2C */
+    U8                                  DmaGroup;               /* 0x2D */
+    U8                                  ControlGroup;           /* 0x2E */
+    U8                                  Reserved1;              /* 0x2F */
+    U32                                 Reserved2;              /* 0x30 */
+    U32                                 Reserved3;              /* 0x34 */
+} MPI2_CONFIG_PAGE_SAS_DEV_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_DEV_0,
+  Mpi2SasDevicePage0_t, MPI2_POINTER pMpi2SasDevicePage0_t;
+
+#define MPI2_SASDEVICE0_PAGEVERSION         (0x08)
+
+/* values for SAS Device Page 0 AccessStatus field */
+#define MPI2_SAS_DEVICE0_ASTATUS_NO_ERRORS                  (0x00)
+#define MPI2_SAS_DEVICE0_ASTATUS_SATA_INIT_FAILED           (0x01)
+#define MPI2_SAS_DEVICE0_ASTATUS_SATA_CAPABILITY_FAILED     (0x02)
+#define MPI2_SAS_DEVICE0_ASTATUS_SATA_AFFILIATION_CONFLICT  (0x03)
+#define MPI2_SAS_DEVICE0_ASTATUS_SATA_NEEDS_INITIALIZATION  (0x04)
+#define MPI2_SAS_DEVICE0_ASTATUS_ROUTE_NOT_ADDRESSABLE      (0x05)
+#define MPI2_SAS_DEVICE0_ASTATUS_SMP_ERROR_NOT_ADDRESSABLE  (0x06)
+#define MPI2_SAS_DEVICE0_ASTATUS_DEVICE_BLOCKED             (0x07)
+/* specific values for SATA Init failures */
+#define MPI2_SAS_DEVICE0_ASTATUS_SIF_UNKNOWN                (0x10)
+#define MPI2_SAS_DEVICE0_ASTATUS_SIF_AFFILIATION_CONFLICT   (0x11)
+#define MPI2_SAS_DEVICE0_ASTATUS_SIF_DIAG                   (0x12)
+#define MPI2_SAS_DEVICE0_ASTATUS_SIF_IDENTIFICATION         (0x13)
+#define MPI2_SAS_DEVICE0_ASTATUS_SIF_CHECK_POWER            (0x14)
+#define MPI2_SAS_DEVICE0_ASTATUS_SIF_PIO_SN                 (0x15)
+#define MPI2_SAS_DEVICE0_ASTATUS_SIF_MDMA_SN                (0x16)
+#define MPI2_SAS_DEVICE0_ASTATUS_SIF_UDMA_SN                (0x17)
+#define MPI2_SAS_DEVICE0_ASTATUS_SIF_ZONING_VIOLATION       (0x18)
+#define MPI2_SAS_DEVICE0_ASTATUS_SIF_NOT_ADDRESSABLE        (0x19)
+#define MPI2_SAS_DEVICE0_ASTATUS_SIF_MAX                    (0x1F)
+
+/* see mpi2_sas.h for values for SAS Device Page 0 DeviceInfo values */
+
+/* values for SAS Device Page 0 Flags field */
+#define MPI2_SAS_DEVICE0_FLAGS_SATA_ASYNCHRONOUS_NOTIFY     (0x0400)
+#define MPI2_SAS_DEVICE0_FLAGS_SATA_SW_PRESERVE             (0x0200)
+#define MPI2_SAS_DEVICE0_FLAGS_UNSUPPORTED_DEVICE           (0x0100)
+#define MPI2_SAS_DEVICE0_FLAGS_SATA_48BIT_LBA_SUPPORTED     (0x0080)
+#define MPI2_SAS_DEVICE0_FLAGS_SATA_SMART_SUPPORTED         (0x0040)
+#define MPI2_SAS_DEVICE0_FLAGS_SATA_NCQ_SUPPORTED           (0x0020)
+#define MPI2_SAS_DEVICE0_FLAGS_SATA_FUA_SUPPORTED           (0x0010)
+#define MPI2_SAS_DEVICE0_FLAGS_PORT_SELECTOR_ATTACH         (0x0008)
+#define MPI2_SAS_DEVICE0_FLAGS_DEVICE_PRESENT               (0x0001)
+
+
+/* SAS Device Page 1 */
+
+typedef struct _MPI2_CONFIG_PAGE_SAS_DEV_1
+{
+    MPI2_CONFIG_EXTENDED_PAGE_HEADER    Header;                 /* 0x00 */
+    U32                                 Reserved1;              /* 0x08 */
+    U64                                 SASAddress;             /* 0x0C */
+    U32                                 Reserved2;              /* 0x14 */
+    U16                                 DevHandle;              /* 0x18 */
+    U16                                 Reserved3;              /* 0x1A */
+    U8                                  InitialRegDeviceFIS[20];/* 0x1C */
+} MPI2_CONFIG_PAGE_SAS_DEV_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_DEV_1,
+  Mpi2SasDevicePage1_t, MPI2_POINTER pMpi2SasDevicePage1_t;
+
+#define MPI2_SASDEVICE1_PAGEVERSION         (0x01)
+
+
+/****************************************************************************
+*   SAS PHY Config Pages
+****************************************************************************/
+
+/* SAS PHY Page 0 */
+
+typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_0
+{
+    MPI2_CONFIG_EXTENDED_PAGE_HEADER    Header;                 /* 0x00 */
+    U16                                 OwnerDevHandle;         /* 0x08 */
+    U16                                 Reserved1;              /* 0x0A */
+    U16                                 AttachedDevHandle;      /* 0x0C */
+    U8                                  AttachedPhyIdentifier;  /* 0x0E */
+    U8                                  Reserved2;              /* 0x0F */
+    U32                                 AttachedPhyInfo;        /* 0x10 */
+    U8                                  ProgrammedLinkRate;     /* 0x14 */
+    U8                                  HwLinkRate;             /* 0x15 */
+    U8                                  ChangeCount;            /* 0x16 */
+    U8                                  Flags;                  /* 0x17 */
+    U32                                 PhyInfo;                /* 0x18 */
+    U8                                  NegotiatedLinkRate;     /* 0x1C */
+    U8                                  Reserved3;              /* 0x1D */
+    U16                                 Reserved4;              /* 0x1E */
+} MPI2_CONFIG_PAGE_SAS_PHY_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_PHY_0,
+  Mpi2SasPhyPage0_t, MPI2_POINTER pMpi2SasPhyPage0_t;
+
+#define MPI2_SASPHY0_PAGEVERSION            (0x03)
+
+/* use MPI2_SAS_PRATE_ defines for the ProgrammedLinkRate field */
+
+/* use MPI2_SAS_HWRATE_ defines for the HwLinkRate field */
+
+/* values for SAS PHY Page 0 Flags field */
+#define MPI2_SAS_PHY0_FLAGS_SGPIO_DIRECT_ATTACH_ENC             (0x01)
+
+/* use MPI2_SAS_APHYINFO_ defines for AttachedPhyInfo field */
+
+/* use MPI2_SAS_NEG_LINK_RATE_ defines for the NegotiatedLinkRate field */
+
+/* use MPI2_SAS_PHYINFO_ for the PhyInfo field */
+
+
+/* SAS PHY Page 1 */
+
+typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_1
+{
+    MPI2_CONFIG_EXTENDED_PAGE_HEADER    Header;                     /* 0x00 */
+    U32                                 Reserved1;                  /* 0x08 */
+    U32                                 InvalidDwordCount;          /* 0x0C */
+    U32                                 RunningDisparityErrorCount; /* 0x10 */
+    U32                                 LossDwordSynchCount;        /* 0x14 */
+    U32                                 PhyResetProblemCount;       /* 0x18 */
+} MPI2_CONFIG_PAGE_SAS_PHY_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_PHY_1,
+  Mpi2SasPhyPage1_t, MPI2_POINTER pMpi2SasPhyPage1_t;
+
+#define MPI2_SASPHY1_PAGEVERSION            (0x01)
+
+
+/****************************************************************************
+*   SAS Port Config Pages
+****************************************************************************/
+
+/* SAS Port Page 0 */
+
+typedef struct _MPI2_CONFIG_PAGE_SAS_PORT_0
+{
+    MPI2_CONFIG_EXTENDED_PAGE_HEADER    Header;                     /* 0x00 */
+    U8                                  PortNumber;                 /* 0x08 */
+    U8                                  PhysicalPort;               /* 0x09 */
+    U8                                  PortWidth;                  /* 0x0A */
+    U8                                  PhysicalPortWidth;          /* 0x0B */
+    U8                                  ZoneGroup;                  /* 0x0C */
+    U8                                  Reserved1;                  /* 0x0D */
+    U16                                 Reserved2;                  /* 0x0E */
+    U64                                 SASAddress;                 /* 0x10 */
+    U32                                 DeviceInfo;                 /* 0x18 */
+    U32                                 Reserved3;                  /* 0x1C */
+    U32                                 Reserved4;                  /* 0x20 */
+} MPI2_CONFIG_PAGE_SAS_PORT_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_PORT_0,
+  Mpi2SasPortPage0_t, MPI2_POINTER pMpi2SasPortPage0_t;
+
+#define MPI2_SASPORT0_PAGEVERSION           (0x00)
+
+/* see mpi2_sas.h for values for SAS Port Page 0 DeviceInfo values */
+
+
+/****************************************************************************
+*   SAS Enclosure Config Pages
+****************************************************************************/
+
+/* SAS Enclosure Page 0 */
+
+typedef struct _MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0
+{
+    MPI2_CONFIG_EXTENDED_PAGE_HEADER    Header;                     /* 0x00 */
+    U32                                 Reserved1;                  /* 0x08 */
+    U64                                 EnclosureLogicalID;         /* 0x0C */
+    U16                                 Flags;                      /* 0x14 */
+    U16                                 EnclosureHandle;            /* 0x16 */
+    U16                                 NumSlots;                   /* 0x18 */
+    U16                                 StartSlot;                  /* 0x1A */
+    U16                                 Reserved2;                  /* 0x1C */
+    U16                                 SEPDevHandle;               /* 0x1E */
+    U32                                 Reserved3;                  /* 0x20 */
+    U32                                 Reserved4;                  /* 0x24 */
+} MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0,
+  MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0,
+  Mpi2SasEnclosurePage0_t, MPI2_POINTER pMpi2SasEnclosurePage0_t;
+
+#define MPI2_SASENCLOSURE0_PAGEVERSION      (0x03)
+
+/* values for SAS Enclosure Page 0 Flags field */
+#define MPI2_SAS_ENCLS0_FLAGS_MNG_MASK              (0x000F)
+#define MPI2_SAS_ENCLS0_FLAGS_MNG_UNKNOWN           (0x0000)
+#define MPI2_SAS_ENCLS0_FLAGS_MNG_IOC_SES           (0x0001)
+#define MPI2_SAS_ENCLS0_FLAGS_MNG_IOC_SGPIO         (0x0002)
+#define MPI2_SAS_ENCLS0_FLAGS_MNG_EXP_SGPIO         (0x0003)
+#define MPI2_SAS_ENCLS0_FLAGS_MNG_SES_ENCLOSURE     (0x0004)
+#define MPI2_SAS_ENCLS0_FLAGS_MNG_IOC_GPIO          (0x0005)
+
+
+/****************************************************************************
+*   Log Config Page
+****************************************************************************/
+
+/* Log Page 0 */
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check Header.ExtPageLength or NumPhys at runtime.
+ */
+#ifndef MPI2_LOG_0_NUM_LOG_ENTRIES
+#define MPI2_LOG_0_NUM_LOG_ENTRIES          (1)
+#endif
+
+#define MPI2_LOG_0_LOG_DATA_LENGTH          (0x1C)
+
+typedef struct _MPI2_LOG_0_ENTRY
+{
+    U64         TimeStamp;                          /* 0x00 */
+    U32         Reserved1;                          /* 0x08 */
+    U16         LogSequence;                        /* 0x0C */
+    U16         LogEntryQualifier;                  /* 0x0E */
+    U8          VP_ID;                              /* 0x10 */
+    U8          VF_ID;                              /* 0x11 */
+    U16         Reserved2;                          /* 0x12 */
+    U8          LogData[MPI2_LOG_0_LOG_DATA_LENGTH];/* 0x14 */
+} MPI2_LOG_0_ENTRY, MPI2_POINTER PTR_MPI2_LOG_0_ENTRY,
+  Mpi2Log0Entry_t, MPI2_POINTER pMpi2Log0Entry_t;
+
+/* values for Log Page 0 LogEntry LogEntryQualifier field */
+#define MPI2_LOG_0_ENTRY_QUAL_ENTRY_UNUSED          (0x0000)
+#define MPI2_LOG_0_ENTRY_QUAL_POWER_ON_RESET        (0x0001)
+#define MPI2_LOG_0_ENTRY_QUAL_TIMESTAMP_UPDATE      (0x0002)
+#define MPI2_LOG_0_ENTRY_QUAL_MIN_IMPLEMENT_SPEC    (0x8000)
+#define MPI2_LOG_0_ENTRY_QUAL_MAX_IMPLEMENT_SPEC    (0xFFFF)
+
+typedef struct _MPI2_CONFIG_PAGE_LOG_0
+{
+    MPI2_CONFIG_EXTENDED_PAGE_HEADER    Header;                     /* 0x00 */
+    U32                                 Reserved1;                  /* 0x08 */
+    U32                                 Reserved2;                  /* 0x0C */
+    U16                                 NumLogEntries;              /* 0x10 */
+    U16                                 Reserved3;                  /* 0x12 */
+    MPI2_LOG_0_ENTRY                    LogEntry[MPI2_LOG_0_NUM_LOG_ENTRIES]; /* 0x14 */
+} MPI2_CONFIG_PAGE_LOG_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_LOG_0,
+  Mpi2LogPage0_t, MPI2_POINTER pMpi2LogPage0_t;
+
+#define MPI2_LOG_0_PAGEVERSION              (0x02)
+
+
+/****************************************************************************
+*   RAID Config Page
+****************************************************************************/
+
+/* RAID Page 0 */
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check Header.ExtPageLength or NumPhys at runtime.
+ */
+#ifndef MPI2_RAIDCONFIG0_MAX_ELEMENTS
+#define MPI2_RAIDCONFIG0_MAX_ELEMENTS       (1)
+#endif
+
+typedef struct _MPI2_RAIDCONFIG0_CONFIG_ELEMENT
+{
+    U16                     ElementFlags;               /* 0x00 */
+    U16                     VolDevHandle;               /* 0x02 */
+    U8                      HotSparePool;               /* 0x04 */
+    U8                      PhysDiskNum;                /* 0x05 */
+    U16                     PhysDiskDevHandle;          /* 0x06 */
+} MPI2_RAIDCONFIG0_CONFIG_ELEMENT,
+  MPI2_POINTER PTR_MPI2_RAIDCONFIG0_CONFIG_ELEMENT,
+  Mpi2RaidConfig0ConfigElement_t, MPI2_POINTER pMpi2RaidConfig0ConfigElement_t;
+
+/* values for the ElementFlags field */
+#define MPI2_RAIDCONFIG0_EFLAGS_MASK_ELEMENT_TYPE       (0x000F)
+#define MPI2_RAIDCONFIG0_EFLAGS_VOLUME_ELEMENT          (0x0000)
+#define MPI2_RAIDCONFIG0_EFLAGS_VOL_PHYS_DISK_ELEMENT   (0x0001)
+#define MPI2_RAIDCONFIG0_EFLAGS_HOT_SPARE_ELEMENT       (0x0002)
+#define MPI2_RAIDCONFIG0_EFLAGS_OCE_ELEMENT             (0x0003)
+
+
+typedef struct _MPI2_CONFIG_PAGE_RAID_CONFIGURATION_0
+{
+    MPI2_CONFIG_EXTENDED_PAGE_HEADER    Header;                     /* 0x00 */
+    U8                                  NumHotSpares;               /* 0x08 */
+    U8                                  NumPhysDisks;               /* 0x09 */
+    U8                                  NumVolumes;                 /* 0x0A */
+    U8                                  ConfigNum;                  /* 0x0B */
+    U32                                 Flags;                      /* 0x0C */
+    U8                                  ConfigGUID[24];             /* 0x10 */
+    U32                                 Reserved1;                  /* 0x28 */
+    U8                                  NumElements;                /* 0x2C */
+    U8                                  Reserved2;                  /* 0x2D */
+    U16                                 Reserved3;                  /* 0x2E */
+    MPI2_RAIDCONFIG0_CONFIG_ELEMENT     ConfigElement[MPI2_RAIDCONFIG0_MAX_ELEMENTS]; /* 0x30 */
+} MPI2_CONFIG_PAGE_RAID_CONFIGURATION_0,
+  MPI2_POINTER PTR_MPI2_CONFIG_PAGE_RAID_CONFIGURATION_0,
+  Mpi2RaidConfigurationPage0_t, MPI2_POINTER pMpi2RaidConfigurationPage0_t;
+
+#define MPI2_RAIDCONFIG0_PAGEVERSION            (0x00)
+
+/* values for RAID Configuration Page 0 Flags field */
+#define MPI2_RAIDCONFIG0_FLAG_FOREIGN_CONFIG        (0x00000001)
+
+
+/****************************************************************************
+*   Driver Persistent Mapping Config Pages
+****************************************************************************/
+
+/* Driver Persistent Mapping Page 0 */
+
+typedef struct _MPI2_CONFIG_PAGE_DRIVER_MAP0_ENTRY
+{
+    U64                                 PhysicalIdentifier;         /* 0x00 */
+    U16                                 MappingInformation;         /* 0x08 */
+    U16                                 DeviceIndex;                /* 0x0A */
+    U32                                 PhysicalBitsMapping;        /* 0x0C */
+    U32                                 Reserved1;                  /* 0x10 */
+} MPI2_CONFIG_PAGE_DRIVER_MAP0_ENTRY,
+  MPI2_POINTER PTR_MPI2_CONFIG_PAGE_DRIVER_MAP0_ENTRY,
+  Mpi2DriverMap0Entry_t, MPI2_POINTER pMpi2DriverMap0Entry_t;
+
+typedef struct _MPI2_CONFIG_PAGE_DRIVER_MAPPING_0
+{
+    MPI2_CONFIG_EXTENDED_PAGE_HEADER    Header;                     /* 0x00 */
+    MPI2_CONFIG_PAGE_DRIVER_MAP0_ENTRY  Entry;                      /* 0x08 */
+} MPI2_CONFIG_PAGE_DRIVER_MAPPING_0,
+  MPI2_POINTER PTR_MPI2_CONFIG_PAGE_DRIVER_MAPPING_0,
+  Mpi2DriverMappingPage0_t, MPI2_POINTER pMpi2DriverMappingPage0_t;
+
+#define MPI2_DRIVERMAPPING0_PAGEVERSION         (0x00)
+
+/* values for Driver Persistent Mapping Page 0 MappingInformation field */
+#define MPI2_DRVMAP0_MAPINFO_SLOT_MASK              (0x07F0)
+#define MPI2_DRVMAP0_MAPINFO_SLOT_SHIFT             (4)
+#define MPI2_DRVMAP0_MAPINFO_MISSING_MASK           (0x000F)
+
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/sys/scsi/adapters/mpt_sas/mpi/mpi2_init.h	Fri Jun 19 20:12:07 2009 +0800
@@ -0,0 +1,465 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2000 to 2009, LSI Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms of all code within
+ * this file that is exclusively owned by LSI, with or without
+ * modification, is permitted provided that, in addition to the CDDL 1.0
+ * License requirements, the following conditions are met:
+ *
+ *    Neither the name of the author nor the names of its contributors may be
+ *    used to endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ */
+
+/*
+ *           Name:  mpi2_init.h
+ *          Title:  MPI SCSI initiator mode messages and structures
+ *  Creation Date:  June 23, 2006
+ *
+ *    mpi2_init.h Version:  02.00.06
+ *
+ *  Version History
+ *  ---------------
+ *
+ *  Date      Version   Description
+ *  --------  --------  ------------------------------------------------------
+ *  04-30-07  02.00.00  Corresponds to Fusion-MPT MPI Specification Rev A.
+ *  10-31-07  02.00.01  Fixed name for pMpi2SCSITaskManagementRequest_t.
+ *  12-18-07  02.00.02  Modified Task Management Target Reset Method defines.
+ *  02-29-08  02.00.03  Added Query Task Set and Query Unit Attention.
+ *  03-03-08  02.00.04  Fixed name of struct _MPI2_SCSI_TASK_MANAGE_REPLY.
+ *  05-21-08  02.00.05  Fixed typo in name of Mpi2SepRequest_t.
+ *  10-02-08  02.00.06  Removed Untagged and No Disconnect values from SCSI IO
+ *                      Control field Task Attribute flags.
+ *                      Moved LUN field defines to mpi2.h becasue they are
+ *                      common to many structures.
+ *  --------------------------------------------------------------------------
+ */
+
+#ifndef MPI2_INIT_H
+#define MPI2_INIT_H
+
+/*****************************************************************************
+*
+*               SCSI Initiator Messages
+*
+*****************************************************************************/
+
+/****************************************************************************
+*  SCSI IO messages and associated structures
+****************************************************************************/
+
+typedef struct
+{
+    U8                      CDB[20];                    /* 0x00 */
+    U32                     PrimaryReferenceTag;        /* 0x14 */
+    U16                     PrimaryApplicationTag;      /* 0x18 */
+    U16                     PrimaryApplicationTagMask;  /* 0x1A */
+    U32                     TransferLength;             /* 0x1C */
+} MPI2_SCSI_IO_CDB_EEDP32, MPI2_POINTER PTR_MPI2_SCSI_IO_CDB_EEDP32,
+  Mpi2ScsiIoCdbEedp32_t, MPI2_POINTER pMpi2ScsiIoCdbEedp32_t;
+
+/* TBD: I don't think this is needed for MPI2/Gen2 */
+#if 0
+typedef struct
+{
+    U8                      CDB[16];                    /* 0x00 */
+    U32                     DataLength;                 /* 0x10 */
+    U32                     PrimaryReferenceTag;        /* 0x14 */
+    U16                     PrimaryApplicationTag;      /* 0x18 */
+    U16                     PrimaryApplicationTagMask;  /* 0x1A */
+    U32                     TransferLength;             /* 0x1C */
+} MPI2_SCSI_IO32_CDB_EEDP16, MPI2_POINTER PTR_MPI2_SCSI_IO32_CDB_EEDP16,
+  Mpi2ScsiIo32CdbEedp16_t, MPI2_POINTER pMpi2ScsiIo32CdbEedp16_t;
+#endif
+
+typedef union
+{
+    U8                      CDB32[32];
+    MPI2_SCSI_IO_CDB_EEDP32 EEDP32;
+    MPI2_SGE_SIMPLE_UNION   SGE;
+} MPI2_SCSI_IO_CDB_UNION, MPI2_POINTER PTR_MPI2_SCSI_IO_CDB_UNION,
+  Mpi2ScsiIoCdb_t, MPI2_POINTER pMpi2ScsiIoCdb_t;
+
+/* SCSI IO Request Message */
+typedef struct _MPI2_SCSI_IO_REQUEST
+{
+    U16                     DevHandle;                      /* 0x00 */
+    U8                      ChainOffset;                    /* 0x02 */
+    U8                      Function;                       /* 0x03 */
+    U16                     Reserved1;                      /* 0x04 */
+    U8                      Reserved2;                      /* 0x06 */
+    U8                      MsgFlags;                       /* 0x07 */
+    U8                      VP_ID;                          /* 0x08 */
+    U8                      VF_ID;                          /* 0x09 */
+    U16                     Reserved3;                      /* 0x0A */
+    U32                     SenseBufferLowAddress;          /* 0x0C */
+    U16                     SGLFlags;                       /* 0x10 */
+    U8                      SenseBufferLength;              /* 0x12 */
+    U8                      Reserved4;                      /* 0x13 */
+    U8                      SGLOffset0;                     /* 0x14 */
+    U8                      SGLOffset1;                     /* 0x15 */
+    U8                      SGLOffset2;                     /* 0x16 */
+    U8                      SGLOffset3;                     /* 0x17 */
+    U32                     SkipCount;                      /* 0x18 */
+    U32                     DataLength;                     /* 0x1C */
+    U32                     BidirectionalDataLength;        /* 0x20 */
+    U16                     IoFlags;                        /* 0x24 */
+    U16                     EEDPFlags;                      /* 0x26 */
+    U32                     EEDPBlockSize;                  /* 0x28 */
+    U32                     SecondaryReferenceTag;          /* 0x2C */
+    U16                     SecondaryApplicationTag;        /* 0x30 */
+    U16                     ApplicationTagTranslationMask;  /* 0x32 */
+    U8                      LUN[8];                         /* 0x34 */
+    U32                     Control;                        /* 0x3C */
+    MPI2_SCSI_IO_CDB_UNION  CDB;                            /* 0x40 */
+    MPI2_SGE_IO_UNION       SGL;                            /* 0x60 */
+} MPI2_SCSI_IO_REQUEST, MPI2_POINTER PTR_MPI2_SCSI_IO_REQUEST,
+  Mpi2SCSIIORequest_t, MPI2_POINTER pMpi2SCSIIORequest_t;
+
+/* SCSI IO MsgFlags bits */
+
+/* MsgFlags for SenseBufferAddressSpace */
+#define MPI2_SCSIIO_MSGFLAGS_MASK_SENSE_ADDR        (0x0C)
+#define MPI2_SCSIIO_MSGFLAGS_SYSTEM_SENSE_ADDR      (0x00)
+#define MPI2_SCSIIO_MSGFLAGS_IOCDDR_SENSE_ADDR      (0x04)
+#define MPI2_SCSIIO_MSGFLAGS_IOCPLB_SENSE_ADDR      (0x08)
+#define MPI2_SCSIIO_MSGFLAGS_IOCPLBNTA_SENSE_ADDR   (0x0C)
+
+/* SCSI IO SGLFlags bits */
+
+/* base values for Data Location Address Space */
+#define MPI2_SCSIIO_SGLFLAGS_ADDR_MASK              (0x0C)
+#define MPI2_SCSIIO_SGLFLAGS_SYSTEM_ADDR            (0x00)
+#define MPI2_SCSIIO_SGLFLAGS_IOCDDR_ADDR            (0x04)
+#define MPI2_SCSIIO_SGLFLAGS_IOCPLB_ADDR            (0x08)
+#define MPI2_SCSIIO_SGLFLAGS_IOCPLBNTA_ADDR         (0x0C)
+
+/* base values for Type */
+#define MPI2_SCSIIO_SGLFLAGS_TYPE_MASK              (0x03)
+#define MPI2_SCSIIO_SGLFLAGS_TYPE_MPI               (0x00)
+#define MPI2_SCSIIO_SGLFLAGS_TYPE_IEEE32            (0x01)
+#define MPI2_SCSIIO_SGLFLAGS_TYPE_IEEE64            (0x02)
+
+/* shift values for each sub-field */
+#define MPI2_SCSIIO_SGLFLAGS_SGL3_SHIFT             (12)
+#define MPI2_SCSIIO_SGLFLAGS_SGL2_SHIFT             (8)
+#define MPI2_SCSIIO_SGLFLAGS_SGL1_SHIFT             (4)
+#define MPI2_SCSIIO_SGLFLAGS_SGL0_SHIFT             (0)
+
+/* SCSI IO IoFlags bits */
+
+/* Large CDB Address Space */
+#define MPI2_SCSIIO_CDB_ADDR_MASK                   (0x6000)
+#define MPI2_SCSIIO_CDB_ADDR_SYSTEM                 (0x0000)
+#define MPI2_SCSIIO_CDB_ADDR_IOCDDR                 (0x2000)
+#define MPI2_SCSIIO_CDB_ADDR_IOCPLB                 (0x4000)
+#define MPI2_SCSIIO_CDB_ADDR_IOCPLBNTA              (0x6000)
+
+#define MPI2_SCSIIO_IOFLAGS_LARGE_CDB               (0x1000)
+#define MPI2_SCSIIO_IOFLAGS_BIDIRECTIONAL           (0x0800)
+#define MPI2_SCSIIO_IOFLAGS_MULTICAST               (0x0400)
+#define MPI2_SCSIIO_IOFLAGS_CMD_DETERMINES_DATA_DIR (0x0200)
+#define MPI2_SCSIIO_IOFLAGS_CDBLENGTH_MASK          (0x01FF)
+
+/* SCSI IO EEDPFlags bits */
+
+#define MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG        (0x8000)
+#define MPI2_SCSIIO_EEDPFLAGS_INC_SEC_REFTAG        (0x4000)
+#define MPI2_SCSIIO_EEDPFLAGS_INC_PRI_APPTAG        (0x2000)
+#define MPI2_SCSIIO_EEDPFLAGS_INC_SEC_APPTAG        (0x1000)
+
+#define MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG          (0x0400)
+#define MPI2_SCSIIO_EEDPFLAGS_CHECK_APPTAG          (0x0200)
+#define MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD           (0x0100)
+
+#define MPI2_SCSIIO_EEDPFLAGS_PASSTHRU_REFTAG       (0x0008)
+
+#define MPI2_SCSIIO_EEDPFLAGS_MASK_OP               (0x0007)
+#define MPI2_SCSIIO_EEDPFLAGS_NOOP_OP               (0x0000)
+#define MPI2_SCSIIO_EEDPFLAGS_CHECK_OP              (0x0001)
+#define MPI2_SCSIIO_EEDPFLAGS_STRIP_OP              (0x0002)
+#define MPI2_SCSIIO_EEDPFLAGS_CHECK_REMOVE_OP       (0x0003)
+#define MPI2_SCSIIO_EEDPFLAGS_INSERT_OP             (0x0004)
+#define MPI2_SCSIIO_EEDPFLAGS_REPLACE_OP            (0x0006)
+#define MPI2_SCSIIO_EEDPFLAGS_CHECK_REGEN_OP        (0x0007)
+
+/* SCSI IO LUN fields: use MPI2_LUN_ from mpi2.h */
+
+/* SCSI IO Control bits */
+#define MPI2_SCSIIO_CONTROL_ADDCDBLEN_MASK      (0xFC000000)
+#define MPI2_SCSIIO_CONTROL_ADDCDBLEN_SHIFT     (26)
+
+#define MPI2_SCSIIO_CONTROL_DATADIRECTION_MASK  (0x03000000)
+#define MPI2_SCSIIO_CONTROL_NODATATRANSFER      (0x00000000)
+#define MPI2_SCSIIO_CONTROL_WRITE               (0x01000000)
+#define MPI2_SCSIIO_CONTROL_READ                (0x02000000)
+#define MPI2_SCSIIO_CONTROL_BIDIRECTIONAL       (0x03000000)
+
+#define MPI2_SCSIIO_CONTROL_TASKPRI_MASK        (0x00007800)
+#define MPI2_SCSIIO_CONTROL_TASKPRI_SHIFT       (11)
+
+#define MPI2_SCSIIO_CONTROL_TASKATTRIBUTE_MASK  (0x00000700)
+#define MPI2_SCSIIO_CONTROL_SIMPLEQ             (0x00000000)
+#define MPI2_SCSIIO_CONTROL_HEADOFQ             (0x00000100)
+#define MPI2_SCSIIO_CONTROL_ORDEREDQ            (0x00000200)
+#define MPI2_SCSIIO_CONTROL_ACAQ                (0x00000400)
+
+#define MPI2_SCSIIO_CONTROL_TLR_MASK            (0x000000C0)
+#define MPI2_SCSIIO_CONTROL_NO_TLR              (0x00000000)
+#define MPI2_SCSIIO_CONTROL_TLR_ON              (0x00000040)
+#define MPI2_SCSIIO_CONTROL_TLR_OFF             (0x00000080)
+
+
+/* SCSI IO Error Reply Message */
+typedef struct _MPI2_SCSI_IO_REPLY
+{
+    U16                     DevHandle;                      /* 0x00 */
+    U8                      MsgLength;                      /* 0x02 */
+    U8                      Function;                       /* 0x03 */
+    U16                     Reserved1;                      /* 0x04 */
+    U8                      Reserved2;                      /* 0x06 */
+    U8                      MsgFlags;                       /* 0x07 */
+    U8                      VP_ID;                          /* 0x08 */
+    U8                      VF_ID;                          /* 0x09 */
+    U16                     Reserved3;                      /* 0x0A */
+    U8                      SCSIStatus;                     /* 0x0C */
+    U8                      SCSIState;                      /* 0x0D */
+    U16                     IOCStatus;                      /* 0x0E */
+    U32                     IOCLogInfo;                     /* 0x10 */
+    U32                     TransferCount;                  /* 0x14 */
+    U32                     SenseCount;                     /* 0x18 */
+    U32                     ResponseInfo;                   /* 0x1C */
+    U16                     TaskTag;                        /* 0x20 */
+    U16                     Reserved4;                      /* 0x22 */
+    U32                     BidirectionalTransferCount;     /* 0x24 */
+    U32                     Reserved5;                      /* 0x28 */
+    U32                     Reserved6;                      /* 0x2C */
+} MPI2_SCSI_IO_REPLY, MPI2_POINTER PTR_MPI2_SCSI_IO_REPLY,
+  Mpi2SCSIIOReply_t, MPI2_POINTER pMpi2SCSIIOReply_t;
+
+/* SCSI IO Reply SCSIStatus values (SAM-4 status codes) */
+
+#define MPI2_SCSI_STATUS_GOOD                   (0x00)
+#define MPI2_SCSI_STATUS_CHECK_CONDITION        (0x02)
+#define MPI2_SCSI_STATUS_CONDITION_MET          (0x04)
+#define MPI2_SCSI_STATUS_BUSY                   (0x08)
+#define MPI2_SCSI_STATUS_INTERMEDIATE           (0x10)
+#define MPI2_SCSI_STATUS_INTERMEDIATE_CONDMET   (0x14)
+#define MPI2_SCSI_STATUS_RESERVATION_CONFLICT   (0x18)
+#define MPI2_SCSI_STATUS_COMMAND_TERMINATED     (0x22) /* obsolete */
+#define MPI2_SCSI_STATUS_TASK_SET_FULL          (0x28)
+#define MPI2_SCSI_STATUS_ACA_ACTIVE             (0x30)
+#define MPI2_SCSI_STATUS_TASK_ABORTED           (0x40)
+
+/* SCSI IO Reply SCSIState flags */
+
+#define MPI2_SCSI_STATE_RESPONSE_INFO_VALID     (0x10)
+#define MPI2_SCSI_STATE_TERMINATED              (0x08)
+#define MPI2_SCSI_STATE_NO_SCSI_STATUS          (0x04)
+#define MPI2_SCSI_STATE_AUTOSENSE_FAILED        (0x02)
+#define MPI2_SCSI_STATE_AUTOSENSE_VALID         (0x01)
+
+#define MPI2_SCSI_TASKTAG_UNKNOWN               (0xFFFF)
+
+
+/****************************************************************************
+*  SCSI Task Management messages
+****************************************************************************/
+
+/* SCSI Task Management Request Message */
+typedef struct _MPI2_SCSI_TASK_MANAGE_REQUEST
+{
+    U16                     DevHandle;                      /* 0x00 */
+    U8                      ChainOffset;                    /* 0x02 */
+    U8                      Function;                       /* 0x03 */
+    U8                      Reserved1;                      /* 0x04 */
+    U8                      TaskType;                       /* 0x05 */
+    U8                      Reserved2;                      /* 0x06 */
+    U8                      MsgFlags;                       /* 0x07 */
+    U8                      VP_ID;                          /* 0x08 */
+    U8                      VF_ID;                          /* 0x09 */
+    U16                     Reserved3;                      /* 0x0A */
+    U8                      LUN[8];                         /* 0x0C */
+    U32                     Reserved4[7];                   /* 0x14 */
+    U16                     TaskMID;                        /* 0x30 */
+    U16                     Reserved5;                      /* 0x32 */
+} MPI2_SCSI_TASK_MANAGE_REQUEST,
+  MPI2_POINTER PTR_MPI2_SCSI_TASK_MANAGE_REQUEST,
+  Mpi2SCSITaskManagementRequest_t,
+  MPI2_POINTER pMpi2SCSITaskManagementRequest_t;
+
+/* TaskType values */
+
+#define MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK           (0x01)
+#define MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET        (0x02)
+#define MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET         (0x03)
+#define MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET   (0x05)
+#define MPI2_SCSITASKMGMT_TASKTYPE_CLEAR_TASK_SET       (0x06)
+#define MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK           (0x07)
+#define MPI2_SCSITASKMGMT_TASKTYPE_CLR_ACA              (0x08)
+#define MPI2_SCSITASKMGMT_TASKTYPE_QRY_TASK_SET         (0x09)
+#define MPI2_SCSITASKMGMT_TASKTYPE_QRY_UNIT_ATTENTION   (0x0A)
+
+/* MsgFlags bits */
+
+#define MPI2_SCSITASKMGMT_MSGFLAGS_MASK_TARGET_RESET    (0x18)
+#define MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET           (0x00)
+#define MPI2_SCSITASKMGMT_MSGFLAGS_NEXUS_RESET_SRST     (0x08)
+#define MPI2_SCSITASKMGMT_MSGFLAGS_SAS_HARD_LINK_RESET  (0x10)
+
+#define MPI2_SCSITASKMGMT_MSGFLAGS_DO_NOT_SEND_TASK_IU  (0x01)
+
+
+
+/* SCSI Task Management Reply Message */
+typedef struct _MPI2_SCSI_TASK_MANAGE_REPLY
+{
+    U16                     DevHandle;                      /* 0x00 */
+    U8                      MsgLength;                      /* 0x02 */
+    U8                      Function;                       /* 0x03 */
+    U8                      ResponseCode;                   /* 0x04 */
+    U8                      TaskType;                       /* 0x05 */
+    U8                      Reserved1;                      /* 0x06 */
+    U8                      MsgFlags;                       /* 0x07 */
+    U8                      VP_ID;                          /* 0x08 */
+    U8                      VF_ID;                          /* 0x09 */
+    U16                     Reserved2;                      /* 0x0A */
+    U16                     Reserved3;                      /* 0x0C */
+    U16                     IOCStatus;                      /* 0x0E */
+    U32                     IOCLogInfo;                     /* 0x10 */
+    U32                     TerminationCount;               /* 0x14 */
+} MPI2_SCSI_TASK_MANAGE_REPLY,
+  MPI2_POINTER PTR_MPI2_SCSI_TASK_MANAGE_REPLY,
+  Mpi2SCSITaskManagementReply_t, MPI2_POINTER pMpi2SCSIManagementReply_t;
+
+/* ResponseCode values */
+
+#define MPI2_SCSITASKMGMT_RSP_TM_COMPLETE               (0x00)
+#define MPI2_SCSITASKMGMT_RSP_INVALID_FRAME             (0x02)
+#define MPI2_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED          (0x04)
+#define MPI2_SCSITASKMGMT_RSP_TM_FAILED                 (0x05)
+#define MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED              (0x08)
+#define MPI2_SCSITASKMGMT_RSP_TM_INVALID_LUN            (0x09)
+#define MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC          (0x80)
+
+
+/****************************************************************************
+*  SCSI Enclosure Processor messages
+****************************************************************************/
+
+/* SCSI Enclosure Processor Request Message */
+typedef struct _MPI2_SEP_REQUEST
+{
+    U16                     DevHandle;          /* 0x00 */
+    U8                      ChainOffset;        /* 0x02 */
+    U8                      Function;           /* 0x03 */
+    U8                      Action;             /* 0x04 */
+    U8                      Flags;              /* 0x05 */
+    U8                      Reserved1;          /* 0x06 */
+    U8                      MsgFlags;           /* 0x07 */
+    U8                      VP_ID;              /* 0x08 */
+    U8                      VF_ID;              /* 0x09 */
+    U16                     Reserved2;          /* 0x0A */
+    U32                     SlotStatus;         /* 0x0C */
+    U32                     Reserved3;          /* 0x10 */
+    U32                     Reserved4;          /* 0x14 */
+    U32                     Reserved5;          /* 0x18 */
+    U16                     Slot;               /* 0x1C */
+    U16                     EnclosureHandle;    /* 0x1E */
+} MPI2_SEP_REQUEST, MPI2_POINTER PTR_MPI2_SEP_REQUEST,
+  Mpi2SepRequest_t, MPI2_POINTER pMpi2SepRequest_t;
+
+/* Action defines */
+#define MPI2_SEP_REQ_ACTION_WRITE_STATUS                (0x00)
+#define MPI2_SEP_REQ_ACTION_READ_STATUS                 (0x01)
+
+/* Flags defines */
+#define MPI2_SEP_REQ_FLAGS_DEVHANDLE_ADDRESS            (0x00)
+#define MPI2_SEP_REQ_FLAGS_ENCLOSURE_SLOT_ADDRESS       (0x01)
+
+/* SlotStatus defines */
+#define MPI2_SEP_REQ_SLOTSTATUS_REQUEST_REMOVE          (0x00040000)
+#define MPI2_SEP_REQ_SLOTSTATUS_IDENTIFY_REQUEST        (0x00020000)
+#define MPI2_SEP_REQ_SLOTSTATUS_REBUILD_STOPPED         (0x00000200)
+#define MPI2_SEP_REQ_SLOTSTATUS_HOT_SPARE               (0x00000100)
+#define MPI2_SEP_REQ_SLOTSTATUS_UNCONFIGURED            (0x00000080)
+#define MPI2_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT         (0x00000040)
+#define MPI2_SEP_REQ_SLOTSTATUS_DEV_REBUILDING          (0x00000004)
+#define MPI2_SEP_REQ_SLOTSTATUS_DEV_FAULTY              (0x00000002)
+#define MPI2_SEP_REQ_SLOTSTATUS_NO_ERROR                (0x00000001)
+
+
+/* SCSI Enclosure Processor Reply Message */
+typedef struct _MPI2_SEP_REPLY
+{
+    U16                     DevHandle;          /* 0x00 */
+    U8                      MsgLength;          /* 0x02 */
+    U8                      Function;           /* 0x03 */
+    U8                      Action;             /* 0x04 */
+    U8                      Flags;              /* 0x05 */
+    U8                      Reserved1;          /* 0x06 */
+    U8                      MsgFlags;           /* 0x07 */
+    U8                      VP_ID;              /* 0x08 */
+    U8                      VF_ID;              /* 0x09 */
+    U16                     Reserved2;          /* 0x0A */
+    U16                     Reserved3;          /* 0x0C */
+    U16                     IOCStatus;          /* 0x0E */
+    U32                     IOCLogInfo;         /* 0x10 */
+    U32                     SlotStatus;         /* 0x14 */
+    U32                     Reserved4;          /* 0x18 */
+    U16                     Slot;               /* 0x1C */
+    U16                     EnclosureHandle;    /* 0x1E */
+} MPI2_SEP_REPLY, MPI2_POINTER PTR_MPI2_SEP_REPLY,
+  Mpi2SepReply_t, MPI2_POINTER pMpi2SepReply_t;
+
+/* SlotStatus defines */
+#define MPI2_SEP_REPLY_SLOTSTATUS_REMOVE_READY          (0x00040000)
+#define MPI2_SEP_REPLY_SLOTSTATUS_IDENTIFY_REQUEST      (0x00020000)
+#define MPI2_SEP_REPLY_SLOTSTATUS_REBUILD_STOPPED       (0x00000200)
+#define MPI2_SEP_REPLY_SLOTSTATUS_HOT_SPARE             (0x00000100)
+#define MPI2_SEP_REPLY_SLOTSTATUS_UNCONFIGURED          (0x00000080)
+#define MPI2_SEP_REPLY_SLOTSTATUS_PREDICTED_FAULT       (0x00000040)
+#define MPI2_SEP_REPLY_SLOTSTATUS_DEV_REBUILDING        (0x00000004)
+#define MPI2_SEP_REPLY_SLOTSTATUS_DEV_FAULTY            (0x00000002)
+#define MPI2_SEP_REPLY_SLOTSTATUS_NO_ERROR              (0x00000001)
+
+
+#endif
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/sys/scsi/adapters/mpt_sas/mpi/mpi2_ioc.h	Fri Jun 19 20:12:07 2009 +0800
@@ -0,0 +1,1340 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2000 to 2009, LSI Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms of all code within
+ * this file that is exclusively owned by LSI, with or without
+ * modification, is permitted provided that, in addition to the CDDL 1.0 
+ * License requirements, the following conditions are met:
+ *
+ *    Neither the name of the author nor the names of its contributors may be
+ *    used to endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ */
+
+/*
+ *           Name:  mpi2_ioc.h
+ *          Title:  MPI IOC, Port, Event, FW Download, and FW Upload messages
+ *  Creation Date:  October 11, 2006
+ *
+ *  mpi2_ioc.h Version:  02.00.10
+ *
+ *  Version History
+ *  ---------------
+ *
+ *  Date      Version   Description
+ *  --------  --------  ------------------------------------------------------
+ *  04-30-07  02.00.00  Corresponds to Fusion-MPT MPI Specification Rev A.
+ *  06-04-07  02.00.01  In IOCFacts Reply structure, renamed MaxDevices to
+ *                      MaxTargets.
+ *                      Added TotalImageSize field to FWDownload Request.
+ *                      Added reserved words to FWUpload Request.
+ *  06-26-07  02.00.02  Added IR Configuration Change List Event.
+ *  08-31-07  02.00.03  Removed SystemReplyQueueDepth field from the IOCInit
+ *                      request and replaced it with
+ *                      ReplyDescriptorPostQueueDepth and ReplyFreeQueueDepth.
+ *                      Replaced the MinReplyQueueDepth field of the IOCFacts
+ *                      reply with MaxReplyDescriptorPostQueueDepth.
+ *                      Added MPI2_RDPQ_DEPTH_MIN define to specify the minimum
+ *                      depth for the Reply Descriptor Post Queue.
+ *                      Added SASAddress field to Initiator Device Table
+ *                      Overflow Event data.
+ *  10-31-07  02.00.04  Added ReasonCode MPI2_EVENT_SAS_INIT_RC_NOT_RESPONDING
+ *                      for SAS Initiator Device Status Change Event data.
+ *                      Modified Reason Code defines for SAS Topology Change
+ *                      List Event data, including adding a bit for PHY Vacant
+ *                      status, and adding a mask for the Reason Code.
+ *                      Added define for
+ *                      MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING.
+ *                      Added define for MPI2_EXT_IMAGE_TYPE_MEGARAID.
+ *  12-18-07  02.00.05  Added Boot Status defines for the IOCExceptions field of
+ *                      the IOCFacts Reply.
+ *                      Removed MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER define.
+ *                      Moved MPI2_VERSION_UNION to mpi2.h.
+ *                      Changed MPI2_EVENT_NOTIFICATION_REQUEST to use masks
+ *                      instead of enables, and added SASBroadcastPrimitiveMasks
+ *                      field.
+ *                      Added Log Entry Added Event and related structure.
+ *  02-29-08  02.00.06  Added define MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID.
+ *                      Removed define MPI2_IOCFACTS_PROTOCOL_SMP_TARGET.
+ *                      Added MaxVolumes and MaxPersistentEntries fields to
+ *                      IOCFacts reply.
+ *                      Added ProtocalFlags and IOCCapabilities fields to
+ *                      MPI2_FW_IMAGE_HEADER.
+ *                      Removed MPI2_PORTENABLE_FLAGS_ENABLE_SINGLE_PORT.
+ *  03-03-08  02.00.07  Fixed MPI2_FW_IMAGE_HEADER by changing Reserved26 to
+ *                      a U16 (from a U32).
+ *                      Removed extra 's' from EventMasks name.
+ *  06-27-08  02.00.08  Fixed an offset in a comment.
+ *  10-02-08  02.00.09  Removed SystemReplyFrameSize from MPI2_IOC_INIT_REQUEST.
+ *                      Removed CurReplyFrameSize from MPI2_IOC_FACTS_REPLY and
+ *                      renamed MinReplyFrameSize to ReplyFrameSize.
+ *                      Added MPI2_IOCFACTS_EXCEPT_IR_FOREIGN_CONFIG_MAX.
+ *                      Added two new RAIDOperation values for Integrated RAID
+ *                      Operations Status Event data.
+ *                      Added four new IR Configuration Change List Event data
+ *                      ReasonCode values.
+ *                      Added two new ReasonCode defines for SAS Device Status
+ *                      Change Event data.
+ *                      Added three new DiscoveryStatus bits for the SAS
+ *                      Discovery event data.
+ *                      Added Multiplexing Status Change bit to the PhyStatus
+ *                      field of the SAS Topology Change List event data.
+ *                      Removed define for MPI2_INIT_IMAGE_BOOTFLAGS_XMEMCOPY.
+ *                      BootFlags are now product-specific.
+ *                      Added defines for the indivdual signature bytes
+ *                      for MPI2_INIT_IMAGE_FOOTER.
+ *  01-19-09  02.00.10  Added MPI2_IOCFACTS_CAPABILITY_EVENT_REPLAY define.
+ *                      Added MPI2_EVENT_SAS_DISC_DS_DOWNSTREAM_INITIATOR
+ *                      define.
+ *                      Added MPI2_EVENT_SAS_DEV_STAT_RC_SATA_INIT_FAILURE
+ *                      define.
+ *                      Removed MPI2_EVENT_SAS_DISC_DS_SATA_INIT_FAILURE define.
+ *  --------------------------------------------------------------------------
+ */
+
+#ifndef MPI2_IOC_H
+#define MPI2_IOC_H
+
+/*****************************************************************************
+*
+*               IOC Messages
+*
+*****************************************************************************/
+
+/****************************************************************************
+*  IOCInit message
+****************************************************************************/
+
+/* IOCInit Request message */
+typedef struct _MPI2_IOC_INIT_REQUEST
+{
+    U8                      WhoInit;                        /* 0x00 */
+    U8                      Reserved1;                      /* 0x01 */
+    U8                      ChainOffset;                    /* 0x02 */
+    U8                      Function;                       /* 0x03 */
+    U16                     Reserved2;                      /* 0x04 */
+    U8                      Reserved3;                      /* 0x06 */
+    U8                      MsgFlags;                       /* 0x07 */
+    U8                      VP_ID;                          /* 0x08 */
+    U8                      VF_ID;                          /* 0x09 */
+    U16                     Reserved4;                      /* 0x0A */
+    U16                     MsgVersion;                     /* 0x0C */
+    U16                     HeaderVersion;                  /* 0x0E */
+    U32                     Reserved5;                      /* 0x10 */
+    U32                     Reserved6;                      /* 0x14 */
+    U16                     Reserved7;                      /* 0x18 */
+    U16                     SystemRequestFrameSize;         /* 0x1A */
+    U16                     ReplyDescriptorPostQueueDepth;  /* 0x1C */
+    U16                     ReplyFreeQueueDepth;            /* 0x1E */
+    U32                     SenseBufferAddressHigh;         /* 0x20 */
+    U32                     SystemReplyAddressHigh;         /* 0x24 */
+    U64                     SystemRequestFrameBaseAddress;  /* 0x28 */
+    U64                     ReplyDescriptorPostQueueAddress;/* 0x30 */
+    U64                     ReplyFreeQueueAddress;          /* 0x38 */
+    U64                     TimeStamp;                      /* 0x40 */
+} MPI2_IOC_INIT_REQUEST, MPI2_POINTER PTR_MPI2_IOC_INIT_REQUEST,
+  Mpi2IOCInitRequest_t, MPI2_POINTER pMpi2IOCInitRequest_t;
+
+/* WhoInit values */
+#define MPI2_WHOINIT_NOT_INITIALIZED            (0x00)
+#define MPI2_WHOINIT_SYSTEM_BIOS                (0x01)
+#define MPI2_WHOINIT_ROM_BIOS                   (0x02)
+#define MPI2_WHOINIT_PCI_PEER                   (0x03)
+#define MPI2_WHOINIT_HOST_DRIVER                (0x04)
+#define MPI2_WHOINIT_MANUFACTURER               (0x05)
+
+/* MsgVersion */
+#define MPI2_IOCINIT_MSGVERSION_MAJOR_MASK      (0xFF00)
+#define MPI2_IOCINIT_MSGVERSION_MAJOR_SHIFT     (8)
+#define MPI2_IOCINIT_MSGVERSION_MINOR_MASK      (0x00FF)
+#define MPI2_IOCINIT_MSGVERSION_MINOR_SHIFT     (0)
+
+/* HeaderVersion */
+#define MPI2_IOCINIT_HDRVERSION_UNIT_MASK       (0xFF00)
+#define MPI2_IOCINIT_HDRVERSION_UNIT_SHIFT      (8)
+#define MPI2_IOCINIT_HDRVERSION_DEV_MASK        (0x00FF)
+#define MPI2_IOCINIT_HDRVERSION_DEV_SHIFT       (0)
+
+/* minimum depth for the Reply Descriptor Post Queue */
+#define MPI2_RDPQ_DEPTH_MIN                     (16)
+
+
+/* IOCInit Reply message */
+typedef struct _MPI2_IOC_INIT_REPLY
+{
+    U8                      WhoInit;                        /* 0x00 */
+    U8                      Reserved1;                      /* 0x01 */
+    U8                      MsgLength;                      /* 0x02 */
+    U8                      Function;                       /* 0x03 */
+    U16                     Reserved2;                      /* 0x04 */
+    U8                      Reserved3;                      /* 0x06 */
+    U8                      MsgFlags;                       /* 0x07 */
+    U8                      VP_ID;                          /* 0x08 */
+    U8                      VF_ID;                          /* 0x09 */
+    U16                     Reserved4;                      /* 0x0A */
+    U16                     Reserved5;                      /* 0x0C */
+    U16                     IOCStatus;                      /* 0x0E */
+    U32                     IOCLogInfo;                     /* 0x10 */
+} MPI2_IOC_INIT_REPLY, MPI2_POINTER PTR_MPI2_IOC_INIT_REPLY,
+  Mpi2IOCInitReply_t, MPI2_POINTER pMpi2IOCInitReply_t;
+
+
+/****************************************************************************
+*  IOCFacts message
+****************************************************************************/
+
+/* IOCFacts Request message */
+typedef struct _MPI2_IOC_FACTS_REQUEST
+{
+    U16                     Reserved1;                      /* 0x00 */
+    U8                      ChainOffset;                    /* 0x02 */
+    U8                      Function;                       /* 0x03 */
+    U16                     Reserved2;                      /* 0x04 */
+    U8                      Reserved3;                      /* 0x06 */
+    U8                      MsgFlags;                       /* 0x07 */
+    U8                      VP_ID;                          /* 0x08 */
+    U8                      VF_ID;                          /* 0x09 */
+    U16                     Reserved4;                      /* 0x0A */
+} MPI2_IOC_FACTS_REQUEST, MPI2_POINTER PTR_MPI2_IOC_FACTS_REQUEST,
+  Mpi2IOCFactsRequest_t, MPI2_POINTER pMpi2IOCFactsRequest_t;
+
+
+/* IOCFacts Reply message */
+typedef struct _MPI2_IOC_FACTS_REPLY
+{
+    U16                     MsgVersion;                     /* 0x00 */
+    U8                      MsgLength;                      /* 0x02 */
+    U8                      Function;                       /* 0x03 */
+    U16                     HeaderVersion;                  /* 0x04 */
+    U8                      IOCNumber;                      /* 0x06 */
+    U8                      MsgFlags;                       /* 0x07 */
+    U8                      VP_ID;                          /* 0x08 */
+    U8                      VF_ID;                          /* 0x09 */
+    U16                     Reserved1;                      /* 0x0A */
+    U16                     IOCExceptions;                  /* 0x0C */
+    U16                     IOCStatus;                      /* 0x0E */
+    U32                     IOCLogInfo;                     /* 0x10 */
+    U8                      MaxChainDepth;                  /* 0x14 */
+    U8                      WhoInit;                        /* 0x15 */
+    U8                      NumberOfPorts;                  /* 0x16 */
+    U8                      Reserved2;                      /* 0x17 */
+    U16                     RequestCredit;                  /* 0x18 */
+    U16                     ProductID;                      /* 0x1A */
+    U32                     IOCCapabilities;                /* 0x1C */
+    MPI2_VERSION_UNION      FWVersion;                      /* 0x20 */
+    U16                     IOCRequestFrameSize;            /* 0x24 */
+    U16                     Reserved3;                      /* 0x26 */
+    U16                     MaxInitiators;                  /* 0x28 */
+    U16                     MaxTargets;                     /* 0x2A */
+    U16                     MaxSasExpanders;                /* 0x2C */
+    U16                     MaxEnclosures;                  /* 0x2E */
+    U16                     ProtocolFlags;                  /* 0x30 */
+    U16                     HighPriorityCredit;             /* 0x32 */
+    U16                     MaxReplyDescriptorPostQueueDepth; /* 0x34 */
+    U8                      ReplyFrameSize;                 /* 0x36 */
+    U8                      MaxVolumes;                     /* 0x37 */
+    U16                     MaxDevHandle;                   /* 0x38 */
+    U16                     MaxPersistentEntries;           /* 0x3A */
+    U32                     Reserved4;                      /* 0x3C */
+} MPI2_IOC_FACTS_REPLY, MPI2_POINTER PTR_MPI2_IOC_FACTS_REPLY,
+  Mpi2IOCFactsReply_t, MPI2_POINTER pMpi2IOCFactsReply_t;
+
+/* MsgVersion */
+#define MPI2_IOCFACTS_MSGVERSION_MAJOR_MASK             (0xFF00)
+#define MPI2_IOCFACTS_MSGVERSION_MAJOR_SHIFT            (8)
+#define MPI2_IOCFACTS_MSGVERSION_MINOR_MASK             (0x00FF)
+#define MPI2_IOCFACTS_MSGVERSION_MINOR_SHIFT            (0)
+
+/* HeaderVersion */
+#define MPI2_IOCFACTS_HDRVERSION_UNIT_MASK              (0xFF00)
+#define MPI2_IOCFACTS_HDRVERSION_UNIT_SHIFT             (8)
+#define MPI2_IOCFACTS_HDRVERSION_DEV_MASK               (0x00FF)
+#define MPI2_IOCFACTS_HDRVERSION_DEV_SHIFT              (0)
+
+/* IOCExceptions */
+#define MPI2_IOCFACTS_EXCEPT_IR_FOREIGN_CONFIG_MAX      (0x0100)
+
+#define MPI2_IOCFACTS_EXCEPT_BOOTSTAT_MASK              (0x00E0)
+#define MPI2_IOCFACTS_EXCEPT_BOOTSTAT_GOOD              (0x0000)
+#define MPI2_IOCFACTS_EXCEPT_BOOTSTAT_BACKUP            (0x0020)
+#define MPI2_IOCFACTS_EXCEPT_BOOTSTAT_RESTORED          (0x0040)
+#define MPI2_IOCFACTS_EXCEPT_BOOTSTAT_CORRUPT_BACKUP    (0x0060)
+
+#define MPI2_IOCFACTS_EXCEPT_METADATA_UNSUPPORTED       (0x0010)
+#define MPI2_IOCFACTS_EXCEPT_MANUFACT_CHECKSUM_FAIL     (0x0008)
+#define MPI2_IOCFACTS_EXCEPT_FW_CHECKSUM_FAIL           (0x0004)
+#define MPI2_IOCFACTS_EXCEPT_RAID_CONFIG_INVALID        (0x0002)
+#define MPI2_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL       (0x0001)
+
+/* defines for WhoInit field are after the IOCInit Request */
+
+/* ProductID field uses MPI2_FW_HEADER_PID_ */
+
+/* IOCCapabilities */
+#define MPI2_IOCFACTS_CAPABILITY_EVENT_REPLAY           (0x00002000)
+#define MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID        (0x00001000)
+#define MPI2_IOCFACTS_CAPABILITY_TLR                    (0x00000800)
+#define MPI2_IOCFACTS_CAPABILITY_MULTICAST              (0x00000100)
+#define MPI2_IOCFACTS_CAPABILITY_BIDIRECTIONAL_TARGET   (0x00000080)
+#define MPI2_IOCFACTS_CAPABILITY_EEDP                   (0x00000040)
+#define MPI2_IOCFACTS_CAPABILITY_SNAPSHOT_BUFFER        (0x00000010)
+#define MPI2_IOCFACTS_CAPABILITY_DIAG_TRACE_BUFFER      (0x00000008)
+#define MPI2_IOCFACTS_CAPABILITY_TASK_SET_FULL_HANDLING (0x00000004)
+
+/* ProtocolFlags */
+#define MPI2_IOCFACTS_PROTOCOL_SCSI_TARGET              (0x0001)
+#define MPI2_IOCFACTS_PROTOCOL_SCSI_INITIATOR           (0x0002)
+
+
+/****************************************************************************
+*  PortFacts message
+****************************************************************************/
+
+/* PortFacts Request message */
+typedef struct _MPI2_PORT_FACTS_REQUEST
+{
+    U16                     Reserved1;                      /* 0x00 */
+    U8                      ChainOffset;                    /* 0x02 */
+    U8                      Function;                       /* 0x03 */
+    U16                     Reserved2;                      /* 0x04 */
+    U8                      PortNumber;                     /* 0x06 */
+    U8                      MsgFlags;                       /* 0x07 */
+    U8                      VP_ID;                          /* 0x08 */
+    U8                      VF_ID;                          /* 0x09 */
+    U16                     Reserved3;                      /* 0x0A */
+} MPI2_PORT_FACTS_REQUEST, MPI2_POINTER PTR_MPI2_PORT_FACTS_REQUEST,
+  Mpi2PortFactsRequest_t, MPI2_POINTER pMpi2PortFactsRequest_t;
+
+/* PortFacts Reply message */
+typedef struct _MPI2_PORT_FACTS_REPLY
+{
+    U16                     Reserved1;                      /* 0x00 */
+    U8                      MsgLength;                      /* 0x02 */
+    U8                      Function;                       /* 0x03 */
+    U16                     Reserved2;                      /* 0x04 */
+    U8                      PortNumber;                     /* 0x06 */
+    U8                      MsgFlags;                       /* 0x07 */
+    U8                      VP_ID;                          /* 0x08 */
+    U8                      VF_ID;                          /* 0x09 */
+    U16                     Reserved3;                      /* 0x0A */
+    U16                     Reserved4;                      /* 0x0C */
+    U16                     IOCStatus;                      /* 0x0E */
+    U32                     IOCLogInfo;                     /* 0x10 */
+    U8                      Reserved5;                      /* 0x14 */
+    U8                      PortType;                       /* 0x15 */
+    U16                     Reserved6;                      /* 0x16 */
+    U16                     MaxPostedCmdBuffers;            /* 0x18 */
+    U16                     Reserved7;                      /* 0x1A */
+} MPI2_PORT_FACTS_REPLY, MPI2_POINTER PTR_MPI2_PORT_FACTS_REPLY,
+  Mpi2PortFactsReply_t, MPI2_POINTER pMpi2PortFactsReply_t;
+
+/* PortType values */
+#define MPI2_PORTFACTS_PORTTYPE_INACTIVE            (0x00)
+#define MPI2_PORTFACTS_PORTTYPE_FC                  (0x10)
+#define MPI2_PORTFACTS_PORTTYPE_ISCSI               (0x20)
+#define MPI2_PORTFACTS_PORTTYPE_SAS_PHYSICAL        (0x30)
+#define MPI2_PORTFACTS_PORTTYPE_SAS_VIRTUAL         (0x31)
+
+
+/****************************************************************************
+*  PortEnable message
+****************************************************************************/
+
+/* PortEnable Request message */
+typedef struct _MPI2_PORT_ENABLE_REQUEST
+{
+    U16                     Reserved1;                      /* 0x00 */
+    U8                      ChainOffset;                    /* 0x02 */
+    U8                      Function;                       /* 0x03 */
+    U8                      Reserved2;                      /* 0x04 */
+    U8                      PortFlags;                      /* 0x05 */
+    U8                      Reserved3;                      /* 0x06 */
+    U8                      MsgFlags;                       /* 0x07 */
+    U8                      VP_ID;                          /* 0x08 */
+    U8                      VF_ID;                          /* 0x09 */
+    U16                     Reserved4;                      /* 0x0A */
+} MPI2_PORT_ENABLE_REQUEST, MPI2_POINTER PTR_MPI2_PORT_ENABLE_REQUEST,
+  Mpi2PortEnableRequest_t, MPI2_POINTER pMpi2PortEnableRequest_t;
+
+
+/* PortEnable Reply message */
+typedef struct _MPI2_PORT_ENABLE_REPLY
+{
+    U16                     Reserved1;                      /* 0x00 */
+    U8                      MsgLength;                      /* 0x02 */
+    U8                      Function;                       /* 0x03 */
+    U8                      Reserved2;                      /* 0x04 */
+    U8                      PortFlags;                      /* 0x05 */
+    U8                      Reserved3;                      /* 0x06 */
+    U8                      MsgFlags;                       /* 0x07 */
+    U8                      VP_ID;                          /* 0x08 */
+    U8                      VF_ID;                          /* 0x09 */
+    U16                     Reserved4;                      /* 0x0A */
+    U16                     Reserved5;                      /* 0x0C */
+    U16                     IOCStatus;                      /* 0x0E */
+    U32                     IOCLogInfo;                     /* 0x10 */
+} MPI2_PORT_ENABLE_REPLY, MPI2_POINTER PTR_MPI2_PORT_ENABLE_REPLY,
+  Mpi2PortEnableReply_t, MPI2_POINTER pMpi2PortEnableReply_t;
+
+
+/****************************************************************************
+*  EventNotification message
+****************************************************************************/
+
+/* EventNotification Request message */
+#define MPI2_EVENT_NOTIFY_EVENTMASK_WORDS           (4)
+
+typedef struct _MPI2_EVENT_NOTIFICATION_REQUEST
+{
+    U16                     Reserved1;                      /* 0x00 */
+    U8                      ChainOffset;                    /* 0x02 */
+    U8                      Function;                       /* 0x03 */
+    U16                     Reserved2;                      /* 0x04 */
+    U8                      Reserved3;                      /* 0x06 */
+    U8                      MsgFlags;                       /* 0x07 */
+    U8                      VP_ID;                          /* 0x08 */
+    U8                      VF_ID;                          /* 0x09 */
+    U16                     Reserved4;                      /* 0x0A */
+    U32                     Reserved5;                      /* 0x0C */
+    U32                     Reserved6;                      /* 0x10 */
+    U32                     EventMasks[MPI2_EVENT_NOTIFY_EVENTMASK_WORDS];/* 0x14 */
+    U16                     SASBroadcastPrimitiveMasks;     /* 0x24 */
+    U16                     Reserved7;                      /* 0x26 */
+    U32                     Reserved8;                      /* 0x28 */
+} MPI2_EVENT_NOTIFICATION_REQUEST,
+  MPI2_POINTER PTR_MPI2_EVENT_NOTIFICATION_REQUEST,
+  Mpi2EventNotificationRequest_t, MPI2_POINTER pMpi2EventNotificationRequest_t;
+
+
+/* EventNotification Reply message */
+typedef struct _MPI2_EVENT_NOTIFICATION_REPLY
+{
+    U16                     EventDataLength;                /* 0x00 */
+    U8                      MsgLength;                      /* 0x02 */
+    U8                      Function;                       /* 0x03 */
+    U16                     Reserved1;                      /* 0x04 */
+    U8                      AckRequired;                    /* 0x06 */
+    U8                      MsgFlags;                       /* 0x07 */
+    U8                      VP_ID;                          /* 0x08 */
+    U8                      VF_ID;                          /* 0x09 */
+    U16                     Reserved2;                      /* 0x0A */
+    U16                     Reserved3;                      /* 0x0C */
+    U16                     IOCStatus;                      /* 0x0E */
+    U32                     IOCLogInfo;                     /* 0x10 */
+    U16                     Event;                          /* 0x14 */
+    U16                     Reserved4;                      /* 0x16 */
+    U32                     EventContext;                   /* 0x18 */
+    U32                     EventData[1];                   /* 0x1C */
+} MPI2_EVENT_NOTIFICATION_REPLY, MPI2_POINTER PTR_MPI2_EVENT_NOTIFICATION_REPLY,
+  Mpi2EventNotificationReply_t, MPI2_POINTER pMpi2EventNotificationReply_t;
+
+/* AckRequired */
+#define MPI2_EVENT_NOTIFICATION_ACK_NOT_REQUIRED    (0x00)
+#define MPI2_EVENT_NOTIFICATION_ACK_REQUIRED        (0x01)
+
+/* Event */
+#define MPI2_EVENT_LOG_DATA                         (0x0001)
+#define MPI2_EVENT_STATE_CHANGE                     (0x0002)
+#define MPI2_EVENT_HARD_RESET_RECEIVED              (0x0005)
+#define MPI2_EVENT_EVENT_CHANGE                     (0x000A)
+#define MPI2_EVENT_TASK_SET_FULL                    (0x000E)
+#define MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE         (0x000F)
+#define MPI2_EVENT_IR_OPERATION_STATUS              (0x0014)
+#define MPI2_EVENT_SAS_DISCOVERY                    (0x0016)
+#define MPI2_EVENT_SAS_BROADCAST_PRIMITIVE          (0x0017)
+#define MPI2_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE    (0x0018)
+#define MPI2_EVENT_SAS_INIT_TABLE_OVERFLOW          (0x0019)
+#define MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST         (0x001C)
+#define MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE    (0x001D)
+#define MPI2_EVENT_IR_VOLUME                        (0x001E)
+#define MPI2_EVENT_IR_PHYSICAL_DISK                 (0x001F)
+#define MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST     (0x0020)
+#define MPI2_EVENT_LOG_ENTRY_ADDED                  (0x0021)
+
+
+/* Log Entry Added Event data */
+
+/* the following structure matches MPI2_LOG_0_ENTRY in mpi2_cnfg.h */
+#define MPI2_EVENT_DATA_LOG_DATA_LENGTH             (0x1C)
+
+typedef struct _MPI2_EVENT_DATA_LOG_ENTRY_ADDED
+{
+    U64         TimeStamp;                          /* 0x00 */
+    U32         Reserved1;                          /* 0x08 */
+    U16         LogSequence;                        /* 0x0C */
+    U16         LogEntryQualifier;                  /* 0x0E */
+    U8          VP_ID;                              /* 0x10 */
+    U8          VF_ID;                              /* 0x11 */
+    U16         Reserved2;                          /* 0x12 */
+    U8          LogData[MPI2_EVENT_DATA_LOG_DATA_LENGTH];/* 0x14 */
+} MPI2_EVENT_DATA_LOG_ENTRY_ADDED,
+  MPI2_POINTER PTR_MPI2_EVENT_DATA_LOG_ENTRY_ADDED,
+  Mpi2EventDataLogEntryAdded_t, MPI2_POINTER pMpi2EventDataLogEntryAdded_t;
+
+/* Hard Reset Received Event data */
+
+typedef struct _MPI2_EVENT_DATA_HARD_RESET_RECEIVED
+{
+    U8                      Reserved1;                      /* 0x00 */
+    U8                      Port;                           /* 0x01 */
+    U16                     Reserved2;                      /* 0x02 */
+} MPI2_EVENT_DATA_HARD_RESET_RECEIVED,
+  MPI2_POINTER PTR_MPI2_EVENT_DATA_HARD_RESET_RECEIVED,
+  Mpi2EventDataHardResetReceived_t,
+  MPI2_POINTER pMpi2EventDataHardResetReceived_t;
+
+/* Task Set Full Event data */
+
+typedef struct _MPI2_EVENT_DATA_TASK_SET_FULL
+{
+    U16                     DevHandle;                      /* 0x00 */
+    U16                     CurrentDepth;                   /* 0x02 */
+} MPI2_EVENT_DATA_TASK_SET_FULL, MPI2_POINTER PTR_MPI2_EVENT_DATA_TASK_SET_FULL,
+  Mpi2EventDataTaskSetFull_t, MPI2_POINTER pMpi2EventDataTaskSetFull_t;
+
+
+/* SAS Device Status Change Event data */
+
+typedef struct _MPI2_EVENT_DATA_SAS_DEVICE_STATUS_CHANGE
+{
+    U16                     TaskTag;                        /* 0x00 */
+    U8                      ReasonCode;                     /* 0x02 */
+    U8                      Reserved1;                      /* 0x03 */
+    U8                      ASC;                            /* 0x04 */
+    U8                      ASCQ;                           /* 0x05 */
+    U16                     DevHandle;                      /* 0x06 */
+    U32                     Reserved2;                      /* 0x08 */
+    U64                     SASAddress;                     /* 0x0C */
+    U8                      LUN[8];                         /* 0x14 */
+} MPI2_EVENT_DATA_SAS_DEVICE_STATUS_CHANGE,
+  MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_DEVICE_STATUS_CHANGE,
+  Mpi2EventDataSasDeviceStatusChange_t,
+  MPI2_POINTER pMpi2EventDataSasDeviceStatusChange_t;
+
+/* SAS Device Status Change Event data ReasonCode values */
+#define MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA               (0x05)
+#define MPI2_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED              (0x07)
+#define MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET    (0x08)
+#define MPI2_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL      (0x09)
+#define MPI2_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL  (0x0A)
+#define MPI2_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL  (0x0B)
+#define MPI2_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL      (0x0C)
+#define MPI2_EVENT_SAS_DEV_STAT_RC_ASYNC_NOTIFICATION       (0x0D)
+#define MPI2_EVENT_SAS_DEV_STAT_RC_CMP_INTERNAL_DEV_RESET   (0x0E)
+#define MPI2_EVENT_SAS_DEV_STAT_RC_CMP_TASK_ABORT_INTERNAL  (0x0F)
+#define MPI2_EVENT_SAS_DEV_STAT_RC_SATA_INIT_FAILURE        (0x10)
+
+
+/* Integrated RAID Operation Status Event data */
+
+typedef struct _MPI2_EVENT_DATA_IR_OPERATION_STATUS
+{
+    U16                     VolDevHandle;               /* 0x00 */
+    U16                     Reserved1;                  /* 0x02 */
+    U8                      RAIDOperation;              /* 0x04 */
+    U8                      PercentComplete;            /* 0x05 */
+    U16                     Reserved2;                  /* 0x06 */
+    U32                     Resereved3;                 /* 0x08 */
+} MPI2_EVENT_DATA_IR_OPERATION_STATUS,
+  MPI2_POINTER PTR_MPI2_EVENT_DATA_IR_OPERATION_STATUS,
+  Mpi2EventDataIrOperationStatus_t,
+  MPI2_POINTER pMpi2EventDataIrOperationStatus_t;
+
+/* Integrated RAID Operation Status Event data RAIDOperation values */
+#define MPI2_EVENT_IR_RAIDOP_RESYNC                     (0x00)
+#define MPI2_EVENT_IR_RAIDOP_ONLINE_CAP_EXPANSION       (0x01)
+#define MPI2_EVENT_IR_RAIDOP_CONSISTENCY_CHECK          (0x02)
+#define MPI2_EVENT_IR_RAIDOP_BACKGROUND_INIT            (0x03)
+#define MPI2_EVENT_IR_RAIDOP_MAKE_DATA_CONSISTENT       (0x04)
+
+
+/* Integrated RAID Volume Event data */
+
+typedef struct _MPI2_EVENT_DATA_IR_VOLUME
+{
+    U16                     VolDevHandle;               /* 0x00 */
+    U8                      ReasonCode;                 /* 0x02 */
+    U8                      Reserved1;                  /* 0x03 */
+    U32                     NewValue;                   /* 0x04 */
+    U32                     PreviousValue;              /* 0x08 */
+} MPI2_EVENT_DATA_IR_VOLUME, MPI2_POINTER PTR_MPI2_EVENT_DATA_IR_VOLUME,
+  Mpi2EventDataIrVolume_t, MPI2_POINTER pMpi2EventDataIrVolume_t;
+
+/* Integrated RAID Volume Event data ReasonCode values */
+#define MPI2_EVENT_IR_VOLUME_RC_SETTINGS_CHANGED        (0x01)
+#define MPI2_EVENT_IR_VOLUME_RC_STATUS_FLAGS_CHANGED    (0x02)
+#define MPI2_EVENT_IR_VOLUME_RC_STATE_CHANGED           (0x03)
+
+
+/* Integrated RAID Physical Disk Event data */
+
+typedef struct _MPI2_EVENT_DATA_IR_PHYSICAL_DISK
+{
+    U16                     Reserved1;                  /* 0x00 */
+    U8                      ReasonCode;                 /* 0x02 */
+    U8                      PhysDiskNum;                /* 0x03 */
+    U16                     PhysDiskDevHandle;          /* 0x04 */
+    U16                     Reserved2;                  /* 0x06 */
+    U16                     Slot;                       /* 0x08 */
+    U16                     EnclosureHandle;            /* 0x0A */
+    U32                     NewValue;                   /* 0x0C */
+    U32                     PreviousValue;              /* 0x10 */
+} MPI2_EVENT_DATA_IR_PHYSICAL_DISK,
+  MPI2_POINTER PTR_MPI2_EVENT_DATA_IR_PHYSICAL_DISK,
+  Mpi2EventDataIrPhysicalDisk_t, MPI2_POINTER pMpi2EventDataIrPhysicalDisk_t;
+
+/* Integrated RAID Physical Disk Event data ReasonCode values */
+#define MPI2_EVENT_IR_PHYSDISK_RC_SETTINGS_CHANGED      (0x01)
+#define MPI2_EVENT_IR_PHYSDISK_RC_STATUS_FLAGS_CHANGED  (0x02)
+#define MPI2_EVENT_IR_PHYSDISK_RC_STATE_CHANGED         (0x03)
+
+
+/* Integrated RAID Configuration Change List Event data */
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check NumElements at runtime.
+ */
+#ifndef MPI2_EVENT_IR_CONFIG_ELEMENT_COUNT
+#define MPI2_EVENT_IR_CONFIG_ELEMENT_COUNT          (1)
+#endif
+
+typedef struct _MPI2_EVENT_IR_CONFIG_ELEMENT
+{
+    U16                     ElementFlags;               /* 0x00 */
+    U16                     VolDevHandle;               /* 0x02 */
+    U8                      ReasonCode;                 /* 0x04 */
+    U8                      PhysDiskNum;                /* 0x05 */
+    U16                     PhysDiskDevHandle;          /* 0x06 */
+} MPI2_EVENT_IR_CONFIG_ELEMENT, MPI2_POINTER PTR_MPI2_EVENT_IR_CONFIG_ELEMENT,
+  Mpi2EventIrConfigElement_t, MPI2_POINTER pMpi2EventIrConfigElement_t;
+
+/* IR Configuration Change List Event data ElementFlags values */
+#define MPI2_EVENT_IR_CHANGE_EFLAGS_ELEMENT_TYPE_MASK   (0x000F)
+#define MPI2_EVENT_IR_CHANGE_EFLAGS_VOLUME_ELEMENT      (0x0000)
+#define MPI2_EVENT_IR_CHANGE_EFLAGS_VOLPHYSDISK_ELEMENT (0x0001)
+#define MPI2_EVENT_IR_CHANGE_EFLAGS_HOTSPARE_ELEMENT    (0x0002)
+
+/* IR Configuration Change List Event data ReasonCode values */
+#define MPI2_EVENT_IR_CHANGE_RC_ADDED                   (0x01)
+#define MPI2_EVENT_IR_CHANGE_RC_REMOVED                 (0x02)
+#define MPI2_EVENT_IR_CHANGE_RC_NO_CHANGE               (0x03)
+#define MPI2_EVENT_IR_CHANGE_RC_HIDE                    (0x04)
+#define MPI2_EVENT_IR_CHANGE_RC_UNHIDE                  (0x05)
+#define MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED          (0x06)
+#define MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED          (0x07)
+#define MPI2_EVENT_IR_CHANGE_RC_PD_CREATED              (0x08)
+#define MPI2_EVENT_IR_CHANGE_RC_PD_DELETED              (0x09)
+
+typedef struct _MPI2_EVENT_DATA_IR_CONFIG_CHANGE_LIST
+{
+    U8                              NumElements;        /* 0x00 */
+    U8                              Reserved1;          /* 0x01 */
+    U8                              Reserved2;          /* 0x02 */
+    U8                              ConfigNum;          /* 0x03 */
+    U32                             Flags;              /* 0x04 */
+    MPI2_EVENT_IR_CONFIG_ELEMENT    ConfigElement[MPI2_EVENT_IR_CONFIG_ELEMENT_COUNT];    /* 0x08 */
+} MPI2_EVENT_DATA_IR_CONFIG_CHANGE_LIST,
+  MPI2_POINTER PTR_MPI2_EVENT_DATA_IR_CONFIG_CHANGE_LIST,
+  Mpi2EventDataIrConfigChangeList_t,
+  MPI2_POINTER pMpi2EventDataIrConfigChangeList_t;
+
+/* IR Configuration Change List Event data Flags values */
+#define MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG   (0x00000001)
+
+
+/* SAS Discovery Event data */
+
+typedef struct _MPI2_EVENT_DATA_SAS_DISCOVERY
+{
+    U8                      Flags;                      /* 0x00 */
+    U8                      ReasonCode;                 /* 0x01 */
+    U8                      PhysicalPort;               /* 0x02 */
+    U8                      Reserved1;                  /* 0x03 */
+    U32                     DiscoveryStatus;            /* 0x04 */
+} MPI2_EVENT_DATA_SAS_DISCOVERY,
+  MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_DISCOVERY,
+  Mpi2EventDataSasDiscovery_t, MPI2_POINTER pMpi2EventDataSasDiscovery_t;
+
+/* SAS Discovery Event data Flags values */
+#define MPI2_EVENT_SAS_DISC_DEVICE_CHANGE                   (0x02)
+#define MPI2_EVENT_SAS_DISC_IN_PROGRESS                     (0x01)
+
+/* SAS Discovery Event data ReasonCode values */
+#define MPI2_EVENT_SAS_DISC_RC_STARTED                      (0x01)
+#define MPI2_EVENT_SAS_DISC_RC_COMPLETED                    (0x02)
+
+/* SAS Discovery Event data DiscoveryStatus values */
+#define MPI2_EVENT_SAS_DISC_DS_MAX_ENCLOSURES_EXCEED            (0x80000000)
+#define MPI2_EVENT_SAS_DISC_DS_MAX_EXPANDERS_EXCEED             (0x40000000)
+#define MPI2_EVENT_SAS_DISC_DS_MAX_DEVICES_EXCEED               (0x20000000)
+#define MPI2_EVENT_SAS_DISC_DS_MAX_TOPO_PHYS_EXCEED             (0x10000000)
+#define MPI2_EVENT_SAS_DISC_DS_DOWNSTREAM_INITIATOR             (0x08000000)
+#define MPI2_EVENT_SAS_DISC_DS_MULTI_SUBTRACTIVE_SUBTRACTIVE    (0x00008000)
+#define MPI2_EVENT_SAS_DISC_DS_EXP_MULTI_SUBTRACTIVE            (0x00004000)
+#define MPI2_EVENT_SAS_DISC_DS_MULTI_PORT_DOMAIN                (0x00002000)
+#define MPI2_EVENT_SAS_DISC_DS_TABLE_TO_SUBTRACTIVE_LINK        (0x00001000)
+#define MPI2_EVENT_SAS_DISC_DS_UNSUPPORTED_DEVICE               (0x00000800)
+#define MPI2_EVENT_SAS_DISC_DS_TABLE_LINK                       (0x00000400)
+#define MPI2_EVENT_SAS_DISC_DS_SUBTRACTIVE_LINK                 (0x00000200)
+#define MPI2_EVENT_SAS_DISC_DS_SMP_CRC_ERROR                    (0x00000100)
+#define MPI2_EVENT_SAS_DISC_DS_SMP_FUNCTION_FAILED              (0x00000080)
+#define MPI2_EVENT_SAS_DISC_DS_INDEX_NOT_EXIST                  (0x00000040)
+#define MPI2_EVENT_SAS_DISC_DS_OUT_ROUTE_ENTRIES                (0x00000020)
+#define MPI2_EVENT_SAS_DISC_DS_SMP_TIMEOUT                      (0x00000010)
+#define MPI2_EVENT_SAS_DISC_DS_MULTIPLE_PORTS                   (0x00000004)
+#define MPI2_EVENT_SAS_DISC_DS_UNADDRESSABLE_DEVICE             (0x00000002)
+#define MPI2_EVENT_SAS_DISC_DS_LOOP_DETECTED                    (0x00000001)
+
+
+/* SAS Broadcast Primitive Event data */
+
+typedef struct _MPI2_EVENT_DATA_SAS_BROADCAST_PRIMITIVE
+{
+    U8                      PhyNum;                     /* 0x00 */
+    U8                      Port;                       /* 0x01 */
+    U8                      PortWidth;                  /* 0x02 */
+    U8                      Primitive;                  /* 0x03 */
+} MPI2_EVENT_DATA_SAS_BROADCAST_PRIMITIVE,
+  MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_BROADCAST_PRIMITIVE,
+  Mpi2EventDataSasBroadcastPrimitive_t,
+  MPI2_POINTER pMpi2EventDataSasBroadcastPrimitive_t;
+
+/* defines for the Primitive field */
+#define MPI2_EVENT_PRIMITIVE_CHANGE                         (0x01)
+#define MPI2_EVENT_PRIMITIVE_SES                            (0x02)
+#define MPI2_EVENT_PRIMITIVE_EXPANDER                       (0x03)
+#define MPI2_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT             (0x04)
+#define MPI2_EVENT_PRIMITIVE_RESERVED3                      (0x05)
+#define MPI2_EVENT_PRIMITIVE_RESERVED4                      (0x06)
+#define MPI2_EVENT_PRIMITIVE_CHANGE0_RESERVED               (0x07)
+#define MPI2_EVENT_PRIMITIVE_CHANGE1_RESERVED               (0x08)
+
+
+/* SAS Initiator Device Status Change Event data */
+
+typedef struct _MPI2_EVENT_DATA_SAS_INIT_DEV_STATUS_CHANGE
+{
+    U8                      ReasonCode;                 /* 0x00 */
+    U8                      PhysicalPort;               /* 0x01 */
+    U16                     DevHandle;                  /* 0x02 */
+    U64                     SASAddress;                 /* 0x04 */
+} MPI2_EVENT_DATA_SAS_INIT_DEV_STATUS_CHANGE,
+  MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_INIT_DEV_STATUS_CHANGE,
+  Mpi2EventDataSasInitDevStatusChange_t,
+  MPI2_POINTER pMpi2EventDataSasInitDevStatusChange_t;
+
+/* SAS Initiator Device Status Change event ReasonCode values */
+#define MPI2_EVENT_SAS_INIT_RC_ADDED                (0x01)
+#define MPI2_EVENT_SAS_INIT_RC_NOT_RESPONDING       (0x02)
+
+
+/* SAS Initiator Device Table Overflow Event data */
+
+typedef struct _MPI2_EVENT_DATA_SAS_INIT_TABLE_OVERFLOW
+{
+    U16                     MaxInit;                    /* 0x00 */
+    U16                     CurrentInit;                /* 0x02 */
+    U64                     SASAddress;                 /* 0x04 */
+} MPI2_EVENT_DATA_SAS_INIT_TABLE_OVERFLOW,
+  MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_INIT_TABLE_OVERFLOW,
+  Mpi2EventDataSasInitTableOverflow_t,
+  MPI2_POINTER pMpi2EventDataSasInitTableOverflow_t;
+
+
+/* SAS Topology Change List Event data */
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check NumEntries at runtime.
+ */
+#ifndef MPI2_EVENT_SAS_TOPO_PHY_COUNT
+#define MPI2_EVENT_SAS_TOPO_PHY_COUNT           (1)
+#endif
+
+typedef struct _MPI2_EVENT_SAS_TOPO_PHY_ENTRY
+{
+    U16                     AttachedDevHandle;          /* 0x00 */
+    U8                      LinkRate;                   /* 0x02 */
+    U8                      PhyStatus;                  /* 0x03 */
+} MPI2_EVENT_SAS_TOPO_PHY_ENTRY, MPI2_POINTER PTR_MPI2_EVENT_SAS_TOPO_PHY_ENTRY,
+  Mpi2EventSasTopoPhyEntry_t, MPI2_POINTER pMpi2EventSasTopoPhyEntry_t;
+
+typedef struct _MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST
+{
+    U16                             EnclosureHandle;            /* 0x00 */
+    U16                             ExpanderDevHandle;          /* 0x02 */
+    U8                              NumPhys;                    /* 0x04 */
+    U8                              Reserved1;                  /* 0x05 */
+    U16                             Reserved2;                  /* 0x06 */
+    U8                              NumEntries;                 /* 0x08 */
+    U8                              StartPhyNum;                /* 0x09 */
+    U8                              ExpStatus;                  /* 0x0A */
+    U8                              PhysicalPort;               /* 0x0B */
+    MPI2_EVENT_SAS_TOPO_PHY_ENTRY   PHY[MPI2_EVENT_SAS_TOPO_PHY_COUNT]; /* 0x0C*/
+} MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST,
+  MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST,
+  Mpi2EventDataSasTopologyChangeList_t,
+  MPI2_POINTER pMpi2EventDataSasTopologyChangeList_t;
+
+/* values for the ExpStatus field */
+#define MPI2_EVENT_SAS_TOPO_ES_ADDED                        (0x01)
+#define MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING               (0x02)
+#define MPI2_EVENT_SAS_TOPO_ES_RESPONDING                   (0x03)
+#define MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING         (0x04)
+
+/* defines for the LinkRate field */
+#define MPI2_EVENT_SAS_TOPO_LR_CURRENT_MASK                 (0xF0)
+#define MPI2_EVENT_SAS_TOPO_LR_CURRENT_SHIFT                (4)
+#define MPI2_EVENT_SAS_TOPO_LR_PREV_MASK                    (0x0F)
+#define MPI2_EVENT_SAS_TOPO_LR_PREV_SHIFT                   (0)
+
+#define MPI2_EVENT_SAS_TOPO_LR_UNKNOWN_LINK_RATE            (0x00)
+#define MPI2_EVENT_SAS_TOPO_LR_PHY_DISABLED                 (0x01)
+#define MPI2_EVENT_SAS_TOPO_LR_NEGOTIATION_FAILED           (0x02)
+#define MPI2_EVENT_SAS_TOPO_LR_SATA_OOB_COMPLETE            (0x03)
+#define MPI2_EVENT_SAS_TOPO_LR_PORT_SELECTOR                (0x04)
+#define MPI2_EVENT_SAS_TOPO_LR_SMP_RESET_IN_PROGRESS        (0x05)
+#define MPI2_EVENT_SAS_TOPO_LR_RATE_1_5                     (0x08)
+#define MPI2_EVENT_SAS_TOPO_LR_RATE_3_0                     (0x09)
+#define MPI2_EVENT_SAS_TOPO_LR_RATE_6_0                     (0x0A)
+
+/* values for the PhyStatus field */
+#define MPI2_EVENT_SAS_TOPO_PHYSTATUS_VACANT                (0x80)
+#define MPI2_EVENT_SAS_TOPO_PS_MULTIPLEX_CHANGE             (0x10)
+/* values for the PhyStatus ReasonCode sub-field */
+#define MPI2_EVENT_SAS_TOPO_RC_MASK                         (0x0F)
+#define MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED                   (0x01)
+#define MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING          (0x02)
+#define MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED                  (0x03)
+#define MPI2_EVENT_SAS_TOPO_RC_NO_CHANGE                    (0x04)
+#define MPI2_EVENT_SAS_TOPO_RC_DELAY_NOT_RESPONDING         (0x05)
+
+
+/* SAS Enclosure Device Status Change Event data */
+
+typedef struct _MPI2_EVENT_DATA_SAS_ENCL_DEV_STATUS_CHANGE
+{
+    U16                     EnclosureHandle;            /* 0x00 */
+    U8                      ReasonCode;                 /* 0x02 */
+    U8                      PhysicalPort;               /* 0x03 */
+    U64                     EnclosureLogicalID;         /* 0x04 */
+    U16                     NumSlots;                   /* 0x0C */
+    U16                     StartSlot;                  /* 0x0E */
+    U32                     PhyBits;                    /* 0x10 */
+} MPI2_EVENT_DATA_SAS_ENCL_DEV_STATUS_CHANGE,
+  MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_ENCL_DEV_STATUS_CHANGE,
+  Mpi2EventDataSasEnclDevStatusChange_t,
+  MPI2_POINTER pMpi2EventDataSasEnclDevStatusChange_t;
+
+/* SAS Enclosure Device Status Change event ReasonCode values */
+#define MPI2_EVENT_SAS_ENCL_RC_ADDED                (0x01)
+#define MPI2_EVENT_SAS_ENCL_RC_NOT_RESPONDING       (0x02)
+
+
+/****************************************************************************
+*  EventAck message
+****************************************************************************/
+
+/* EventAck Request message */
+typedef struct _MPI2_EVENT_ACK_REQUEST
+{
+    U16                     Reserved1;                      /* 0x00 */
+    U8                      ChainOffset;                    /* 0x02 */
+    U8                      Function;                       /* 0x03 */
+    U16                     Reserved2;                      /* 0x04 */
+    U8                      Reserved3;                      /* 0x06 */
+    U8                      MsgFlags;                       /* 0x07 */
+    U8                      VP_ID;                          /* 0x08 */
+    U8                      VF_ID;                          /* 0x09 */
+    U16                     Reserved4;                      /* 0x0A */
+    U16                     Event;                          /* 0x0C */
+    U16                     Reserved5;                      /* 0x0E */
+    U32                     EventContext;                   /* 0x10 */
+} MPI2_EVENT_ACK_REQUEST, MPI2_POINTER PTR_MPI2_EVENT_ACK_REQUEST,
+  Mpi2EventAckRequest_t, MPI2_POINTER pMpi2EventAckRequest_t;
+
+
+/* EventAck Reply message */
+typedef struct _MPI2_EVENT_ACK_REPLY
+{
+    U16                     Reserved1;                      /* 0x00 */
+    U8                      MsgLength;                      /* 0x02 */
+    U8                      Function;                       /* 0x03 */
+    U16                     Reserved2;                      /* 0x04 */
+    U8                      Reserved3;                      /* 0x06 */
+    U8                      MsgFlags;                       /* 0x07 */
+    U8                      VP_ID;                          /* 0x08 */
+    U8                      VF_ID;                          /* 0x09 */
+    U16                     Reserved4;                      /* 0x0A */
+    U16                     Reserved5;                      /* 0x0C */
+    U16                     IOCStatus;                      /* 0x0E */
+    U32                     IOCLogInfo;                     /* 0x10 */
+} MPI2_EVENT_ACK_REPLY, MPI2_POINTER PTR_MPI2_EVENT_ACK_REPLY,
+  Mpi2EventAckReply_t, MPI2_POINTER pMpi2EventAckReply_t;
+
+
+/****************************************************************************
+*  FWDownload message
+****************************************************************************/
+
+/* FWDownload Request message */
+typedef struct _MPI2_FW_DOWNLOAD_REQUEST
+{
+    U8                      ImageType;                  /* 0x00 */
+    U8                      Reserved1;                  /* 0x01 */
+    U8                      ChainOffset;                /* 0x02 */
+    U8                      Function;                   /* 0x03 */
+    U16                     Reserved2;                  /* 0x04 */
+    U8                      Reserved3;                  /* 0x06 */
+    U8                      MsgFlags;                   /* 0x07 */
+    U8                      VP_ID;                      /* 0x08 */
+    U8                      VF_ID;                      /* 0x09 */
+    U16                     Reserved4;                  /* 0x0A */
+    U32                     TotalImageSize;             /* 0x0C */
+    U32                     Reserved5;                  /* 0x10 */
+    MPI2_MPI_SGE_UNION      SGL;                        /* 0x14 */
+} MPI2_FW_DOWNLOAD_REQUEST, MPI2_POINTER PTR_MPI2_FW_DOWNLOAD_REQUEST,
+  Mpi2FWDownloadRequest, MPI2_POINTER pMpi2FWDownloadRequest;
+
+#define MPI2_FW_DOWNLOAD_MSGFLGS_LAST_SEGMENT   (0x01)
+
+#define MPI2_FW_DOWNLOAD_ITYPE_FW                   (0x01)
+#define MPI2_FW_DOWNLOAD_ITYPE_BIOS                 (0x02)
+#define MPI2_FW_DOWNLOAD_ITYPE_MANUFACTURING        (0x06)
+#define MPI2_FW_DOWNLOAD_ITYPE_CONFIG_1             (0x07)
+#define MPI2_FW_DOWNLOAD_ITYPE_CONFIG_2             (0x08)
+#define MPI2_FW_DOWNLOAD_ITYPE_MEGARAID             (0x09)
+#define MPI2_FW_DOWNLOAD_ITYPE_COMMON_BOOT_BLOCK    (0x0B)
+
+/* FWDownload TransactionContext Element */
+typedef struct _MPI2_FW_DOWNLOAD_TCSGE
+{
+    U8                      Reserved1;                  /* 0x00 */
+    U8                      ContextSize;                /* 0x01 */
+    U8                      DetailsLength;              /* 0x02 */
+    U8                      Flags;                      /* 0x03 */
+    U32                     Reserved2;                  /* 0x04 */
+    U32                     ImageOffset;                /* 0x08 */
+    U32                     ImageSize;                  /* 0x0C */
+} MPI2_FW_DOWNLOAD_TCSGE, MPI2_POINTER PTR_MPI2_FW_DOWNLOAD_TCSGE,
+  Mpi2FWDownloadTCSGE_t, MPI2_POINTER pMpi2FWDownloadTCSGE_t;
+
+/* FWDownload Reply message */
+typedef struct _MPI2_FW_DOWNLOAD_REPLY
+{
+    U8                      ImageType;                  /* 0x00 */
+    U8                      Reserved1;                  /* 0x01 */
+    U8                      MsgLength;                  /* 0x02 */
+    U8                      Function;                   /* 0x03 */
+    U16                     Reserved2;                  /* 0x04 */
+    U8                      Reserved3;                  /* 0x06 */
+    U8                      MsgFlags;                   /* 0x07 */
+    U8                      VP_ID;                      /* 0x08 */
+    U8                      VF_ID;                      /* 0x09 */
+    U16                     Reserved4;                  /* 0x0A */
+    U16                     Reserved5;                  /* 0x0C */
+    U16                     IOCStatus;                  /* 0x0E */
+    U32                     IOCLogInfo;                 /* 0x10 */
+} MPI2_FW_DOWNLOAD_REPLY, MPI2_POINTER PTR_MPI2_FW_DOWNLOAD_REPLY,
+  Mpi2FWDownloadReply_t, MPI2_POINTER pMpi2FWDownloadReply_t;
+
+
+/****************************************************************************
+*  FWUpload message
+****************************************************************************/
+
+/* FWUpload Request message */
+typedef struct _MPI2_FW_UPLOAD_REQUEST
+{
+    U8                      ImageType;                  /* 0x00 */
+    U8                      Reserved1;                  /* 0x01 */
+    U8                      ChainOffset;                /* 0x02 */
+    U8                      Function;                   /* 0x03 */
+    U16                     Reserved2;                  /* 0x04 */
+    U8                      Reserved3;                  /* 0x06 */
+    U8                      MsgFlags;                   /* 0x07 */
+    U8                      VP_ID;                      /* 0x08 */
+    U8                      VF_ID;                      /* 0x09 */
+    U16                     Reserved4;                  /* 0x0A */
+    U32                     Reserved5;                  /* 0x0C */
+    U32                     Reserved6;                  /* 0x10 */
+    MPI2_MPI_SGE_UNION      SGL;                        /* 0x14 */
+} MPI2_FW_UPLOAD_REQUEST, MPI2_POINTER PTR_MPI2_FW_UPLOAD_REQUEST,
+  Mpi2FWUploadRequest_t, MPI2_POINTER pMpi2FWUploadRequest_t;
+
+#define MPI2_FW_UPLOAD_ITYPE_FW_CURRENT         (0x00)
+#define MPI2_FW_UPLOAD_ITYPE_FW_FLASH           (0x01)
+#define MPI2_FW_UPLOAD_ITYPE_BIOS_FLASH         (0x02)
+#define MPI2_FW_UPLOAD_ITYPE_FW_BACKUP          (0x05)
+#define MPI2_FW_UPLOAD_ITYPE_MANUFACTURING      (0x06)
+#define MPI2_FW_UPLOAD_ITYPE_CONFIG_1           (0x07)
+#define MPI2_FW_UPLOAD_ITYPE_CONFIG_2           (0x08)
+#define MPI2_FW_UPLOAD_ITYPE_MEGARAID           (0x09)
+#define MPI2_FW_UPLOAD_ITYPE_COMPLETE           (0x0A)
+#define MPI2_FW_UPLOAD_ITYPE_COMMON_BOOT_BLOCK  (0x0B)
+
+typedef struct _MPI2_FW_UPLOAD_TCSGE
+{
+    U8                      Reserved1;                  /* 0x00 */
+    U8                      ContextSize;                /* 0x01 */
+    U8                      DetailsLength;              /* 0x02 */
+    U8                      Flags;                      /* 0x03 */
+    U32                     Reserved2;                  /* 0x04 */
+    U32                     ImageOffset;                /* 0x08 */
+    U32                     ImageSize;                  /* 0x0C */
+} MPI2_FW_UPLOAD_TCSGE, MPI2_POINTER PTR_MPI2_FW_UPLOAD_TCSGE,
+  Mpi2FWUploadTCSGE_t, MPI2_POINTER pMpi2FWUploadTCSGE_t;
+
+/* FWUpload Reply message */
+typedef struct _MPI2_FW_UPLOAD_REPLY
+{
+    U8                      ImageType;                  /* 0x00 */
+    U8                      Reserved1;                  /* 0x01 */
+    U8                      MsgLength;                  /* 0x02 */
+    U8                      Function;                   /* 0x03 */
+    U16                     Reserved2;                  /* 0x04 */
+    U8                      Reserved3;                  /* 0x06 */
+    U8                      MsgFlags;                   /* 0x07 */
+    U8                      VP_ID;                      /* 0x08 */
+    U8                      VF_ID;                      /* 0x09 */
+    U16                     Reserved4;                  /* 0x0A */
+    U16                     Reserved5;                  /* 0x0C */
+    U16                     IOCStatus;                  /* 0x0E */
+    U32                     IOCLogInfo;                 /* 0x10 */
+    U32                     ActualImageSize;            /* 0x14 */
+} MPI2_FW_UPLOAD_REPLY, MPI2_POINTER PTR_MPI2_FW_UPLOAD_REPLY,
+  Mpi2FWUploadReply_t, MPI2_POINTER pMPi2FWUploadReply_t;
+
+
+/* FW Image Header */
+typedef struct _MPI2_FW_IMAGE_HEADER
+{
+    U32                     Signature;                  /* 0x00 */
+    U32                     Signature0;                 /* 0x04 */
+    U32                     Signature1;                 /* 0x08 */
+    U32                     Signature2;                 /* 0x0C */
+    MPI2_VERSION_UNION      MPIVersion;                 /* 0x10 */
+    MPI2_VERSION_UNION      FWVersion;                  /* 0x14 */
+    MPI2_VERSION_UNION      NVDATAVersion;              /* 0x18 */
+    MPI2_VERSION_UNION      PackageVersion;             /* 0x1C */
+    U16                     VendorID;                   /* 0x20 */
+    U16                     ProductID;                  /* 0x22 */
+    U16                     ProtocolFlags;              /* 0x24 */
+    U16                     Reserved26;                 /* 0x26 */
+    U32                     IOCCapabilities;            /* 0x28 */
+    U32                     ImageSize;                  /* 0x2C */
+    U32                     NextImageHeaderOffset;      /* 0x30 */
+    U32                     Checksum;                   /* 0x34 */
+    U32                     Reserved38;                 /* 0x38 */
+    U32                     Reserved3C;                 /* 0x3C */
+    U32                     Reserved40;                 /* 0x40 */
+    U32                     Reserved44;                 /* 0x44 */
+    U32                     Reserved48;                 /* 0x48 */
+    U32                     Reserved4C;                 /* 0x4C */
+    U32                     Reserved50;                 /* 0x50 */
+    U32                     Reserved54;                 /* 0x54 */
+    U32                     Reserved58;                 /* 0x58 */
+    U32                     Reserved5C;                 /* 0x5C */
+    U32                     Reserved60;                 /* 0x60 */
+    U32                     FirmwareVersionNameWhat;    /* 0x64 */
+    U8                      FirmwareVersionName[32];    /* 0x68 */
+    U32                     VendorNameWhat;             /* 0x88 */
+    U8                      VendorName[32];             /* 0x8C */
+    U32                     PackageNameWhat;            /* 0x88 */
+    U8                      PackageName[32];            /* 0x8C */
+    U32                     ReservedD0;                 /* 0xD0 */
+    U32                     ReservedD4;                 /* 0xD4 */
+    U32                     ReservedD8;                 /* 0xD8 */
+    U32                     ReservedDC;                 /* 0xDC */
+    U32                     ReservedE0;                 /* 0xE0 */
+    U32                     ReservedE4;                 /* 0xE4 */
+    U32                     ReservedE8;                 /* 0xE8 */
+    U32                     ReservedEC;                 /* 0xEC */
+    U32                     ReservedF0;                 /* 0xF0 */
+    U32                     ReservedF4;                 /* 0xF4 */
+    U32                     ReservedF8;                 /* 0xF8 */
+    U32                     ReservedFC;                 /* 0xFC */
+} MPI2_FW_IMAGE_HEADER, MPI2_POINTER PTR_MPI2_FW_IMAGE_HEADER,
+  Mpi2FWImageHeader_t, MPI2_POINTER pMpi2FWImageHeader_t;
+
+/* Signature field */
+#define MPI2_FW_HEADER_SIGNATURE_OFFSET         (0x00)
+#define MPI2_FW_HEADER_SIGNATURE_MASK           (0xFF000000)
+#define MPI2_FW_HEADER_SIGNATURE                (0xEA000000)
+
+/* Signature0 field */
+#define MPI2_FW_HEADER_SIGNATURE0_OFFSET        (0x04)
+#define MPI2_FW_HEADER_SIGNATURE0               (0x5AFAA55A)
+
+/* Signature1 field */
+#define MPI2_FW_HEADER_SIGNATURE1_OFFSET        (0x08)
+#define MPI2_FW_HEADER_SIGNATURE1               (0xA55AFAA5)
+
+/* Signature2 field */
+#define MPI2_FW_HEADER_SIGNATURE2_OFFSET        (0x0C)
+#define MPI2_FW_HEADER_SIGNATURE2               (0x5AA55AFA)
+
+
+/* defines for using the ProductID field */
+#define MPI2_FW_HEADER_PID_TYPE_MASK            (0xF000)
+#define MPI2_FW_HEADER_PID_TYPE_SAS             (0x2000)
+
+#define MPI2_FW_HEADER_PID_PROD_MASK            (0x0F00)
+#define MPI2_FW_HEADER_PID_PROD_A               (0x0000)
+
+#define MPI2_FW_HEADER_PID_FAMILY_MASK          (0x00FF)
+/* SAS */
+#define MPI2_FW_HEADER_PID_FAMILY_2108_SAS      (0x0010)
+
+/* use MPI2_IOCFACTS_PROTOCOL_ defines for ProtocolFlags field */
+
+/* use MPI2_IOCFACTS_CAPABILITY_ defines for IOCCapabilities field */
+
+
+#define MPI2_FW_HEADER_IMAGESIZE_OFFSET         (0x2C)
+#define MPI2_FW_HEADER_NEXTIMAGE_OFFSET         (0x30)
+#define MPI2_FW_HEADER_VERNMHWAT_OFFSET         (0x64)
+
+#define MPI2_FW_HEADER_WHAT_SIGNATURE           (0x29232840)
+
+#define MPI2_FW_HEADER_SIZE                     (0x100)
+
+
+/* Extended Image Header */
+typedef struct _MPI2_EXT_IMAGE_HEADER
+
+{
+    U8                      ImageType;                  /* 0x00 */
+    U8                      Reserved1;                  /* 0x01 */
+    U16                     Reserved2;                  /* 0x02 */
+    U32                     Checksum;                   /* 0x04 */
+    U32                     ImageSize;                  /* 0x08 */
+    U32                     NextImageHeaderOffset;      /* 0x0C */
+    U32                     PackageVersion;             /* 0x10 */
+    U32                     Reserved3;                  /* 0x14 */
+    U32                     Reserved4;                  /* 0x18 */
+    U32                     Reserved5;                  /* 0x1C */
+    U8                      IdentifyString[32];         /* 0x20 */
+} MPI2_EXT_IMAGE_HEADER, MPI2_POINTER PTR_MPI2_EXT_IMAGE_HEADER,
+  Mpi2ExtImageHeader_t, MPI2_POINTER pMpi2ExtImageHeader_t;
+
+/* useful offsets */
+#define MPI2_EXT_IMAGE_IMAGETYPE_OFFSET         (0x00)
+#define MPI2_EXT_IMAGE_IMAGESIZE_OFFSET         (0x08)
+#define MPI2_EXT_IMAGE_NEXTIMAGE_OFFSET         (0x0C)
+
+#define MPI2_EXT_IMAGE_HEADER_SIZE              (0x40)
+
+/* defines for the ImageType field */
+#define MPI2_EXT_IMAGE_TYPE_UNSPECIFIED         (0x00)
+#define MPI2_EXT_IMAGE_TYPE_FW                  (0x01)
+#define MPI2_EXT_IMAGE_TYPE_NVDATA              (0x03)
+#define MPI2_EXT_IMAGE_TYPE_BOOTLOADER          (0x04)
+#define MPI2_EXT_IMAGE_TYPE_INITIALIZATION      (0x05)
+#define MPI2_EXT_IMAGE_TYPE_FLASH_LAYOUT        (0x06)
+#define MPI2_EXT_IMAGE_TYPE_SUPPORTED_DEVICES   (0x07)
+#define MPI2_EXT_IMAGE_TYPE_MEGARAID            (0x08)
+
+#define MPI2_EXT_IMAGE_TYPE_MAX                 (MPI2_EXT_IMAGE_TYPE_MEGARAID)
+
+
+
+/* FLASH Layout Extended Image Data */
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check RegionsPerLayout at runtime.
+ */
+#ifndef MPI2_FLASH_NUMBER_OF_REGIONS
+#define MPI2_FLASH_NUMBER_OF_REGIONS        (1)
+#endif
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check NumberOfLayouts at runtime.
+ */
+#ifndef MPI2_FLASH_NUMBER_OF_LAYOUTS
+#define MPI2_FLASH_NUMBER_OF_LAYOUTS        (1)
+#endif
+
+typedef struct _MPI2_FLASH_REGION
+{
+    U8                      RegionType;                 /* 0x00 */
+    U8                      Reserved1;                  /* 0x01 */
+    U16                     Reserved2;                  /* 0x02 */
+    U32                     RegionOffset;               /* 0x04 */
+    U32                     RegionSize;                 /* 0x08 */
+    U32                     Reserved3;                  /* 0x0C */
+} MPI2_FLASH_REGION, MPI2_POINTER PTR_MPI2_FLASH_REGION,
+  Mpi2FlashRegion_t, MPI2_POINTER pMpi2FlashRegion_t;
+
+typedef struct _MPI2_FLASH_LAYOUT
+{
+    U32                     FlashSize;                  /* 0x00 */
+    U32                     Reserved1;                  /* 0x04 */
+    U32                     Reserved2;                  /* 0x08 */
+    U32                     Reserved3;                  /* 0x0C */
+    MPI2_FLASH_REGION       Region[MPI2_FLASH_NUMBER_OF_REGIONS];/* 0x10 */
+} MPI2_FLASH_LAYOUT, MPI2_POINTER PTR_MPI2_FLASH_LAYOUT,
+  Mpi2FlashLayout_t, MPI2_POINTER pMpi2FlashLayout_t;
+
+typedef struct _MPI2_FLASH_LAYOUT_DATA
+{
+    U8                      ImageRevision;              /* 0x00 */
+    U8                      Reserved1;                  /* 0x01 */
+    U8                      SizeOfRegion;               /* 0x02 */
+    U8                      Reserved2;                  /* 0x03 */
+    U16                     NumberOfLayouts;            /* 0x04 */
+    U16                     RegionsPerLayout;           /* 0x06 */
+    U16                     MinimumSectorAlignment;     /* 0x08 */
+    U16                     Reserved3;                  /* 0x0A */
+    U32                     Reserved4;                  /* 0x0C */
+    MPI2_FLASH_LAYOUT       Layout[MPI2_FLASH_NUMBER_OF_LAYOUTS];/* 0x10 */
+} MPI2_FLASH_LAYOUT_DATA, MPI2_POINTER PTR_MPI2_FLASH_LAYOUT_DATA,
+  Mpi2FlashLayoutData_t, MPI2_POINTER pMpi2FlashLayoutData_t;
+
+/* defines for the RegionType field */
+#define MPI2_FLASH_REGION_UNUSED                (0x00)
+#define MPI2_FLASH_REGION_FIRMWARE              (0x01)
+#define MPI2_FLASH_REGION_BIOS                  (0x02)
+#define MPI2_FLASH_REGION_NVDATA                (0x03)
+#define MPI2_FLASH_REGION_FIRMWARE_BACKUP       (0x05)
+#define MPI2_FLASH_REGION_MFG_INFORMATION       (0x06)
+#define MPI2_FLASH_REGION_CONFIG_1              (0x07)
+#define MPI2_FLASH_REGION_CONFIG_2              (0x08)
+#define MPI2_FLASH_REGION_MEGARAID              (0x09)
+#define MPI2_FLASH_REGION_INIT                  (0x0A)
+
+/* ImageRevision */
+#define MPI2_FLASH_LAYOUT_IMAGE_REVISION        (0x00)
+
+
+
+/* Supported Devices Extended Image Data */
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check NumberOfDevices at runtime.
+ */
+#ifndef MPI2_SUPPORTED_DEVICES_IMAGE_NUM_DEVICES
+#define MPI2_SUPPORTED_DEVICES_IMAGE_NUM_DEVICES    (1)
+#endif
+
+typedef struct _MPI2_SUPPORTED_DEVICE
+{
+    U16                     DeviceID;                   /* 0x00 */
+    U16                     VendorID;                   /* 0x02 */
+    U16                     DeviceIDMask;               /* 0x04 */
+    U16                     Reserved1;                  /* 0x06 */
+    U8                      LowPCIRev;                  /* 0x08 */
+    U8                      HighPCIRev;                 /* 0x09 */
+    U16                     Reserved2;                  /* 0x0A */
+    U32                     Reserved3;                  /* 0x0C */
+} MPI2_SUPPORTED_DEVICE, MPI2_POINTER PTR_MPI2_SUPPORTED_DEVICE,
+  Mpi2SupportedDevice_t, MPI2_POINTER pMpi2SupportedDevice_t;
+
+typedef struct _MPI2_SUPPORTED_DEVICES_DATA
+{
+    U8                      ImageRevision;              /* 0x00 */
+    U8                      Reserved1;                  /* 0x01 */
+    U8                      NumberOfDevices;            /* 0x02 */
+    U8                      Reserved2;                  /* 0x03 */
+    U32                     Reserved3;                  /* 0x04 */
+    MPI2_SUPPORTED_DEVICE   SupportedDevice[MPI2_SUPPORTED_DEVICES_IMAGE_NUM_DEVICES]; /* 0x08 */
+} MPI2_SUPPORTED_DEVICES_DATA, MPI2_POINTER PTR_MPI2_SUPPORTED_DEVICES_DATA,
+  Mpi2SupportedDevicesData_t, MPI2_POINTER pMpi2SupportedDevicesData_t;
+
+/* ImageRevision */
+#define MPI2_SUPPORTED_DEVICES_IMAGE_REVISION   (0x00)
+
+
+/* Init Extended Image Data */
+
+typedef struct _MPI2_INIT_IMAGE_FOOTER
+
+{
+    U32                     BootFlags;                  /* 0x00 */
+    U32                     ImageSize;                  /* 0x04 */
+    U32                     Signature0;                 /* 0x08 */
+    U32                     Signature1;                 /* 0x0C */
+    U32                     Signature2;                 /* 0x10 */
+    U32                     ResetVector;                /* 0x14 */
+} MPI2_INIT_IMAGE_FOOTER, MPI2_POINTER PTR_MPI2_INIT_IMAGE_FOOTER,
+  Mpi2InitImageFooter_t, MPI2_POINTER pMpi2InitImageFooter_t;
+
+/* defines for the BootFlags field */
+#define MPI2_INIT_IMAGE_BOOTFLAGS_OFFSET        (0x00)
+
+/* defines for the ImageSize field */
+#define MPI2_INIT_IMAGE_IMAGESIZE_OFFSET        (0x04)
+
+/* defines for the Signature0 field */
+#define MPI2_INIT_IMAGE_SIGNATURE0_OFFSET       (0x08)
+#define MPI2_INIT_IMAGE_SIGNATURE0              (0x5AA55AEA)
+
+/* defines for the Signature1 field */
+#define MPI2_INIT_IMAGE_SIGNATURE1_OFFSET       (0x0C)
+#define MPI2_INIT_IMAGE_SIGNATURE1              (0xA55AEAA5)
+
+/* defines for the Signature2 field */
+#define MPI2_INIT_IMAGE_SIGNATURE2_OFFSET       (0x10)
+#define MPI2_INIT_IMAGE_SIGNATURE2              (0x5AEAA55A)
+
+/* Signature fields as individual bytes */
+#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_0        (0xEA)
+#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_1        (0x5A)
+#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_2        (0xA5)
+#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_3        (0x5A)
+
+#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_4        (0xA5)
+#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_5        (0xEA)
+#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_6        (0x5A)
+#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_7        (0xA5)
+
+#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_8        (0x5A)
+#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_9        (0xA5)
+#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_A        (0xEA)
+#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_B        (0x5A)
+
+/* defines for the ResetVector field */
+#define MPI2_INIT_IMAGE_RESETVECTOR_OFFSET      (0x14)
+
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/sys/scsi/adapters/mpt_sas/mpi/mpi2_sas.h	Fri Jun 19 20:12:07 2009 +0800
@@ -0,0 +1,327 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2000 to 2009, LSI Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms of all code within
+ * this file that is exclusively owned by LSI, with or without
+ * modification, is permitted provided that, in addition to the CDDL 1.0
+ * License requirements, the following conditions are met:
+ *
+ *    Neither the name of the author nor the names of its contributors may be
+ *    used to endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ */
+
+/*
+ *           Name:  mpi2_sas.h
+ *          Title:  MPI Serial Attached SCSI structures and definitions
+ *  Creation Date:  February 9, 2007
+ *
+ *  mpi2.h Version:  02.00.02
+ *
+ *  Version History
+ *  ---------------
+ *
+ *  Date      Version   Description
+ *  --------  --------  ------------------------------------------------------
+ *  04-30-07  02.00.00  Corresponds to Fusion-MPT MPI Specification Rev A.
+ *  06-26-07  02.00.01  Added Clear All Persistent Operation to SAS IO Unit
+ *                      Control Request.
+ *  10-02-08  02.00.02  Added Set IOC Parameter Operation to SAS IO Unit Control
+ *                      Request.
+ *  --------------------------------------------------------------------------
+ */
+
+#ifndef MPI2_SAS_H
+#define MPI2_SAS_H
+
+/*
+ * Values for SASStatus.
+ */
+#define MPI2_SASSTATUS_SUCCESS                          (0x00)
+#define MPI2_SASSTATUS_UNKNOWN_ERROR                    (0x01)
+#define MPI2_SASSTATUS_INVALID_FRAME                    (0x02)
+#define MPI2_SASSTATUS_UTC_BAD_DEST                     (0x03)
+#define MPI2_SASSTATUS_UTC_BREAK_RECEIVED               (0x04)
+#define MPI2_SASSTATUS_UTC_CONNECT_RATE_NOT_SUPPORTED   (0x05)
+#define MPI2_SASSTATUS_UTC_PORT_LAYER_REQUEST           (0x06)
+#define MPI2_SASSTATUS_UTC_PROTOCOL_NOT_SUPPORTED       (0x07)
+#define MPI2_SASSTATUS_UTC_STP_RESOURCES_BUSY           (0x08)
+#define MPI2_SASSTATUS_UTC_WRONG_DESTINATION            (0x09)
+#define MPI2_SASSTATUS_SHORT_INFORMATION_UNIT           (0x0A)
+#define MPI2_SASSTATUS_LONG_INFORMATION_UNIT            (0x0B)
+#define MPI2_SASSTATUS_XFER_RDY_INCORRECT_WRITE_DATA    (0x0C)
+#define MPI2_SASSTATUS_XFER_RDY_REQUEST_OFFSET_ERROR    (0x0D)
+#define MPI2_SASSTATUS_XFER_RDY_NOT_EXPECTED            (0x0E)
+#define MPI2_SASSTATUS_DATA_INCORRECT_DATA_LENGTH       (0x0F)
+#define MPI2_SASSTATUS_DATA_TOO_MUCH_READ_DATA          (0x10)
+#define MPI2_SASSTATUS_DATA_OFFSET_ERROR                (0x11)
+#define MPI2_SASSTATUS_SDSF_NAK_RECEIVED                (0x12)
+#define MPI2_SASSTATUS_SDSF_CONNECTION_FAILED           (0x13)
+#define MPI2_SASSTATUS_INITIATOR_RESPONSE_TIMEOUT       (0x14)
+
+
+/*
+ * Values for the SAS DeviceInfo field used in SAS Device Status Change Event
+ * data and SAS Configuration pages.
+ */
+#define MPI2_SAS_DEVICE_INFO_SEP                (0x00004000)
+#define MPI2_SAS_DEVICE_INFO_ATAPI_DEVICE       (0x00002000)
+#define MPI2_SAS_DEVICE_INFO_LSI_DEVICE         (0x00001000)
+#define MPI2_SAS_DEVICE_INFO_DIRECT_ATTACH      (0x00000800)
+#define MPI2_SAS_DEVICE_INFO_SSP_TARGET         (0x00000400)
+#define MPI2_SAS_DEVICE_INFO_STP_TARGET         (0x00000200)
+#define MPI2_SAS_DEVICE_INFO_SMP_TARGET         (0x00000100)
+#define MPI2_SAS_DEVICE_INFO_SATA_DEVICE        (0x00000080)
+#define MPI2_SAS_DEVICE_INFO_SSP_INITIATOR      (0x00000040)
+#define MPI2_SAS_DEVICE_INFO_STP_INITIATOR      (0x00000020)
+#define MPI2_SAS_DEVICE_INFO_SMP_INITIATOR      (0x00000010)
+#define MPI2_SAS_DEVICE_INFO_SATA_HOST          (0x00000008)
+
+#define MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE   (0x00000007)
+#define MPI2_SAS_DEVICE_INFO_NO_DEVICE          (0x00000000)
+#define MPI2_SAS_DEVICE_INFO_END_DEVICE         (0x00000001)
+#define MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER      (0x00000002)
+#define MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER    (0x00000003)
+
+
+/*****************************************************************************
+*
+*        SAS Messages
+*
+*****************************************************************************/
+
+/****************************************************************************
+*  SMP Passthrough messages
+****************************************************************************/
+
+/* SMP Passthrough Request Message */
+typedef struct _MPI2_SMP_PASSTHROUGH_REQUEST
+{
+    U8                      PassthroughFlags;   /* 0x00 */
+    U8                      PhysicalPort;       /* 0x01 */
+    U8                      ChainOffset;        /* 0x02 */
+    U8                      Function;           /* 0x03 */
+    U16                     RequestDataLength;  /* 0x04 */
+    U8                      SGLFlags;           /* 0x06 */
+    U8                      MsgFlags;           /* 0x07 */
+    U8                      VP_ID;              /* 0x08 */
+    U8                      VF_ID;              /* 0x09 */
+    U16                     Reserved1;          /* 0x0A */
+    U32                     Reserved2;          /* 0x0C */
+    U64                     SASAddress;         /* 0x10 */
+    U32                     Reserved3;          /* 0x18 */
+    U32                     Reserved4;          /* 0x1C */
+    MPI2_SIMPLE_SGE_UNION   SGL;                /* 0x20 */
+} MPI2_SMP_PASSTHROUGH_REQUEST, MPI2_POINTER PTR_MPI2_SMP_PASSTHROUGH_REQUEST,
+  Mpi2SmpPassthroughRequest_t, MPI2_POINTER pMpi2SmpPassthroughRequest_t;
+
+/* values for PassthroughFlags field */
+#define MPI2_SMP_PT_REQ_PT_FLAGS_IMMEDIATE      (0x80)
+
+/* values for SGLFlags field are in the SGL section of mpi2.h */
+
+
+/* SMP Passthrough Reply Message */
+typedef struct _MPI2_SMP_PASSTHROUGH_REPLY
+{
+    U8                      PassthroughFlags;   /* 0x00 */
+    U8                      PhysicalPort;       /* 0x01 */
+    U8                      MsgLength;          /* 0x02 */
+    U8                      Function;           /* 0x03 */
+    U16                     ResponseDataLength; /* 0x04 */
+    U8                      SGLFlags;           /* 0x06 */
+    U8                      MsgFlags;           /* 0x07 */
+    U8                      VP_ID;              /* 0x08 */
+    U8                      VF_ID;              /* 0x09 */
+    U16                     Reserved1;          /* 0x0A */
+    U8                      Reserved2;          /* 0x0C */
+    U8                      SASStatus;          /* 0x0D */
+    U16                     IOCStatus;          /* 0x0E */
+    U32                     IOCLogInfo;         /* 0x10 */
+    U32                     Reserved3;          /* 0x14 */
+    U8                      ResponseData[4];    /* 0x18 */
+} MPI2_SMP_PASSTHROUGH_REPLY, MPI2_POINTER PTR_MPI2_SMP_PASSTHROUGH_REPLY,
+  Mpi2SmpPassthroughReply_t, MPI2_POINTER pMpi2SmpPassthroughReply_t;
+
+/* values for PassthroughFlags field */
+#define MPI2_SMP_PT_REPLY_PT_FLAGS_IMMEDIATE    (0x80)
+
+/* values for SASStatus field are at the top of this file */
+
+
+/****************************************************************************
+*  SATA Passthrough messages
+****************************************************************************/
+
+/* SATA Passthrough Request Message */
+typedef struct _MPI2_SATA_PASSTHROUGH_REQUEST
+{
+    U16                     DevHandle;          /* 0x00 */
+    U8                      ChainOffset;        /* 0x02 */
+    U8                      Function;           /* 0x03 */
+    U16                     PassthroughFlags;   /* 0x04 */
+    U8                      SGLFlags;           /* 0x06 */
+    U8                      MsgFlags;           /* 0x07 */
+    U8                      VP_ID;              /* 0x08 */
+    U8                      VF_ID;              /* 0x09 */
+    U16                     Reserved1;          /* 0x0A */
+    U32                     Reserved2;          /* 0x0C */
+    U32                     Reserved3;          /* 0x10 */
+    U32                     Reserved4;          /* 0x14 */
+    U32                     DataLength;         /* 0x18 */
+    U8                      CommandFIS[20];     /* 0x1C */
+    MPI2_SIMPLE_SGE_UNION   SGL;                /* 0x20 */
+} MPI2_SATA_PASSTHROUGH_REQUEST, MPI2_POINTER PTR_MPI2_SATA_PASSTHROUGH_REQUEST,
+  Mpi2SataPassthroughRequest_t, MPI2_POINTER pMpi2SataPassthroughRequest_t;
+
+/* values for PassthroughFlags field */
+#define MPI2_SATA_PT_REQ_PT_FLAGS_EXECUTE_DIAG      (0x0100)
+#define MPI2_SATA_PT_REQ_PT_FLAGS_DMA               (0x0020)
+#define MPI2_SATA_PT_REQ_PT_FLAGS_PIO               (0x0010)
+#define MPI2_SATA_PT_REQ_PT_FLAGS_UNSPECIFIED_VU    (0x0004)
+#define MPI2_SATA_PT_REQ_PT_FLAGS_WRITE             (0x0002)
+#define MPI2_SATA_PT_REQ_PT_FLAGS_READ              (0x0001)
+
+/* values for SGLFlags field are in the SGL section of mpi2.h */
+
+
+/* SATA Passthrough Reply Message */
+typedef struct _MPI2_SATA_PASSTHROUGH_REPLY
+{
+    U16                     DevHandle;          /* 0x00 */
+    U8                      MsgLength;          /* 0x02 */
+    U8                      Function;           /* 0x03 */
+    U16                     PassthroughFlags;   /* 0x04 */
+    U8                      SGLFlags;           /* 0x06 */
+    U8                      MsgFlags;           /* 0x07 */
+    U8                      VP_ID;              /* 0x08 */
+    U8                      VF_ID;              /* 0x09 */
+    U16                     Reserved1;          /* 0x0A */
+    U8                      Reserved2;          /* 0x0C */
+    U8                      SASStatus;          /* 0x0D */
+    U16                     IOCStatus;          /* 0x0E */
+    U32                     IOCLogInfo;         /* 0x10 */
+    U8                      StatusFIS[20];      /* 0x14 */
+    U32                     StatusControlRegisters; /* 0x28 */
+    U32                     TransferCount;      /* 0x2C */
+} MPI2_SATA_PASSTHROUGH_REPLY, MPI2_POINTER PTR_MPI2_SATA_PASSTHROUGH_REPLY,
+  Mpi2SataPassthroughReply_t, MPI2_POINTER pMpi2SataPassthroughReply_t;
+
+/* values for SASStatus field are at the top of this file */
+
+
+/****************************************************************************
+*  SAS IO Unit Control messages
+****************************************************************************/
+
+/* SAS IO Unit Control Request Message */
+typedef struct _MPI2_SAS_IOUNIT_CONTROL_REQUEST
+{
+    U8                      Operation;          /* 0x00 */
+    U8                      Reserved1;          /* 0x01 */
+    U8                      ChainOffset;        /* 0x02 */
+    U8                      Function;           /* 0x03 */
+    U16                     DevHandle;          /* 0x04 */
+    U8                      IOCParameter;       /* 0x06 */
+    U8                      MsgFlags;           /* 0x07 */
+    U8                      VP_ID;              /* 0x08 */
+    U8                      VF_ID;              /* 0x09 */
+    U16                     Reserved3;          /* 0x0A */
+    U16                     Reserved4;          /* 0x0C */
+    U8                      PhyNum;             /* 0x0E */
+    U8                      PrimFlags;          /* 0x0F */
+    U32                     Primitive;          /* 0x10 */
+    U8                      LookupMethod;       /* 0x14 */
+    U8                      Reserved5;          /* 0x15 */
+    U16                     SlotNumber;         /* 0x16 */
+    U64                     LookupAddress;      /* 0x18 */
+    U32                     IOCParameterValue;  /* 0x20 */
+    U32                     Reserved7;          /* 0x24 */
+    U32                     Reserved8;          /* 0x28 */
+} MPI2_SAS_IOUNIT_CONTROL_REQUEST,
+  MPI2_POINTER PTR_MPI2_SAS_IOUNIT_CONTROL_REQUEST,
+  Mpi2SasIoUnitControlRequest_t, MPI2_POINTER pMpi2SasIoUnitControlRequest_t;
+
+/* values for the Operation field */
+#define MPI2_SAS_OP_CLEAR_ALL_PERSISTENT        (0x02)
+#define MPI2_SAS_OP_PHY_LINK_RESET              (0x06)
+#define MPI2_SAS_OP_PHY_HARD_RESET              (0x07)
+#define MPI2_SAS_OP_PHY_CLEAR_ERROR_LOG         (0x08)
+#define MPI2_SAS_OP_SEND_PRIMITIVE              (0x0A)
+#define MPI2_SAS_OP_FORCE_FULL_DISCOVERY        (0x0B)
+#define MPI2_SAS_OP_TRANSMIT_PORT_SELECT_SIGNAL (0x0C)
+#define MPI2_SAS_OP_REMOVE_DEVICE               (0x0D)
+#define MPI2_SAS_OP_LOOKUP_MAPPING              (0x0E)
+#define MPI2_SAS_OP_SET_IOC_PARAMETER           (0x0F)
+#define MPI2_SAS_OP_PRODUCT_SPECIFIC_MIN        (0x80)
+
+/* values for the PrimFlags field */
+#define MPI2_SAS_PRIMFLAGS_SINGLE               (0x08)
+#define MPI2_SAS_PRIMFLAGS_TRIPLE               (0x02)
+#define MPI2_SAS_PRIMFLAGS_REDUNDANT            (0x01)
+
+/* values for the LookupMethod field */
+#define MPI2_SAS_LOOKUP_METHOD_SAS_ADDRESS          (0x01)
+#define MPI2_SAS_LOOKUP_METHOD_SAS_ENCLOSURE_SLOT   (0x02)
+#define MPI2_SAS_LOOKUP_METHOD_SAS_DEVICE_NAME      (0x03)
+
+
+/* SAS IO Unit Control Reply Message */
+typedef struct _MPI2_SAS_IOUNIT_CONTROL_REPLY
+{
+    U8                      Operation;          /* 0x00 */
+    U8                      Reserved1;          /* 0x01 */
+    U8                      MsgLength;          /* 0x02 */
+    U8                      Function;           /* 0x03 */
+    U16                     DevHandle;          /* 0x04 */
+    U8                      IOCParameter;       /* 0x06 */
+    U8                      MsgFlags;           /* 0x07 */
+    U8                      VP_ID;              /* 0x08 */
+    U8                      VF_ID;              /* 0x09 */
+    U16                     Reserved3;          /* 0x0A */
+    U16                     Reserved4;          /* 0x0C */
+    U16                     IOCStatus;          /* 0x0E */
+    U32                     IOCLogInfo;         /* 0x10 */
+} MPI2_SAS_IOUNIT_CONTROL_REPLY,
+  MPI2_POINTER PTR_MPI2_SAS_IOUNIT_CONTROL_REPLY,
+  Mpi2SasIoUnitControlReply_t, MPI2_POINTER pMpi2SasIoUnitControlReply_t;
+
+
+#endif
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/sys/scsi/adapters/mpt_sas/mpi/mpi2_type.h	Fri Jun 19 20:12:07 2009 +0800
@@ -0,0 +1,137 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2000 to 2009, LSI Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms of all code within
+ * this file that is exclusively owned by LSI, with or without
+ * modification, is permitted provided that, in addition to the CDDL 1.0
+ * License requirements, the following conditions are met:
+ *
+ *    Neither the name of the author nor the names of its contributors may be
+ *    used to endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ */
+
+/*
+ *           Name:  mpi2_type.h
+ *          Title:  MPI basic type definitions
+ *  Creation Date:  August 16, 2006
+ *
+ *    mpi2_type.h Version:  02.00.00
+ *
+ *  Version History
+ *  ---------------
+ *
+ *  Date      Version   Description
+ *  --------  --------  ------------------------------------------------------
+ *  04-30-07  02.00.00  Corresponds to Fusion-MPT MPI Specification Rev A.
+ *  --------------------------------------------------------------------------
+ */
+
+#ifndef MPI2_TYPE_H
+#define MPI2_TYPE_H
+
+
+/*******************************************************************************
+ * Define MPI2_POINTER if it hasn't already been defined. By default
+ * MPI2_POINTER is defined to be a near pointer. MPI2_POINTER can be defined as
+ * a far pointer by defining MPI2_POINTER as "far *" before this header file is
+ * included.
+ */
+#ifndef MPI2_POINTER
+#define MPI2_POINTER     *
+#endif
+
+/* the basic types may have already been included by mpi_type.h */
+#ifndef MPI_TYPE_H
+/*****************************************************************************
+*
+*               Basic Types
+*
+*****************************************************************************/
+
+typedef signed   char   S8;
+typedef unsigned char   U8;
+typedef signed   short  S16;
+typedef unsigned short  U16;
+
+
+#if defined(unix) || defined(__arm) || defined(ALPHA) || defined(__PPC__) || defined(__ppc)
+
+    typedef signed   int   S32;
+    typedef unsigned int   U32;
+
+#else
+
+    typedef signed   long  S32;
+    typedef unsigned long  U32;
+
+#endif
+
+
+typedef struct _S64
+{
+    U32          Low;
+    S32          High;
+} S64;
+
+typedef struct _U64
+{
+    U32          Low;
+    U32          High;
+} U64;
+
+
+/*****************************************************************************
+*
+*               Pointer Types
+*
+*****************************************************************************/
+
+typedef S8      *PS8;
+typedef U8      *PU8;
+typedef S16     *PS16;
+typedef U16     *PU16;
+typedef S32     *PS32;
+typedef U32     *PU32;
+typedef S64     *PS64;
+typedef U64     *PU64;
+
+#endif
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/sys/scsi/adapters/mpt_sas/mptsas_ioctl.h	Fri Jun 19 20:12:07 2009 +0800
@@ -0,0 +1,277 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Copyright (c) 2000 to 2009, LSI Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms of all code within
+ * this file that is exclusively owned by LSI, with or without
+ * modification, is permitted provided that, in addition to the CDDL 1.0
+ * License requirements, the following conditions are met:
+ *
+ *    Neither the name of the author nor the names of its contributors may be
+ *    used to endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ */
+
+#ifndef _MPTSAS_IOCTL_H
+#define	_MPTSAS_IOCTL_H
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+#include <sys/types.h>
+
+#define	MPTIOCTL			('I' << 8)
+#define	MPTIOCTL_GET_ADAPTER_DATA	(MPTIOCTL | 1)
+#define	MPTIOCTL_UPDATE_FLASH		(MPTIOCTL | 2)
+#define	MPTIOCTL_RESET_ADAPTER		(MPTIOCTL | 3)
+#define	MPTIOCTL_PASS_THRU		(MPTIOCTL | 4)
+#define	MPTIOCTL_EVENT_QUERY		(MPTIOCTL | 5)
+#define	MPTIOCTL_EVENT_ENABLE		(MPTIOCTL | 6)
+#define	MPTIOCTL_EVENT_REPORT		(MPTIOCTL | 7)
+#define	MPTIOCTL_GET_PCI_INFO		(MPTIOCTL | 8)
+#define	MPTIOCTL_DIAG_ACTION		(MPTIOCTL | 9)
+
+/*
+ *  The following are our ioctl() return status values.  If everything went
+ *  well, we return good status.  If the buffer length sent to us is too short
+ *  we return a status to tell the user.
+ */
+#define	MPTIOCTL_STATUS_GOOD		0
+#define	MPTIOCTL_STATUS_LEN_TOO_SHORT	1
+
+/*
+ *  The following is the MPTIOCTL_GET_ADAPTER_DATA data structure.  This data
+ *  structure is setup so that we hopefully are properly aligned for both
+ *  32-bit and 64-bit mode applications.
+ *
+ *  Adapter Type - Value = 4 = SCSI Protocol through SAS-2 adapter
+ *
+ *  MPI Port Number - The PCI Function number for this device
+ *
+ *  PCI Device HW Id - The PCI device number for this device
+ *
+ */
+#define	MPTIOCTL_ADAPTER_TYPE_SAS2	4
+typedef struct mptsas_adapter_data
+{
+	uint32_t	StructureLength;
+	uint32_t	AdapterType;
+	uint32_t	MpiPortNumber;
+	uint32_t	PCIDeviceHwId;
+	uint32_t	PCIDeviceHwRev;
+	uint32_t	SubSystemId;
+	uint32_t	SubsystemVendorId;
+	uint32_t	Reserved1;
+	uint32_t	MpiFirmwareVersion;
+	uint32_t	BiosVersion;
+	uint8_t		DriverVersion[32];
+	uint8_t		Reserved2;
+	uint8_t		ScsiId;
+	uint16_t	Reserved3;
+	uint32_t	PciInformation;
+	uint32_t	PciSegmentId;
+} mptsas_adapter_data_t;
+
+
+typedef struct mptsas_update_flash
+{
+	uint64_t	PtrBuffer;
+	uint32_t	ImageChecksum;
+	uint32_t	ImageOffset;
+	uint32_t	ImageSize;
+	uint32_t	ImageType;
+} mptsas_update_flash_t;
+
+
+#define	MPTSAS_PASS_THRU_DIRECTION_NONE		0
+#define	MPTSAS_PASS_THRU_DIRECTION_READ		1
+#define	MPTSAS_PASS_THRU_DIRECTION_WRITE	2
+#define	MPTSAS_PASS_THRU_DIRECTION_BOTH		3
+
+typedef struct mptsas_pass_thru
+{
+	uint64_t	PtrRequest;
+	uint64_t	PtrReply;
+	uint64_t	PtrData;
+	uint32_t	RequestSize;
+	uint32_t	ReplySize;
+	uint32_t	DataSize;
+	uint32_t	DataDirection;
+	uint64_t	PtrDataOut;
+	uint32_t	DataOutSize;
+	uint32_t	Timeout;
+} mptsas_pass_thru_t;
+
+
+/*
+ * Event queue defines
+ */
+#define	MPTSAS_EVENT_QUEUE_SIZE		(50) /* Max Events stored in driver */
+#define	MPTSAS_MAX_EVENT_DATA_LENGTH	(48) /* Size of each event in Dwords */
+
+typedef struct mptsas_event_query
+{
+	uint16_t	Entries;
+	uint16_t	Reserved;
+	uint32_t	Types[4];
+} mptsas_event_query_t;
+
+typedef struct mptsas_event_enable
+{
+	uint32_t	Types[4];
+} mptsas_event_enable_t;
+
+/*
+ * Event record entry for ioctl.
+ */
+typedef struct mptsas_event_entry
+{
+	uint32_t	Type;
+	uint32_t	Number;
+	uint32_t	Data[MPTSAS_MAX_EVENT_DATA_LENGTH];
+} mptsas_event_entry_t;
+
+typedef struct mptsas_event_report
+{
+	uint32_t		Size;
+	mptsas_event_entry_t	Events[1];
+} mptsas_event_report_t;
+
+
+typedef struct mptsas_pci_info
+{
+	uint32_t	BusNumber;
+	uint8_t		DeviceNumber;
+	uint8_t		FunctionNumber;
+	uint16_t	InterruptVector;
+	uint8_t		PciHeader[256];
+} mptsas_pci_info_t;
+
+
+typedef struct mptsas_diag_action
+{
+	uint32_t	Action;
+	uint32_t	Length;
+	uint64_t	PtrDiagAction;
+	uint32_t	ReturnCode;
+} mptsas_diag_action_t;
+
+#define	MPTSAS_FW_DIAGNOSTIC_BUFFER_COUNT	(3)
+#define	MPTSAS_FW_DIAGNOSTIC_UID_NOT_FOUND	(0xFF)
+
+#define	MPTSAS_FW_DIAG_NEW			(0x806E6577)
+
+#define	MPTSAS_FW_DIAG_TYPE_REGISTER		(0x00000001)
+#define	MPTSAS_FW_DIAG_TYPE_UNREGISTER		(0x00000002)
+#define	MPTSAS_FW_DIAG_TYPE_QUERY		(0x00000003)
+#define	MPTSAS_FW_DIAG_TYPE_READ_BUFFER		(0x00000004)
+#define	MPTSAS_FW_DIAG_TYPE_RELEASE		(0x00000005)
+
+#define	MPTSAS_FW_DIAG_INVALID_UID		(0x00000000)
+
+#define	MPTSAS_FW_DIAG_ERROR_SUCCESS		(0x00000000)
+#define	MPTSAS_FW_DIAG_ERROR_FAILURE		(0x00000001)
+#define	MPTSAS_FW_DIAG_ERROR_INVALID_PARAMETER	(0x00000002)
+#define	MPTSAS_FW_DIAG_ERROR_POST_FAILED	(0x00000010)
+#define	MPTSAS_FW_DIAG_ERROR_INVALID_UID	(0x00000011)
+#define	MPTSAS_FW_DIAG_ERROR_RELEASE_FAILED	(0x00000012)
+#define	MPTSAS_FW_DIAG_ERROR_NO_BUFFER		(0x00000013)
+#define	MPTSAS_FW_DIAG_ERROR_ALREADY_RELEASED	(0x00000014)
+
+
+typedef struct mptsas_fw_diag_register
+{
+	uint8_t		Reserved1;
+	uint8_t		BufferType;
+	uint16_t	ApplicationFlags;
+	uint32_t	DiagnosticFlags;
+	uint32_t	ProductSpecific[23];
+	uint32_t	RequestedBufferSize;
+	uint32_t	UniqueId;
+} mptsas_fw_diag_register_t;
+
+typedef struct mptsas_fw_diag_unregister
+{
+	uint32_t	UniqueId;
+} mptsas_fw_diag_unregister_t;
+
+#define	MPTSAS_FW_DIAG_FLAG_APP_OWNED		(0x0001)
+#define	MPTSAS_FW_DIAG_FLAG_BUFFER_VALID	(0x0002)
+#define	MPTSAS_FW_DIAG_FLAG_FW_BUFFER_ACCESS	(0x0004)
+
+typedef struct mptsas_fw_diag_query
+{
+	uint8_t		Reserved1;
+	uint8_t		BufferType;
+	uint16_t	ApplicationFlags;
+	uint32_t	DiagnosticFlags;
+	uint32_t	ProductSpecific[23];
+	uint32_t	TotalBufferSize;
+	uint32_t	DriverAddedBufferSize;
+	uint32_t	UniqueId;
+} mptsas_fw_diag_query_t;
+
+typedef struct mptsas_fw_diag_release
+{
+	uint32_t	UniqueId;
+} mptsas_fw_diag_release;
+
+#define	MPTSAS_FW_DIAG_FLAG_REREGISTER		(0x0001)
+#define	MPTSAS_FW_DIAG_FLAG_FORCE_RELEASE	(0x0002)
+
+typedef struct mptsas_diag_read_buffer
+{
+	uint8_t		Status;
+	uint8_t		Reserved;
+	uint16_t	Flags;
+	uint32_t	StartingOffset;
+	uint32_t	BytesToRead;
+	uint32_t	UniqueId;
+	uint32_t	DataBuffer[1];
+} mptsas_diag_read_buffer_t;
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif	/* _MPTSAS_IOCTL_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/sys/scsi/adapters/mpt_sas/mptsas_var.h	Fri Jun 19 20:12:07 2009 +0800
@@ -0,0 +1,1324 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Copyright (c) 2000 to 2009, LSI Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms of all code within
+ * this file that is exclusively owned by LSI, with or without
+ * modification, is permitted provided that, in addition to the CDDL 1.0
+ * License requirements, the following conditions are met:
+ *
+ *    Neither the name of the author nor the names of its contributors may be
+ *    used to endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ */
+
+#ifndef _SYS_SCSI_ADAPTERS_MPTVAR_H
+#define	_SYS_SCSI_ADAPTERS_MPTVAR_H
+
+#include <sys/byteorder.h>
+#include <sys/isa_defs.h>
+#include <sys/sunmdi.h>
+#include <sys/mdi_impldefs.h>
+#include <sys/scsi/adapters/mpt_sas/mptsas_ioctl.h>
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+/*
+ * Compile options
+ */
+#ifdef DEBUG
+#define	MPTSAS_DEBUG		/* turn on debugging code */
+#endif	/* DEBUG */
+
+#define	MPTSAS_INITIAL_SOFT_SPACE	4
+
+#define	MAX_MPI_PORTS		16
+
+#define	MPTSAS_MAX_PHYS		8
+
+#define	MPTSAS_INVALID_DEVHDL	0xffff
+
+/*
+ * MPT HW defines
+ */
+#define	MPTSAS_MAX_DISKS_IN_CONFIG	14
+#define	MPTSAS_MAX_DISKS_IN_VOL		10
+#define	MPTSAS_MAX_HOTSPARES		2
+#define	MPTSAS_MAX_RAIDVOLS		2
+#define	MPTSAS_MAX_RAIDCONFIGS		5
+
+/*
+ * 64-bit SAS WWN is displayed as 16 characters as HEX characters,
+ * plus one means the end of the string '\0'.
+ */
+#define	MPTSAS_WWN_STRLEN 16 + 1
+#define	MPTSAS_MAX_GUID_LEN	64
+
+/*
+ * DMA routine flags
+ */
+#define	MPTSAS_DMA_HANDLE_ALLOCD	0x2
+#define	MPTSAS_DMA_MEMORY_ALLOCD	0x4
+#define	MPTSAS_DMA_HANDLE_BOUND	0x8
+
+/*
+ * If the HBA supports DMA or bus-mastering, you may have your own
+ * scatter-gather list for physically non-contiguous memory in one
+ * I/O operation; if so, there's probably a size for that list.
+ * It must be placed in the ddi_dma_lim_t structure, so that the system
+ * DMA-support routines can use it to break up the I/O request, so we
+ * define it here.
+ */
+#if defined(__sparc)
+#define	MPTSAS_MAX_DMA_SEGS	1
+#define	MPTSAS_MAX_CMD_SEGS	1
+#else
+#define	MPTSAS_MAX_DMA_SEGS	256
+#define	MPTSAS_MAX_CMD_SEGS	257
+#endif
+#define	MPTSAS_MAX_FRAME_SGES(mpt) \
+	(((mpt->m_req_frame_size - (sizeof (MPI2_SCSI_IO_REQUEST))) / 8) + 1)
+
+/*
+ * Caculating how many 64-bit DMA simple elements can be stored in the first
+ * frame. Note that msg_scsi_io_request contains 2 double-words (8 bytes) for
+ * element storage.  And 64-bit dma element is 3 double-words (12 bytes) in
+ * size.
+ */
+#define	MPTSAS_MAX_FRAME_SGES64(mpt) \
+	((mpt->m_req_frame_size - \
+	(sizeof (MPI2_SCSI_IO_REQUEST)) + sizeof (MPI2_SGE_IO_UNION)) / 12)
+
+/*
+ * Scatter-gather list structure defined by HBA hardware
+ */
+typedef	struct NcrTableIndirect {	/* Table Indirect entries */
+	uint32_t count;		/* 24 bit count */
+	union {
+		uint32_t address32;	/* 32 bit address */
+		struct {
+			uint32_t Low;
+			uint32_t High;
+		} address64;		/* 64 bit address */
+	} addr;
+} mptti_t;
+
+/*
+ * preferred pkt_private length in 64-bit quantities
+ */
+#ifdef	_LP64
+#define	PKT_PRIV_SIZE	2
+#define	PKT_PRIV_LEN	16	/* in bytes */
+#else /* _ILP32 */
+#define	PKT_PRIV_SIZE	1
+#define	PKT_PRIV_LEN	8	/* in bytes */
+#endif
+
+#define	PKT2CMD(pkt)	((struct mptsas_cmd *)((pkt)->pkt_ha_private))
+#define	CMD2PKT(cmdp)	((struct scsi_pkt *)((cmdp)->cmd_pkt))
+#define	EXTCMDS_STATUS_SIZE (sizeof (struct scsi_arq_status))
+
+/*
+ * get offset of item in structure
+ */
+#define	MPTSAS_GET_ITEM_OFF(type, member) ((size_t)(&((type *)0)->member))
+
+/*
+ * WWID provided by LSI firmware is generated by firmware but the WWID is not
+ * IEEE NAA standard format, OBP has no chance to distinguish format of unit
+ * address. According LSI's confirmation, the top nibble of RAID WWID is
+ * meanless, so the consensus between Solaris and OBP is to replace top nibble
+ * of WWID provided by LSI to "3" always to hint OBP that this is a RAID WWID
+ * format unit address.
+ */
+#define	MPTSAS_RAID_WWID(wwid) \
+	((wwid & 0x0FFFFFFFFFFFFFFF) | 0x3000000000000000)
+
+typedef	struct mptsas_target {
+		uint64_t		m_sas_wwn;	/* hash key1 */
+		uint8_t			m_phymask;	/* hash key2 */
+		/*
+		 * m_dr_flag is a flag for DR, make sure the member
+		 * take the place of dr_flag of mptsas_hash_data.
+		 */
+		uint8_t			m_dr_flag;	/* dr_flag */
+		uint16_t		m_devhdl;
+		uint32_t		m_deviceinfo;
+		uint8_t			m_phynum;
+		uint32_t		m_dups;
+		int32_t			m_timeout;
+		int32_t			m_timebase;
+		int32_t			m_t_throttle;
+		int32_t			m_t_ncmds;
+		int32_t			m_reset_delay;
+		int32_t			m_t_nwait;
+
+		uint16_t		m_qfull_retry_interval;
+		uint8_t			m_qfull_retries;
+
+} mptsas_target_t;
+
+typedef struct mptsas_smp {
+	uint64_t	m_sasaddr;	/* hash key1 */
+	uint8_t		m_phymask;	/* hash key2 */
+	uint8_t		reserved1;
+	uint16_t	m_devhdl;
+	uint32_t	m_deviceinfo;
+} mptsas_smp_t;
+
+typedef struct mptsas_hash_data {
+	uint64_t	key1;
+	uint8_t		key2;
+	uint8_t		dr_flag;
+	uint16_t	devhdl;
+	uint32_t	device_info;
+} mptsas_hash_data_t;
+
+typedef struct mptsas_cache_frames {
+	ddi_dma_handle_t m_dma_hdl;
+	ddi_acc_handle_t m_acc_hdl;
+	caddr_t m_frames_addr;
+	uint32_t m_phys_addr;
+} mptsas_cache_frames_t;
+
+typedef struct	mptsas_cmd {
+	uint_t			cmd_flags;	/* flags from scsi_init_pkt */
+	ddi_dma_handle_t	cmd_dmahandle;	/* dma handle */
+	ddi_dma_cookie_t	cmd_cookie;
+	uint_t			cmd_cookiec;
+	uint_t			cmd_winindex;
+	uint_t			cmd_nwin;
+	uint_t			cmd_cur_cookie;
+	off_t			cmd_dma_offset;
+	size_t			cmd_dma_len;
+	uint32_t		cmd_totaldmacount;
+
+	ddi_dma_handle_t	cmd_arqhandle;	/* dma arq handle */
+	ddi_dma_cookie_t	cmd_arqcookie;
+	struct buf		*cmd_arq_buf;
+	ddi_dma_handle_t	cmd_ext_arqhandle; /* dma extern arq handle */
+	ddi_dma_cookie_t	cmd_ext_arqcookie;
+	struct buf		*cmd_ext_arq_buf;
+
+	int			cmd_pkt_flags;
+
+	/* timer for command in active slot */
+	int			cmd_active_timeout;
+
+	struct scsi_pkt		*cmd_pkt;
+	struct scsi_arq_status	cmd_scb;
+	uchar_t			cmd_cdblen;	/* length of cdb */
+	uchar_t			cmd_rqslen;	/* len of requested rqsense */
+	uchar_t			cmd_privlen;
+	uint_t			cmd_scblen;
+	uint32_t		cmd_dmacount;
+	uint64_t		cmd_dma_addr;
+	uchar_t			cmd_age;
+	ushort_t		cmd_qfull_retries;
+	uchar_t			cmd_queued;	/* true if queued */
+	struct mptsas_cmd	*cmd_linkp;
+	mptti_t			*cmd_sg; /* Scatter/Gather structure */
+	uchar_t			cmd_cdb[SCSI_CDB_SIZE];
+	uint64_t		cmd_pkt_private[PKT_PRIV_LEN];
+	uint32_t		cmd_slot;
+	uint32_t		ioc_cmd_slot;
+
+	mptsas_cache_frames_t	*cmd_extra_frames;
+
+	uint32_t		cmd_rfm;
+	mptsas_target_t		*cmd_tgt_addr;
+} mptsas_cmd_t;
+
+/*
+ * These are the defined cmd_flags for this structure.
+ */
+#define	CFLAG_CMDDISC		0x000001 /* cmd currently disconnected */
+#define	CFLAG_WATCH		0x000002 /* watchdog time for this command */
+#define	CFLAG_FINISHED		0x000004 /* command completed */
+#define	CFLAG_CHKSEG		0x000008 /* check cmd_data within seg */
+#define	CFLAG_COMPLETED		0x000010 /* completion routine called */
+#define	CFLAG_PREPARED		0x000020 /* pkt has been init'ed */
+#define	CFLAG_IN_TRANSPORT	0x000040 /* in use by host adapter driver */
+#define	CFLAG_RESTORE_PTRS	0x000080 /* implicit restore ptr on reconnect */
+#define	CFLAG_ARQ_IN_PROGRESS	0x000100 /* auto request sense in progress */
+#define	CFLAG_TRANFLAG		0x0001ff /* covers transport part of flags */
+#define	CFLAG_TM_CMD		0x000200 /* cmd is a task management command */
+#define	CFLAG_CMDARQ		0x000400 /* cmd is a 'rqsense' command */
+#define	CFLAG_DMAVALID		0x000800 /* dma mapping valid */
+#define	CFLAG_DMASEND		0x001000 /* data is going 'out' */
+#define	CFLAG_CMDIOPB		0x002000 /* this is an 'iopb' packet */
+#define	CFLAG_CDBEXTERN		0x004000 /* cdb kmem_alloc'd */
+#define	CFLAG_SCBEXTERN		0x008000 /* scb kmem_alloc'd */
+#define	CFLAG_FREE		0x010000 /* packet is on free list */
+#define	CFLAG_PRIVEXTERN	0x020000 /* target private kmem_alloc'd */
+#define	CFLAG_DMA_PARTIAL	0x040000 /* partial xfer OK */
+#define	CFLAG_QFULL_STATUS	0x080000 /* pkt got qfull status */
+#define	CFLAG_TIMEOUT		0x100000 /* passthru/config command timeout */
+#define	CFLAG_PMM_RECEIVED	0x200000 /* use cmd_pmm* for saving pointers */
+#define	CFLAG_RETRY		0x400000 /* cmd has been retried */
+#define	CFLAG_CMDIOC		0x800000 /* cmd is just for for ioc, no io */
+#define	CFLAG_EXTARQBUFVALID	0x1000000 /* extern arq buf handle is valid */
+#define	CFLAG_PASSTHRU		0x2000000 /* cmd is a passthrough command */
+#define	CFLAG_XARQ		0x4000000 /* cmd requests for extra sense */
+#define	CFLAG_CMDACK		0x8000000 /* cmd for event ack */
+#define	CFLAG_TXQ		0x10000000 /* cmd queued in the tx_waitq */
+#define	CFLAG_FW_CMD		0x20000000 /* cmd is a fw up/down command */
+#define	CFLAG_CONFIG		0x40000000 /* cmd is for config header/page */
+
+#define	MPTSAS_SCSI_REPORTLUNS_ADDRESS_SIZE			8
+#define	MPTSAS_SCSI_REPORTLUNS_ADDRESS_MASK			0xC0
+#define	MPTSAS_SCSI_REPORTLUNS_ADDRESS_PERIPHERAL			0x00
+#define	MPTSAS_SCSI_REPORTLUNS_ADDRESS_FLAT_SPACE			0x40
+#define	MPTSAS_SCSI_REPORTLUNS_ADDRESS_LOGICAL_UNIT		0x80
+#define	MPTSAS_SCSI_REPORTLUNS_ADDRESS_EXTENDED_UNIT		0xC0
+#define	MPTSAS_SCSI_REPORTLUNS_ADDRESS_LOGICAL_UNIT_2B		0x00
+#define	MPTSAS_SCSI_REPORTLUNS_ADDRESS_LOGICAL_UNIT_4B		0x01
+#define	MPTSAS_SCSI_REPORTLUNS_ADDRESS_LOGICAL_UNIT_6B		0x10
+#define	MPTSAS_SCSI_REPORTLUNS_ADDRESS_LOGICAL_UNIT_8B		0x20
+#define	MPTSAS_SCSI_REPORTLUNS_ADDRESS_LOGICAL_UNIT_SIZE		0x30
+
+#define	MPTSAS_HASH_ARRAY_SIZE	16
+/*
+ * hash table definition
+ */
+
+#define	MPTSAS_HASH_FIRST	0xffff
+#define	MPTSAS_HASH_NEXT	0x0000
+
+/*
+ * passthrough request structure
+ */
+typedef struct mptsas_pt_request {
+	uint8_t *request;
+	uint32_t request_size;
+	uint32_t data_size;
+	uint32_t dataout_size;
+	uint32_t direction;
+	ddi_dma_cookie_t data_cookie;
+	ddi_dma_cookie_t dataout_cookie;
+} mptsas_pt_request_t;
+
+/*
+ * config page request structure
+ */
+typedef struct mptsas_config_request {
+	uint32_t	page_address;
+	uint8_t		action;
+	uint8_t		page_type;
+	uint8_t		page_number;
+	uint8_t		page_length;
+	uint8_t		page_version;
+	uint8_t		ext_page_type;
+	uint16_t	ext_page_length;
+} mptsas_config_request_t;
+
+typedef struct mptsas_hash_node {
+	void *data;
+	struct mptsas_hash_node *next;
+} mptsas_hash_node_t;
+
+typedef struct mptsas_hash_table {
+	struct mptsas_hash_node *head[MPTSAS_HASH_ARRAY_SIZE];
+	/*
+	 * last position in traverse
+	 */
+	struct mptsas_hash_node *cur;
+	uint16_t line;
+
+} mptsas_hash_table_t;
+
+/*
+ * RAID volume information
+ */
+typedef struct mptsas_raidvol {
+	ushort_t	m_israid;
+	uint16_t	m_raidhandle;
+	uint64_t	m_raidwwid;
+	uint8_t		m_state;
+	uint32_t	m_statusflags;
+	uint32_t	m_settings;
+	uint16_t	m_devhdl[MPTSAS_MAX_DISKS_IN_VOL];
+	uint8_t		m_disknum[MPTSAS_MAX_DISKS_IN_VOL];
+	ushort_t	m_diskstatus[MPTSAS_MAX_DISKS_IN_VOL];
+	uint64_t	m_raidsize;
+	int		m_raidlevel;
+	int		m_ndisks;
+	mptsas_target_t	*m_raidtgt;
+} mptsas_raidvol_t;
+
+/*
+ * RAID configurations
+ */
+typedef struct mptsas_raidconfig {
+		mptsas_raidvol_t	m_raidvol[MPTSAS_MAX_RAIDVOLS];
+		uint16_t		m_physdisk_devhdl[
+					    MPTSAS_MAX_DISKS_IN_CONFIG];
+		uint8_t			m_native;
+} m_raidconfig_t;
+
+/*
+ * Structure to hold active outstanding cmds.  Also, keep
+ * timeout on a per target basis.
+ */
+typedef struct mptsas_slots {
+	mptsas_hash_table_t	m_tgttbl;
+	mptsas_hash_table_t	m_smptbl;
+	m_raidconfig_t		m_raidconfig[MPTSAS_MAX_RAIDCONFIGS];
+	uint8_t			m_num_raid_configs;
+	uint16_t		m_tags;
+	uint32_t		m_buffer;
+	size_t			m_size;
+	uint16_t		m_n_slots;
+	mptsas_cmd_t		*m_slot[1];
+} mptsas_slots_t;
+
+/*
+ * Structure to hold command and packets for event ack
+ * and task management commands.
+ */
+typedef struct  m_event_struct {
+	struct mptsas_cmd		m_event_cmd;
+	struct m_event_struct	*m_event_linkp;
+	/*
+	 * event member record the failure event and eventcntx
+	 * event member would be used in send ack pending process
+	 */
+	uint32_t		m_event;
+	uint32_t		m_eventcntx;
+	uint_t			in_use;
+	struct scsi_pkt		m_event_pkt;	/* must be last */
+						/* ... scsi_pkt_size() */
+} m_event_struct_t;
+#define	M_EVENT_STRUCT_SIZE	(sizeof (m_event_struct_t) - \
+				sizeof (struct scsi_pkt) + scsi_pkt_size())
+
+#define	MAX_IOC_COMMANDS	8
+
+/*
+ * A pool of MAX_IOC_COMMANDS is maintained for event ack commands.
+ * A new event ack command requests mptsas_cmd and scsi_pkt structures
+ * from this pool, and returns it back when done.
+ */
+
+typedef struct m_replyh_arg {
+	void *mpt;
+	uint32_t rfm;
+} m_replyh_arg_t;
+_NOTE(DATA_READABLE_WITHOUT_LOCK(m_replyh_arg_t::mpt))
+_NOTE(DATA_READABLE_WITHOUT_LOCK(m_replyh_arg_t::rfm))
+
+/*
+ * Flags for DR handler topology change
+ */
+#define	MPTSAS_TOPO_FLAG_DIRECT_ATTACHED_DEVICE		0x0
+#define	MPTSAS_TOPO_FLAG_EXPANDER_ASSOCIATED		0x1
+#define	MPTSAS_TOPO_FLAG_LUN_ASSOCIATED			0x2
+#define	MPTSAS_TOPO_FLAG_RAID_ASSOCIATED		0x4
+#define	MPTSAS_TOPO_FLAG_RAID_PHYSDRV_ASSOCIATED	0x8
+#define	MPTSAS_TOPO_FLAG_EXPANDER_ATTACHED_DEVICE	0x10
+
+typedef struct mptsas_topo_change_list {
+	void *mpt;
+	uint_t  event;
+	union {
+		uint8_t physport;
+		uint8_t phymask;
+	} un;
+	uint16_t devhdl;
+	void *object;
+	uint8_t flags;
+	struct mptsas_topo_change_list *next;
+} mptsas_topo_change_list_t;
+
+
+_NOTE(DATA_READABLE_WITHOUT_LOCK(mptsas_topo_change_list_t::mpt))
+_NOTE(DATA_READABLE_WITHOUT_LOCK(mptsas_topo_change_list_t::event))
+_NOTE(DATA_READABLE_WITHOUT_LOCK(mptsas_topo_change_list_t::physport))
+_NOTE(DATA_READABLE_WITHOUT_LOCK(mptsas_topo_change_list_t::devhdl))
+_NOTE(DATA_READABLE_WITHOUT_LOCK(mptsas_topo_change_list_t::object))
+_NOTE(DATA_READABLE_WITHOUT_LOCK(mptsas_topo_change_list_t::flags))
+
+/*
+ * Status types when calling mptsas_get_target_device_info
+ */
+#define	DEV_INFO_SUCCESS		0x0
+#define	DEV_INFO_FAIL_PAGE0		0x1
+#define	DEV_INFO_WRONG_DEVICE_TYPE	0x2
+#define	DEV_INFO_PHYS_DISK		0x3
+#define	DEV_INFO_FAIL_ALLOC		0x4
+
+/*
+ * mpt hotplug event defines
+ */
+#define	MPTSAS_DR_EVENT_RECONFIG_TARGET	0x01
+#define	MPTSAS_DR_EVENT_OFFLINE_TARGET	0x02
+#define	MPTSAS_TOPO_FLAG_REMOVE_HANDLE	0x04
+
+/*
+ * SMP target hotplug events
+ */
+#define	MPTSAS_DR_EVENT_RECONFIG_SMP	0x10
+#define	MPTSAS_DR_EVENT_OFFLINE_SMP	0x20
+#define	MPTSAS_DR_EVENT_MASK		0x3F
+
+/*
+ * mpt hotplug status definition for m_dr_flag
+ */
+
+/*
+ * MPTSAS_DR_INACTIVE
+ *
+ * The target is in a normal operating state.
+ * No dynamic reconfiguration operation is in progress.
+ */
+#define	MPTSAS_DR_INACTIVE				0x0
+/*
+ * MPTSAS_DR_INTRANSITION
+ *
+ * The target is in a transition mode since
+ * hotplug event happens and offline procedure has not
+ * been finished
+ */
+#define	MPTSAS_DR_INTRANSITION			0x1
+
+typedef struct mptsas_tgt_private {
+	int t_lun;
+	struct mptsas_target *t_private;
+} mptsas_tgt_private_t;
+
+/*
+ * The following defines are used in mptsas_set_init_mode to track the current
+ * state as we progress through reprogramming the HBA from target mode into
+ * initiator mode.
+ */
+
+#define	IOUC_READ_PAGE0		0x00000100
+#define	IOUC_READ_PAGE1		0x00000200
+#define	IOUC_WRITE_PAGE1	0x00000400
+#define	IOUC_DONE		0x00000800
+#define	DISCOVERY_IN_PROGRESS	MPI2_SASIOUNIT0_PORTFLAGS_DISCOVERY_IN_PROGRESS
+#define	AUTO_PORT_CONFIGURATION	MPI2_SASIOUNIT0_PORTFLAGS_AUTO_PORT_CONFIG
+
+/*
+ * Last allocated slot is used for TM requests.  Since only m_max_requests
+ * frames are allocated, the last SMID will be m_max_requests - 1.
+ */
+#define	MPTSAS_SLOTS_SIZE(mpt) \
+	(sizeof (struct mptsas_slots) + (sizeof (struct mptsas_cmd *) * \
+		mpt->m_max_requests))
+#define	MPTSAS_TM_SLOT(mpt)	(mpt->m_max_requests - 1)
+
+/*
+ * Macro for phy_flags
+ */
+typedef struct mptsas_phy_info {
+	uint8_t			port_num;
+	uint8_t			port_flags;
+	uint16_t		ctrl_devhdl;
+	uint32_t		phy_device_type;
+	uint16_t		attached_devhdl;
+	uint8_t			phy_mask;
+} mptsas_phy_info_t;
+
+typedef struct mptsas_doneq_thread_arg {
+	void		*mpt;
+	uint64_t	t;
+} mptsas_doneq_thread_arg_t;
+
+#define	MPTSAS_DONEQ_THREAD_ACTIVE	0x1
+typedef struct mptsas_doneq_thread_list {
+	mptsas_cmd_t		*doneq;
+	mptsas_cmd_t		**donetail;
+	kthread_t		*threadp;
+	kcondvar_t		cv;
+	ushort_t		reserv1;
+	uint32_t		reserv2;
+	kmutex_t		mutex;
+	uint32_t		flag;
+	uint32_t		len;
+	mptsas_doneq_thread_arg_t	arg;
+} mptsas_doneq_thread_list_t;
+
+typedef struct mptsas {
+	int		m_instance;
+
+	struct mptsas *m_next;
+
+	scsi_hba_tran_t		*m_tran;
+	sas_hba_tran_t		*m_smptran;
+	kmutex_t		m_mutex;
+	kcondvar_t		m_cv;
+	kcondvar_t		m_passthru_cv;
+	kcondvar_t		m_fw_cv;
+	kcondvar_t		m_config_cv;
+	dev_info_t		*m_dip;
+
+	/*
+	 * soft state flags
+	 */
+	uint_t		m_softstate;
+
+	struct mptsas_slots *m_active;	/* outstanding cmds */
+
+	mptsas_cmd_t	*m_waitq;	/* cmd queue for active request */
+	mptsas_cmd_t	**m_waitqtail;	/* wait queue tail ptr */
+
+	kmutex_t	m_tx_waitq_mutex;
+	mptsas_cmd_t	*m_tx_waitq;	/* TX cmd queue for active request */
+	mptsas_cmd_t	**m_tx_waitqtail;	/* tx_wait queue tail ptr */
+	int		m_tx_draining;	/* TX queue draining flag */
+
+	mptsas_cmd_t	*m_doneq;	/* queue of completed commands */
+	mptsas_cmd_t	**m_donetail;	/* queue tail ptr */
+
+	/*
+	 * variables for helper threads (fan-out interrupts)
+	 */
+	mptsas_doneq_thread_list_t	*m_doneq_thread_id;
+	uint32_t		m_doneq_thread_n;
+	uint32_t		m_doneq_thread_threshold;
+	uint32_t		m_doneq_length_threshold;
+	uint32_t		m_doneq_len;
+	kcondvar_t		m_doneq_thread_cv;
+	kmutex_t		m_doneq_mutex;
+
+	int		m_ncmds;	/* number of outstanding commands */
+	m_event_struct_t *m_ioc_event_cmdq;	/* cmd queue for ioc event */
+	m_event_struct_t **m_ioc_event_cmdtail;	/* ioc cmd queue tail */
+
+	ddi_acc_handle_t m_datap;	/* operating regs data access handle */
+
+	struct _MPI2_SYSTEM_INTERFACE_REGS	*m_reg;
+
+	ushort_t	m_devid;	/* device id of chip. */
+	uchar_t		m_revid;	/* revision of chip. */
+	uint16_t	m_svid;		/* subsystem Vendor ID of chip */
+	uint16_t	m_ssid;		/* subsystem Device ID of chip */
+
+	uchar_t		m_sync_offset;	/* default offset for this chip. */
+
+	timeout_id_t	m_quiesce_timeid;
+	timeout_id_t	m_pm_timeid;
+
+	ddi_dma_handle_t m_dma_req_frame_hdl;
+	ddi_acc_handle_t m_acc_req_frame_hdl;
+	ddi_dma_handle_t m_dma_reply_frame_hdl;
+	ddi_acc_handle_t m_acc_reply_frame_hdl;
+	ddi_dma_handle_t m_dma_free_queue_hdl;
+	ddi_acc_handle_t m_acc_free_queue_hdl;
+	ddi_dma_handle_t m_dma_post_queue_hdl;
+	ddi_acc_handle_t m_acc_post_queue_hdl;
+
+	/*
+	 * list of reset notification requests
+	 */
+	struct scsi_reset_notify_entry	*m_reset_notify_listf;
+
+	/*
+	 * qfull handling
+	 */
+	timeout_id_t	m_restart_cmd_timeid;
+
+	/*
+	 * scsi	reset delay per	bus
+	 */
+	uint_t		m_scsi_reset_delay;
+
+	int		m_pm_idle_delay;
+
+	uchar_t		m_polled_intr;	/* intr was polled. */
+	uchar_t		m_suspended;	/* true	if driver is suspended */
+
+	struct kmem_cache *m_kmem_cache;
+	struct kmem_cache *m_cache_frames;
+
+	/*
+	 * hba options.
+	 */
+	uint_t		m_options;
+
+	int		m_in_callback;
+
+	int		m_power_level;	/* current power level */
+
+	int		m_busy;		/* power management busy state */
+
+	off_t		m_pmcsr_offset; /* PMCSR offset */
+
+	ddi_acc_handle_t m_config_handle;
+
+	ddi_dma_attr_t		m_io_dma_attr;	/* Used for data I/O */
+	ddi_dma_attr_t		m_msg_dma_attr; /* Used for message frames */
+	ddi_device_acc_attr_t	m_dev_acc_attr;
+
+	/*
+	 * request/reply variables
+	 */
+	caddr_t		m_req_frame;
+	uint64_t	m_req_frame_dma_addr;
+	caddr_t		m_reply_frame;
+	uint64_t	m_reply_frame_dma_addr;
+	caddr_t		m_free_queue;
+	uint64_t	m_free_queue_dma_addr;
+	caddr_t		m_post_queue;
+	uint64_t	m_post_queue_dma_addr;
+
+	m_replyh_arg_t *m_replyh_args;
+
+	uint16_t	m_max_requests;
+	uint16_t	m_req_frame_size;
+
+	/*
+	 * Max frames per request reprted in IOC Facts
+	 */
+	uint8_t		m_max_chain_depth;
+	/*
+	 * Max frames per request which is used in reality. It's adjusted
+	 * according DMA SG length attribute, and shall not exceed the
+	 * m_max_chain_depth.
+	 */
+	uint8_t		m_max_request_frames;
+
+	uint16_t	m_free_queue_depth;
+	uint16_t	m_post_queue_depth;
+	uint16_t	m_max_replies;
+	uint32_t	m_free_index;
+	uint32_t	m_post_index;
+	uint8_t		m_reply_frame_size;
+
+	/*
+	 * indicates if the firmware was upload by the driver
+	 * at boot time
+	 */
+	ushort_t	m_fwupload;
+
+	uint16_t	m_productid;
+
+	/*
+	 * per instance data structures for dma memory resources for
+	 * MPI handshake protocol. only one handshake cmd can run at a time.
+	 */
+	ddi_dma_handle_t	m_hshk_dma_hdl;
+
+	ddi_acc_handle_t	m_hshk_acc_hdl;
+
+	caddr_t			m_hshk_memp;
+
+	size_t			m_hshk_dma_size;
+
+	/* Firmware version on the card at boot time */
+	uint32_t		m_fwversion;
+
+	/* MSI specific fields */
+	ddi_intr_handle_t	*m_htable;	/* For array of interrupts */
+	int			m_intr_type;	/* What type of interrupt */
+	int			m_intr_cnt;	/* # of intrs count returned */
+	size_t			m_intr_size;    /* Size of intr array */
+	uint_t			m_intr_pri;	/* Interrupt priority   */
+	int			m_intr_cap;	/* Interrupt capabilities */
+	ddi_taskq_t		*m_event_taskq;
+
+	/* SAS specific information */
+
+	union {
+		uint64_t	m_base_wwid;	/* Base WWID */
+		struct {
+#ifdef _BIG_ENDIAN
+			uint32_t	m_base_wwid_hi;
+			uint32_t	m_base_wwid_lo;
+#else
+			uint32_t	m_base_wwid_lo;
+			uint32_t	m_base_wwid_hi;
+#endif
+		} sasaddr;
+	} un;
+
+	uint8_t			m_num_phys;		/* # of PHYs */
+	mptsas_phy_info_t	m_phy_info[MPTSAS_MAX_PHYS];
+	uint8_t			m_port_chng;	/* initiator port changes */
+
+	/* FMA Capabilities */
+	int			m_fm_capabilities;
+	ddi_taskq_t		*m_dr_taskq;
+	int			m_mpxio_enable;
+	uint8_t			m_done_traverse_dev;
+	uint8_t			m_done_traverse_smp;
+	int			m_passthru_in_progress;
+	uint16_t		m_dev_handle;
+	uint16_t		m_smp_devhdl;
+
+	/*
+	 * Event recording
+	 */
+	uint32_t		m_event_number;
+	uint32_t		m_event_mask[4];
+	mptsas_event_entry_t	m_events[MPTSAS_EVENT_QUEUE_SIZE];
+
+	/*
+	 * per instance cmd data structures for task management cmds
+	 */
+	m_event_struct_t	m_event_task_mgmt;	/* must be last */
+							/* ... scsi_pkt_size */
+} mptsas_t;
+#define	MPTSAS_SIZE	(sizeof (struct mptsas) - \
+			sizeof (struct scsi_pkt) + scsi_pkt_size())
+/*
+ * Only one of below two conditions is satisfied, we
+ * think the target is associated to the iport and
+ * allow call into mptsas_probe_lun().
+ * 1. physicalsport == physport
+ * 2. (phymask & (1 << physport)) == 0
+ * The condition #2 is because LSI uses lowest PHY
+ * number as the value of physical port when auto port
+ * configuration.
+ */
+#define	IS_SAME_PORT(physicalport, physport, phymask, dynamicport) \
+	((physicalport == physport) || (dynamicport && (phymask & \
+	(1 << physport))))
+
+_NOTE(MUTEX_PROTECTS_DATA(mptsas::m_mutex, mptsas))
+_NOTE(SCHEME_PROTECTS_DATA("safe sharing", mptsas::m_next))
+_NOTE(SCHEME_PROTECTS_DATA("stable data", mptsas::m_dip mptsas::m_tran))
+_NOTE(SCHEME_PROTECTS_DATA("stable data", mptsas::m_kmem_cache))
+_NOTE(DATA_READABLE_WITHOUT_LOCK(mptsas::m_io_dma_attr.dma_attr_sgllen))
+_NOTE(DATA_READABLE_WITHOUT_LOCK(mptsas::m_devid))
+_NOTE(DATA_READABLE_WITHOUT_LOCK(mptsas::m_productid))
+_NOTE(DATA_READABLE_WITHOUT_LOCK(mptsas::m_port_type))
+_NOTE(DATA_READABLE_WITHOUT_LOCK(mptsas::m_mpxio_enable))
+_NOTE(DATA_READABLE_WITHOUT_LOCK(mptsas::m_ntargets))
+_NOTE(DATA_READABLE_WITHOUT_LOCK(mptsas::m_instance))
+
+typedef struct mptsas_dma_alloc_state
+{
+	ddi_dma_handle_t	handle;
+	caddr_t			memp;
+	size_t			size;
+	ddi_acc_handle_t	accessp;
+	ddi_dma_cookie_t	cookie;
+} mptsas_dma_alloc_state_t;
+
+/*
+ * These should eventually migrate into the mpt header files
+ * that may become the /kernel/misc/mpt module...
+ */
+#define	mptsas_init_std_hdr(hdl, mp, DevHandle, Lun, ChainOffset, Function) \
+	mptsas_put_msg_DevHandle(hdl, mp, DevHandle); \
+	mptsas_put_msg_ChainOffset(hdl, mp, ChainOffset); \
+	mptsas_put_msg_Function(hdl, mp, Function); \
+	mptsas_put_msg_Lun(hdl, mp, Lun)
+
+#define	mptsas_put_msg_DevHandle(hdl, mp, val) \
+	ddi_put16(hdl, &(mp)->DevHandle, (val))
+#define	mptsas_put_msg_ChainOffset(hdl, mp, val) \
+	ddi_put8(hdl, &(mp)->ChainOffset, (val))
+#define	mptsas_put_msg_Function(hdl, mp, val) \
+	ddi_put8(hdl, &(mp)->Function, (val))
+#define	mptsas_put_msg_Lun(hdl, mp, val) \
+	ddi_put8(hdl, &(mp)->LUN[1], (val))
+
+#define	mptsas_get_msg_Function(hdl, mp) \
+	ddi_get8(hdl, &(mp)->Function)
+
+#define	mptsas_get_msg_MsgFlags(hdl, mp) \
+	ddi_get8(hdl, &(mp)->MsgFlags)
+
+#define	MPTSAS_ENABLE_DRWE(hdl) \
+	ddi_put32(hdl->m_datap, &hdl->m_reg->WriteSequence, \
+		MPI2_WRSEQ_FLUSH_KEY_VALUE); \
+	ddi_put32(hdl->m_datap, &hdl->m_reg->WriteSequence, \
+		MPI2_WRSEQ_1ST_KEY_VALUE); \
+	ddi_put32(hdl->m_datap, &hdl->m_reg->WriteSequence, \
+		MPI2_WRSEQ_2ND_KEY_VALUE); \
+	ddi_put32(hdl->m_datap, &hdl->m_reg->WriteSequence, \
+		MPI2_WRSEQ_3RD_KEY_VALUE); \
+	ddi_put32(hdl->m_datap, &hdl->m_reg->WriteSequence, \
+		MPI2_WRSEQ_4TH_KEY_VALUE); \
+	ddi_put32(hdl->m_datap, &hdl->m_reg->WriteSequence, \
+		MPI2_WRSEQ_5TH_KEY_VALUE); \
+	ddi_put32(hdl->m_datap, &hdl->m_reg->WriteSequence, \
+		MPI2_WRSEQ_6TH_KEY_VALUE);
+
+/*
+ * m_options flags
+ */
+#define	MPTSAS_OPT_PM		0x01	/* Power Management */
+
+/*
+ * m_softstate flags
+ */
+#define	MPTSAS_SS_DRAINING		0x02
+#define	MPTSAS_SS_QUIESCED		0x04
+#define	MPTSAS_SS_MSG_UNIT_RESET	0x08
+
+/*
+ * regspec defines.
+ */
+#define	CONFIG_SPACE	0	/* regset[0] - configuration space */
+#define	IO_SPACE	1	/* regset[1] - used for i/o mapped device */
+#define	MEM_SPACE	2	/* regset[2] - used for memory mapped device */
+#define	BASE_REG2	3	/* regset[3] - used for 875 scripts ram */
+
+/*
+ * Handy constants
+ */
+#define	FALSE		0
+#define	TRUE		1
+#define	UNDEFINED	-1
+#define	FAILED		-2
+
+/*
+ * power management.
+ */
+#define	MPTSAS_POWER_ON(mpt) { \
+	pci_config_put16(mpt->m_config_handle, mpt->m_pmcsr_offset, \
+	    PCI_PMCSR_D0); \
+	delay(drv_usectohz(10000)); \
+	(void) pci_restore_config_regs(mpt->m_dip); \
+	mptsas_setup_cmd_reg(mpt); \
+}
+
+#define	MPTSAS_POWER_OFF(mpt) { \
+	(void) pci_save_config_regs(mpt->m_dip); \
+	pci_config_put16(mpt->m_config_handle, mpt->m_pmcsr_offset, \
+	    PCI_PMCSR_D3HOT); \
+	mpt->m_power_level = PM_LEVEL_D3; \
+}
+
+/*
+ * inq_dtype:
+ * Bits 5 through 7 are the Peripheral Device Qualifier
+ * 001b: device not connected to the LUN
+ * Bits 0 through 4 are the Peripheral Device Type
+ * 1fh: Unknown or no device type
+ *
+ * Although the inquiry may return success, the following value
+ * means no valid LUN connected.
+ */
+#define	MPTSAS_VALID_LUN(sd_inq) \
+	(((sd_inq->inq_dtype & 0xe0) != 0x20) && \
+	((sd_inq->inq_dtype & 0x1f) != 0x1f))
+
+/*
+ * Default is to have 10 retries on receiving QFULL status and
+ * each retry to be after 100 ms.
+ */
+#define	QFULL_RETRIES		10
+#define	QFULL_RETRY_INTERVAL	100
+
+/*
+ * Handy macros
+ */
+#define	Tgt(sp)	((sp)->cmd_pkt->pkt_address.a_target)
+#define	Lun(sp)	((sp)->cmd_pkt->pkt_address.a_lun)
+
+#define	IS_HEX_DIGIT(n)	(((n) >= '0' && (n) <= '9') || \
+	((n) >= 'a' && (n) <= 'f') || ((n) >= 'A' && (n) <= 'F'))
+
+/*
+ * poll time for mptsas_pollret() and mptsas_wait_intr()
+ */
+#define	MPTSAS_POLL_TIME	30000	/* 30 seconds */
+
+/*
+ * default time for mptsas_do_passthru
+ */
+#define	MPTSAS_PASS_THRU_TIME_DEFAULT	60	/* 60 seconds */
+
+/*
+ * macro for getting value in micro-seconds since last boot to be used as
+ * timeout in cv_timedwait call.
+ */
+#define	MPTSAS_CV_TIMEOUT(timeout)  (ddi_get_lbolt() + \
+    drv_usectohz(timeout * MICROSEC))
+
+/*
+ * macro to return the effective address of a given per-target field
+ */
+#define	EFF_ADDR(start, offset)		((start) + (offset))
+
+#define	SDEV2ADDR(devp)		(&((devp)->sd_address))
+#define	SDEV2TRAN(devp)		((devp)->sd_address.a_hba_tran)
+#define	PKT2TRAN(pkt)		((pkt)->pkt_address.a_hba_tran)
+#define	ADDR2TRAN(ap)		((ap)->a_hba_tran)
+#define	DIP2TRAN(dip)		(ddi_get_driver_private(dip))
+
+
+#define	TRAN2MPT(hba)		((mptsas_t *)(hba)->tran_hba_private)
+#define	DIP2MPT(dip)		(TRAN2MPT((scsi_hba_tran_t *)DIP2TRAN(dip)))
+#define	SDEV2MPT(sd)		(TRAN2MPT(SDEV2TRAN(sd)))
+#define	PKT2MPT(pkt)		(TRAN2MPT(PKT2TRAN(pkt)))
+
+#define	ADDR2MPT(ap)		(TRAN2MPT(ADDR2TRAN(ap)))
+
+#define	POLL_TIMEOUT		(2 * SCSI_POLL_TIMEOUT * 1000000)
+#define	SHORT_POLL_TIMEOUT	(1000000)	/* in usec, about 1 secs */
+#define	MPTSAS_QUIESCE_TIMEOUT	1		/* 1 sec */
+#define	MPTSAS_PM_IDLE_TIMEOUT	60		/* 60 seconds */
+
+#define	MPTSAS_GET_ISTAT(mpt)  (ddi_get32((mpt)->m_datap, \
+			&(mpt)->m_reg->HostInterruptStatus))
+
+#define	MPTSAS_SET_SIGP(P) \
+		ClrSetBits(mpt->m_devaddr + NREG_ISTAT, 0, NB_ISTAT_SIGP)
+
+#define	MPTSAS_RESET_SIGP(P) (void) ddi_get8(mpt->m_datap, \
+			(uint8_t *)(mpt->m_devaddr + NREG_CTEST2))
+
+#define	MPTSAS_GET_INTCODE(P) (ddi_get32(mpt->m_datap, \
+			(uint32_t *)(mpt->m_devaddr + NREG_DSPS)))
+
+
+#define	MPTSAS_START_CMD(mpt, req_desc_lo, req_desc_hi) \
+	ddi_put32(mpt->m_datap, &mpt->m_reg->RequestDescriptorPostLow,\
+	    req_desc_lo);\
+	ddi_put32(mpt->m_datap, &mpt->m_reg->RequestDescriptorPostHigh,\
+	    req_desc_hi);
+
+#define	INTPENDING(mpt) \
+	(MPTSAS_GET_ISTAT(mpt) & MPI2_HIS_REPLY_DESCRIPTOR_INTERRUPT)
+
+/*
+ * Mask all interrupts to disable
+ */
+#define	MPTSAS_DISABLE_INTR(mpt)	\
+	ddi_put32((mpt)->m_datap, &(mpt)->m_reg->HostInterruptMask, \
+	    (MPI2_HIM_RIM | MPI2_HIM_DIM | MPI2_HIM_RESET_IRQ_MASK))
+
+/*
+ * Mask Doorbell and Reset interrupts to enable reply desc int.
+ */
+#define	MPTSAS_ENABLE_INTR(mpt)	\
+	ddi_put32(mpt->m_datap, &mpt->m_reg->HostInterruptMask, \
+	(MPI2_HIM_DIM | MPI2_HIM_RESET_IRQ_MASK))
+
+#define	MPTSAS_GET_NEXT_REPLY(mpt, index)  \
+	&((uint64_t *)(void *)mpt->m_post_queue)[index]
+
+#define	MPTSAS_GET_NEXT_FRAME(mpt, SMID) \
+	(mpt->m_req_frame + (mpt->m_req_frame_size * SMID))
+
+#define	ClrSetBits32(hdl, reg, clr, set) \
+	ddi_put32(hdl, (reg), \
+	    ((ddi_get32(mpt->m_datap, (reg)) & ~(clr)) | (set)))
+
+#define	ClrSetBits(reg, clr, set) \
+	ddi_put8(mpt->m_datap, (uint8_t *)(reg), \
+		((ddi_get8(mpt->m_datap, (uint8_t *)(reg)) & ~(clr)) | (set)))
+
+#define	MPTSAS_WAITQ_RM(mpt, cmdp)	\
+	if ((cmdp = mpt->m_waitq) != NULL) { \
+		/* If the queue is now empty fix the tail pointer */	\
+		if ((mpt->m_waitq = cmdp->cmd_linkp) == NULL) \
+			mpt->m_waitqtail = &mpt->m_waitq; \
+		cmdp->cmd_linkp = NULL; \
+		cmdp->cmd_queued = FALSE; \
+	}
+
+#define	MPTSAS_TX_WAITQ_RM(mpt, cmdp)	\
+	if ((cmdp = mpt->m_tx_waitq) != NULL) { \
+		/* If the queue is now empty fix the tail pointer */	\
+		if ((mpt->m_tx_waitq = cmdp->cmd_linkp) == NULL) \
+			mpt->m_tx_waitqtail = &mpt->m_tx_waitq; \
+		cmdp->cmd_linkp = NULL; \
+		cmdp->cmd_queued = FALSE; \
+	}
+
+/*
+ * defaults for	the global properties
+ */
+#define	DEFAULT_SCSI_OPTIONS	SCSI_OPTIONS_DR
+#define	DEFAULT_TAG_AGE_LIMIT	2
+#define	DEFAULT_WD_TICK		10
+
+/*
+ * invalid hostid.
+ */
+#define	MPTSAS_INVALID_HOSTID  -1
+
+/*
+ * Get/Set hostid from SCSI port configuration page
+ */
+#define	MPTSAS_GET_HOST_ID(configuration) (configuration & 0xFF)
+#define	MPTSAS_SET_HOST_ID(hostid) (hostid | ((1 << hostid) << 16))
+
+/*
+ * Config space.
+ */
+#define	MPTSAS_LATENCY_TIMER	0x40
+
+/*
+ * Offset to firmware version
+ */
+#define	MPTSAS_FW_VERSION_OFFSET	9
+
+/*
+ * Offset and masks to get at the ProductId field
+ */
+#define	MPTSAS_FW_PRODUCTID_OFFSET	8
+#define	MPTSAS_FW_PRODUCTID_MASK	0xFFFF0000
+#define	MPTSAS_FW_PRODUCTID_SHIFT	16
+
+/*
+ * Subsystem ID for HBAs.
+ */
+#define	MPTSAS_HBA_SUBSYSTEM_ID    0x10C0
+#define	MPTSAS_RHEA_SUBSYSTEM_ID	0x10B0
+
+/*
+ * reset delay tick
+ */
+#define	MPTSAS_WATCH_RESET_DELAY_TICK 50	/* specified in milli seconds */
+
+/*
+ * Ioc reset return values
+ */
+#define	MPTSAS_RESET_FAIL	-1
+#define	MPTSAS_NO_RESET		0
+#define	MPTSAS_SUCCESS_HARDRESET	1
+
+/*
+ * throttle support.
+ */
+#define	MAX_THROTTLE	32
+#define	HOLD_THROTTLE	0
+#define	DRAIN_THROTTLE	-1
+#define	QFULL_THROTTLE	-2
+
+/*
+ * Passthrough/config request flags
+ */
+#define	MPTSAS_DATA_ALLOCATED		0x0001
+#define	MPTSAS_DATAOUT_ALLOCATED	0x0002
+#define	MPTSAS_REQUEST_POOL_CMD		0x0004
+#define	MPTSAS_ADDRESS_REPLY		0x0008
+#define	MPTSAS_CMD_TIMEOUT		0x0010
+
+/*
+ * System Events
+ */
+#ifndef	DDI_VENDOR_LSI
+#define	DDI_VENDOR_LSI	"LSI"
+#endif	/* DDI_VENDOR_LSI */
+
+/*
+ * Shared functions
+ */
+int mptsas_save_cmd(struct mptsas *mpt, struct mptsas_cmd *cmd);
+void mptsas_remove_cmd(mptsas_t *mpt, mptsas_cmd_t *cmd);
+void mptsas_waitq_add(mptsas_t *mpt, mptsas_cmd_t *cmd);
+int mptsas_config_space_init(struct mptsas *mpt);
+int mptsas_init_chip(mptsas_t *mpt, int first_time);
+void mptsas_log(struct mptsas *mpt, int level, char *fmt, ...);
+int mptsas_poll(mptsas_t *mpt, mptsas_cmd_t *poll_cmd, int polltime);
+int mptsas_do_dma(mptsas_t *mpt, uint32_t size, int var, int (*callback)());
+int mptsas_send_config_request_msg(mptsas_t *mpt, uint8_t action,
+	uint8_t pagetype, uint32_t pageaddress, uint8_t pagenumber,
+	uint8_t pageversion, uint8_t pagelength, uint32_t
+	SGEflagslength, uint32_t SGEaddress32);
+int mptsas_send_extended_config_request_msg(mptsas_t *mpt, uint8_t action,
+	uint8_t extpagetype, uint32_t pageaddress, uint8_t pagenumber,
+	uint8_t pageversion, uint16_t extpagelength,
+	uint32_t SGEflagslength, uint32_t SGEaddress32);
+int mptsas_update_flash(mptsas_t *mpt, caddr_t ptrbuffer, uint32_t size,
+	uint8_t type, int mode);
+int mptsas_check_flash(mptsas_t *mpt, caddr_t origfile, uint32_t size,
+	uint8_t type, int mode);
+int mptsas_download_firmware();
+int mptsas_can_download_firmware();
+int mptsas_passthru_dma_alloc(mptsas_t *mpt,
+    mptsas_dma_alloc_state_t *dma_statep);
+void mptsas_passthru_dma_free(mptsas_dma_alloc_state_t *dma_statep);
+uint8_t mptsas_physport_to_phymask(mptsas_t *mpt, uint8_t physport);
+uint8_t mptsas_phymask_to_physport(mptsas_t *mpt, uint8_t phymask);
+void mptsas_fma_check(mptsas_t *mpt, mptsas_cmd_t *cmd);
+int mptsas_check_acc_handle(ddi_acc_handle_t handle);
+int mptsas_check_dma_handle(ddi_dma_handle_t handle);
+void mptsas_fm_ereport(mptsas_t *mpt, char *detail);
+
+/*
+ * impl functions
+ */
+int mptsas_ioc_wait_for_response(mptsas_t *mpt);
+int mptsas_ioc_wait_for_doorbell(mptsas_t *mpt);
+int mptsas_ioc_reset(mptsas_t *mpt);
+int mptsas_send_handshake_msg(mptsas_t *mpt, caddr_t memp, int numbytes,
+    ddi_acc_handle_t accessp);
+int mptsas_get_handshake_msg(mptsas_t *mpt, caddr_t memp, int numbytes,
+    ddi_acc_handle_t accessp);
+int mptsas_send_config_request_msg(mptsas_t *mpt, uint8_t action,
+    uint8_t pagetype, uint32_t pageaddress, uint8_t pagenumber,
+    uint8_t pageversion, uint8_t pagelength, uint32_t SGEflagslength,
+    uint32_t SGEaddress32);
+int mptsas_send_extended_config_request_msg(mptsas_t *mpt, uint8_t action,
+    uint8_t extpagetype, uint32_t pageaddress, uint8_t pagenumber,
+    uint8_t pageversion, uint16_t extpagelength,
+    uint32_t SGEflagslength, uint32_t SGEaddress32);
+
+int mptsas_request_from_pool(mptsas_t *mpt, mptsas_cmd_t **cmd,
+    struct scsi_pkt **pkt);
+void mptsas_return_to_pool(mptsas_t *mpt, mptsas_cmd_t *cmd);
+void mptsas_destroy_ioc_event_cmd(mptsas_t *mpt);
+void mptsas_start_config_page_access(mptsas_t *mpt, mptsas_cmd_t *cmd);
+int mptsas_access_config_page(mptsas_t *mpt, uint8_t action, uint8_t page_type,
+    uint8_t page_number, uint32_t page_address, int (*callback) (mptsas_t *,
+    caddr_t, ddi_acc_handle_t, uint16_t, uint32_t, va_list), ...);
+
+int mptsas_ioc_task_management(mptsas_t *mpt, int task_type,
+    uint16_t dev_handle, int lun);
+int mptsas_send_event_ack(mptsas_t *mpt, uint32_t event, uint32_t eventcntx);
+void mptsas_send_pending_event_ack(mptsas_t *mpt);
+void mptsas_set_throttle(struct mptsas *mpt, mptsas_target_t *ptgt, int what);
+int mptsas_restart_ioc(mptsas_t *mpt);
+void mptsas_update_driver_data(struct mptsas *mpt);
+uint64_t mptsas_get_sata_guid(mptsas_t *mpt, mptsas_target_t *ptgt, int lun);
+
+/*
+ * init functions
+ */
+int mptsas_ioc_get_facts(mptsas_t *mpt);
+int mptsas_ioc_get_port_facts(mptsas_t *mpt, int port);
+int mptsas_ioc_enable_port(mptsas_t *mpt);
+int mptsas_ioc_enable_event_notification(mptsas_t *mpt);
+int mptsas_ioc_init(mptsas_t *mpt);
+
+/*
+ * configuration pages operation
+ */
+int mptsas_get_sas_device_page0(mptsas_t *mpt, uint32_t page_address,
+    uint16_t *dev_handle, uint64_t *sas_wwn, uint32_t *dev_info,
+    uint8_t *physport, uint8_t *phynum);
+int mptsas_get_sas_io_unit_page(mptsas_t *mpt);
+int mptsas_get_sas_io_unit_page_hndshk(mptsas_t *mpt);
+int mptsas_get_sas_expander_page0(mptsas_t *mpt, uint32_t page_address,
+    mptsas_smp_t *info);
+int mptsas_set_initiator_mode(mptsas_t *mpt);
+int mptsas_set_ioc_params(mptsas_t *mpt);
+int mptsas_get_manufacture_page5(mptsas_t *mpt);
+int mptsas_get_sas_port_page0(mptsas_t *mpt, uint32_t page_address,
+    uint64_t *sas_wwn, uint8_t *portwidth);
+
+/*
+ * RAID functions
+ */
+int mptsas_get_raid_settings(mptsas_t *mpt, mptsas_raidvol_t *raidvol);
+int mptsas_get_raid_info(mptsas_t *mpt);
+int mptsas_get_physdisk_settings(mptsas_t *mpt, mptsas_raidvol_t *raidvol,
+    uint8_t physdisknum);
+int mptsas_delete_volume(mptsas_t *mpt, uint16_t volid);
+
+#define	MPTSAS_IOCSTATUS(status) (status & MPI2_IOCSTATUS_MASK)
+/*
+ * debugging.
+ */
+#if defined(MPTSAS_DEBUG)
+
+void mptsas_printf(char *fmt, ...);
+
+#define	MPTSAS_DBGPR(m, args)	\
+	if (mptsas_debug_flags & (m)) \
+		mptsas_printf args
+#else	/* ! defined(MPTSAS_DEBUG) */
+#define	MPTSAS_DBGPR(m, args)
+#endif	/* defined(MPTSAS_DEBUG) */
+
+#define	NDBG0(args)	MPTSAS_DBGPR(0x01, args)	/* init	*/
+#define	NDBG1(args)	MPTSAS_DBGPR(0x02, args)	/* normal running */
+#define	NDBG2(args)	MPTSAS_DBGPR(0x04, args)	/* property handling */
+#define	NDBG3(args)	MPTSAS_DBGPR(0x08, args)	/* pkt handling */
+
+#define	NDBG4(args)	MPTSAS_DBGPR(0x10, args)	/* kmem alloc/free */
+#define	NDBG5(args)	MPTSAS_DBGPR(0x20, args)	/* polled cmds */
+#define	NDBG6(args)	MPTSAS_DBGPR(0x40, args)	/* interrupts */
+#define	NDBG7(args)	MPTSAS_DBGPR(0x80, args)	/* queue handling */
+
+#define	NDBG8(args)	MPTSAS_DBGPR(0x0100, args)	/* arq */
+#define	NDBG9(args)	MPTSAS_DBGPR(0x0200, args)	/* Tagged Q'ing */
+#define	NDBG10(args)	MPTSAS_DBGPR(0x0400, args)	/* halting chip */
+#define	NDBG11(args)	MPTSAS_DBGPR(0x0800, args)	/* power management */
+
+#define	NDBG12(args)	MPTSAS_DBGPR(0x1000, args)	/* enumeration */
+#define	NDBG13(args)	MPTSAS_DBGPR(0x2000, args)	/* configuration page */
+#define	NDBG14(args)	MPTSAS_DBGPR(0x4000, args)
+#define	NDBG15(args)	MPTSAS_DBGPR(0x8000, args)
+
+#define	NDBG16(args)	MPTSAS_DBGPR(0x010000, args)
+#define	NDBG17(args)	MPTSAS_DBGPR(0x020000, args)	/* scatter/gather */
+#define	NDBG18(args)	MPTSAS_DBGPR(0x040000, args)
+#define	NDBG19(args)	MPTSAS_DBGPR(0x080000, args)	/* handshaking */
+
+#define	NDBG20(args)	MPTSAS_DBGPR(0x100000, args)	/* events */
+#define	NDBG21(args)	MPTSAS_DBGPR(0x200000, args)	/* dma */
+#define	NDBG22(args)	MPTSAS_DBGPR(0x400000, args)	/* reset */
+#define	NDBG23(args)	MPTSAS_DBGPR(0x800000, args)	/* abort */
+
+#define	NDBG24(args)	MPTSAS_DBGPR(0x1000000, args)	/* capabilities */
+#define	NDBG25(args)	MPTSAS_DBGPR(0x2000000, args)	/* flushing */
+#define	NDBG26(args)	MPTSAS_DBGPR(0x4000000, args)
+#define	NDBG27(args)	MPTSAS_DBGPR(0x8000000, args)
+
+#define	NDBG28(args)	MPTSAS_DBGPR(0x10000000, args)	/* hotplug */
+#define	NDBG29(args)	MPTSAS_DBGPR(0x20000000, args)	/* timeouts */
+#define	NDBG30(args)	MPTSAS_DBGPR(0x40000000, args)	/* mptsas_watch */
+#define	NDBG31(args)	MPTSAS_DBGPR(0x80000000, args)	/* negotations */
+
+/*
+ * auto request sense
+ */
+#define	RQ_MAKECOM_COMMON(pkt, flag, cmd) \
+	(pkt)->pkt_flags = (flag), \
+	((union scsi_cdb *)(pkt)->pkt_cdbp)->scc_cmd = (cmd), \
+	((union scsi_cdb *)(pkt)->pkt_cdbp)->scc_lun = \
+	    (pkt)->pkt_address.a_lun
+
+#define	RQ_MAKECOM_G0(pkt, flag, cmd, addr, cnt) \
+	RQ_MAKECOM_COMMON((pkt), (flag), (cmd)), \
+	FORMG0ADDR(((union scsi_cdb *)(pkt)->pkt_cdbp), (addr)), \
+	FORMG0COUNT(((union scsi_cdb *)(pkt)->pkt_cdbp), (cnt))
+
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* _SYS_SCSI_ADAPTERS_MPTVAR_H */
--- a/usr/src/uts/intel/Makefile.intel.shared	Fri Jun 19 18:13:27 2009 +0800
+++ b/usr/src/uts/intel/Makefile.intel.shared	Fri Jun 19 20:12:07 2009 +0800
@@ -268,6 +268,7 @@
 DRV_KMODS	+= mc-amd
 DRV_KMODS	+= mm
 DRV_KMODS	+= mouse8042
+DRV_KMODS	+= mpt_sas
 DRV_KMODS	+= mr_sas
 DRV_KMODS	+= nca
 DRV_KMODS	+= nsmb
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/intel/mpt_sas/Makefile	Fri Jun 19 20:12:07 2009 +0800
@@ -0,0 +1,122 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#	This makefile drives the production of the mpt_sas driver kernel module.
+#
+#	intel architecture dependent
+#
+
+#
+#	Paths to the base of the uts directory trees
+#
+UTSBASE   = ../../../../src/uts
+
+#
+#	Define the module and object file sets.
+#
+MODULE		= mpt_sas
+OBJECTS		= $(MPTSAS_OBJS:%=$(OBJS_DIR)/%)
+LINTS		= $(MPTSAS_OBJS:%.o=$(LINTS_DIR)/%.ln)
+ROOTMODULE	= $(ROOT_DRV_DIR)/$(MODULE)
+CONF_SRCDIR	= $(UTSBASE)/common/io/scsi/adapters/mpt_sas/
+WARLOCK_OUT     = $(MPTSAS_OBJS:%.o=%.ll)
+WARLOCK_OK      = $(MODULE).ok
+WLCMD_DIR       = $(UTSBASE)/common/io/warlock
+
+#
+#	Kernel Module Dependencies
+#
+LDFLAGS += -dy -Nmisc/scsi -Ndrv/scsi_vhci
+
+#
+#	Define targets
+#
+ALL_TARGET	= $(BINARY) $(CONFMOD)
+LINT_TARGET	= $(MODULE).lint
+INSTALL_TARGET	= $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE)
+
+#
+#	Include common rules.
+#
+include $(UTSBASE)/intel/Makefile.intel
+
+#
+#	Default build targets.
+#
+.KEEP_STATE:
+
+all:		$(ALL_DEPS)
+
+def:		$(DEF_DEPS)
+
+clean:		$(CLEAN_DEPS)
+		$(RM) $(WARLOCK_OUT) $(WARLOCK_OK)
+
+clobber:	$(CLOBBER_DEPS)
+		$(RM) $(WARLOCK_OUT) $(WARLOCK_OK)
+
+lint:		$(LINT_DEPS)
+
+modlintlib:	$(MODLINTLIB_DEPS)
+
+clean.lint:	$(CLEAN_LINT_DEPS)
+
+install:	$(INSTALL_DEPS)
+
+#
+#	Include common targets.
+#
+include $(UTSBASE)/intel/Makefile.targ
+
+#
+#	Defines for local commands.
+#
+WARLOCK		= warlock
+WLCC		= wlcc
+TOUCH		= touch
+TEST		= test
+
+#
+#	lock_lint rules
+#
+SCSI_FILES = $(SCSI_OBJS:%.o= -l $(UTSBASE)/intel/scsi/%.ll)
+
+warlock: $(WARLOCK_OK)
+
+$(WARLOCK_OK): $(WARLOCK_OUT) warlock_ddi.files scsi.files \
+	$(WLCMD_DIR)/mptsas.wlcmd
+	$(WARLOCK) -c $(WLCMD_DIR)/mptsas.wlcmd $(WARLOCK_OUT) \
+	$(SCSI_FILES) \
+	$(UTSBASE)/intel/warlock/scsi.ll \
+	-l $(UTSBASE)/intel/warlock/ddi_dki_impl.ll
+	$(TOUCH) $@
+
+%.ll: $(UTSBASE)/common/io/scsi/adapters/mpt_sas/%.c
+	$(WLCC) $(CPPFLAGS) -DDEBUG -o $@ $<
+
+warlock_ddi.files:
+	@cd $(UTSBASE)/intel/warlock; pwd; $(MAKE) warlock
+
+scsi.files:
+	@cd $(UTSBASE)/intel/scsi; pwd; $(MAKE) warlock
+
--- a/usr/src/uts/sparc/Makefile.sparc.shared	Fri Jun 19 18:13:27 2009 +0800
+++ b/usr/src/uts/sparc/Makefile.sparc.shared	Fri Jun 19 20:12:07 2009 +0800
@@ -281,6 +281,7 @@
 DRV_KMODS	+= pci_pci px_pci pxb_plx pxb_bcm pcie
 DRV_KMODS	+= i8042 kb8042 mouse8042
 DRV_KMODS	+= fcode
+DRV_KMODS	+= mpt_sas
 DRV_KMODS	+= socal
 DRV_KMODS	+= sgen
 DRV_KMODS	+= smp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/sparc/mpt_sas/Makefile	Fri Jun 19 20:12:07 2009 +0800
@@ -0,0 +1,127 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#	This makefile drives the production of the mpt_sas driver kernel module.
+#
+#	Sparc architecture dependent
+#
+
+#
+#	Path to the base of the uts directory tree (usually /usr/src/uts).
+#
+UTSBASE   = ../../../../src/uts
+
+#
+#	Define the module and object file sets.
+#
+MODULE		= mpt_sas
+OBJECTS		= $(MPTSAS_OBJS:%=$(OBJS_DIR)/%)
+LINTS		= $(MPTSAS_OBJS:%.o=$(LINTS_DIR)/%.ln)
+ROOTMODULE	= $(ROOT_DRV_DIR)/$(MODULE)
+CONF_SRCDIR	= $(UTSBASE)/common/io/scsi/adapters/mpt_sas
+WARLOCK_OUT     = $(MPTSAS_OBJS:%.o=%.ll)
+WARLOCK_OK      = $(MODULE).ok
+WLCMD_DIR       = $(UTSBASE)/common/io/warlock
+
+#
+# 	Kernel Module Dependencies
+#
+LDFLAGS += -dy -Nmisc/scsi -Ndrv/scsi_vhci
+
+#
+#	Define targets
+#
+ALL_TARGET	= $(BINARY) $(CONFMOD)
+LINT_TARGET	= $(MODULE).lint
+INSTALL_TARGET	= $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE)
+
+#
+#	Include common rules.
+#
+include $(UTSBASE)/sparc/Makefile.sparc
+
+# 
+# lint pass one enforcement 
+# 
+CFLAGS += $(CCVERBOSE)
+
+#
+#	Default build targets.
+#
+.KEEP_STATE:
+
+all:		$(ALL_DEPS)
+
+def:		$(DEF_DEPS)
+
+clean:		$(CLEAN_DEPS)
+		$(RM) $(WARLOCK_OUT) $(WARLOCK_OK)
+
+clobber:	$(CLOBBER_DEPS)
+		$(RM) $(WARLOCK_OUT) $(WARLOCK_OK)
+
+lint:		$(LINT_DEPS)
+
+modlintlib:	$(MODLINTLIB_DEPS)
+
+clean.lint:	$(CLEAN_LINT_DEPS)
+
+install:	$(INSTALL_DEPS)
+
+#
+#	Include common targets.
+#
+include $(UTSBASE)/sparc/Makefile.targ
+
+#
+#	Defines for local commands.
+#
+WARLOCK		= warlock
+WLCC		= wlcc
+TOUCH		= touch
+TEST		= test
+
+#
+#	lock_lint rules
+#
+SCSI_FILES = $(SCSI_OBJS:%.o= -l $(UTSBASE)/sparc/scsi/%.ll)
+
+warlock: $(WARLOCK_OK)
+
+$(WARLOCK_OK): $(WARLOCK_OUT) warlock_ddi.files scsi.files \
+	$(WLCMD_DIR)/mptsas.wlcmd
+	$(WARLOCK) -c $(WLCMD_DIR)/mptsas.wlcmd $(WARLOCK_OUT) \
+	$(UTSBASE)/sparc/warlock/scsi.ll \
+	$(SCSI_FILES) \
+	-l $(UTSBASE)/sparc/warlock/ddi_dki_impl.ll
+	$(TOUCH) $@
+
+%.ll: $(UTSBASE)/common/io/scsi/adapters/mpt_sas/%.c
+	$(WLCC) $(CPPFLAGS) -DDEBUG -o $@ $<
+
+warlock_ddi.files:
+	@cd $(UTSBASE)/sparc/warlock; pwd; $(MAKE) warlock
+
+scsi.files:
+	@cd $(UTSBASE)/sparc/scsi; pwd; $(MAKE) warlock
+