--- old/usr/src/cmd/mdb/Makefile.common	2014-06-12 17:42:13.793835404 +0100
+++ new/usr/src/cmd/mdb/Makefile.common	2014-06-12 17:42:13.799174306 +0100
@@ -73,6 +73,7 @@
 	mac \
 	md \
 	mpt_sas \
+	mpt_sas3 \
 	mr_sas \
 	nca \
 	nsctl \
--- old/usr/src/cmd/mdb/common/modules/mpt_sas/mpt_sas.c	2014-06-12 17:42:13.947775164 +0100
+++ new/usr/src/cmd/mdb/common/modules/mpt_sas/mpt_sas.c	2014-06-12 17:42:13.953755864 +0100
@@ -150,12 +150,12 @@
 }
 
 void
-mdi_info(struct mptsas m, int target)
+mdi_info(struct mptsas *mp, int target)
 {
 	struct	dev_info	d;
 	struct	mdi_phci	p;
 
-	if (mdb_vread(&d, sizeof (d), (uintptr_t)m.m_dip) == -1) {
+	if (mdb_vread(&d, sizeof (d), (uintptr_t)mp->m_dip) == -1) {
 		mdb_warn("couldn't read m_dip");
 		return;
 	}
@@ -301,52 +301,30 @@
 }
 
 void
-display_targets(struct mptsas *mp)
+display_targets(struct mptsas *mp, uint_t verbose)
 {
 	mptsas_target_t *ptgt;
 	mptsas_smp_t *psmp;
+	int loop, comma;
 
 	mdb_printf("\n");
-	mdb_printf("The SCSI target information\n");
-	for (ptgt = (mptsas_target_t *)krefhash_first((uintptr_t)mp->m_targets);
-	    ptgt != NULL;
-	    ptgt = krefhash_next((uintptr_t)mp->m_targets, ptgt)) {
-		mdb_printf("\n");
-		mdb_printf("devhdl %x, sasaddress %"PRIx64", phymask %x,"
-		    "devinfo %x\n", ptgt->m_devhdl, ptgt->m_addr.mta_wwn,
-		    ptgt->m_addr.mta_phymask, ptgt->m_deviceinfo);
-		mdb_printf("throttle %x, dr_flag %x, m_t_ncmds %x, "
-		    "enclosure %x, slot_num %x\n", ptgt->m_t_throttle,
-		    ptgt->m_dr_flag, ptgt->m_t_ncmds, ptgt->m_enclosure,
-		    ptgt->m_slot_num);
-	}
-
-	mdb_printf("\n");
-	mdb_printf("The smp child information\n");
-	for (psmp = (mptsas_smp_t *)krefhash_first(
-	    (uintptr_t)mp->m_smp_targets);
-	    psmp != NULL;
-	    psmp = krefhash_next((uintptr_t)mp->m_smp_targets, psmp)) {
-		mdb_printf("\n");
-		mdb_printf("devhdl %x, sasaddress %"PRIx64", phymask %x \n",
-		    psmp->m_devhdl, psmp->m_addr.mta_wwn,
-		    psmp->m_addr.mta_phymask);
-	}
-	mdb_printf("\n");
-#if 0
-	mdb_printf("targ         wwn      ncmds throttle "
-	    "dr_flag  timeout  dups\n");
+	mdb_printf("slot devhdl      wwn     ncmds throttle   "
+	    "dr_flag  dups\n");
 	mdb_printf("-------------------------------"
 	    "--------------------------------\n");
-	for (i = 0; i < MPTSAS_MAX_TARGETS; i++) {
-		if (s->m_target[i].m_addr.mta_wwn ||
-		    s->m_target[i].m_deviceinfo) {
-			mdb_printf("%4d ", i);
-			if (s->m_target[i].m_addr.mta_wwn)
+	for (ptgt = (mptsas_target_t *)krefhash_first(
+	    (uintptr_t)mp->m_targets);
+	    ptgt != NULL;
+	    ptgt = krefhash_next((uintptr_t)mp->m_targets, ptgt)) {
+		if (ptgt->m_addr.mta_wwn ||
+		    ptgt->m_deviceinfo) {
+			mdb_printf("%4d ", ptgt->m_slot_num);
+			mdb_printf("%4d ", ptgt->m_devhdl);
+			if (ptgt->m_addr.mta_wwn)
 				mdb_printf("%"PRIx64" ",
-				    s->m_target[i].m_addr.mta_wwn);
-			mdb_printf("%3d", s->m_target[i].m_t_ncmds);
-			switch (s->m_target[i].m_t_throttle) {
+				    ptgt->m_addr.mta_wwn);
+			mdb_printf("%3d", ptgt->m_t_ncmds);
+			switch (ptgt->m_t_throttle) {
 				case QFULL_THROTTLE:
 					mdb_printf("   QFULL ");
 					break;
@@ -359,53 +337,38 @@
 				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);
+					    ptgt->m_t_throttle);
 			}
-			switch (s->m_target[i].m_dr_flag) {
+			switch (ptgt->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 ");
+				case MPTSAS_DR_INTRANSITION:
+					mdb_printf("TRANSITION ");
 					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);
+			mdb_printf("%d\n", ptgt->m_dups);
 
 			if (verbose) {
 				mdb_inc_indent(5);
-				if ((s->m_target[i].m_deviceinfo &
+				if ((ptgt->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 &
+				if ((ptgt->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 &
+				if ((ptgt->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 &
+				if ((ptgt->m_deviceinfo &
 				    MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) ==
 				    MPI2_SAS_DEVICE_INFO_NO_DEVICE)
 					mdb_printf("No device ");
@@ -413,7 +376,7 @@
 				for (loop = 0, comma = 0;
 				    loop < (sizeof (devinfo_array) /
 				    sizeof (devinfo_array[0])); loop++) {
-					if (s->m_target[i].m_deviceinfo &
+					if (ptgt->m_deviceinfo &
 					    devinfo_array[loop].value) {
 						mdb_printf("%s%s",
 						    (comma ? ", " : ""),
@@ -422,40 +385,52 @@
 					}
 				}
 				mdb_printf("\n");
-
-				if (s->m_target[i].m_tgt_dip) {
+#if 0
+				if (ptgt->m_tgt_dip) {
+					char	target_path[PATH_MAX];
 					*target_path = 0;
 					if (construct_path((uintptr_t)
-					    s->m_target[i].m_tgt_dip,
+					    ptgt->m_tgt_dip,
 					    target_path)
 					    == DCMD_OK)
 						mdb_printf("%s\n", target_path);
 				}
-				mdi_info(m, i);
+#endif
+				mdi_info(mp, ptgt->m_slot_num);
 				mdb_dec_indent(5);
 			}
 		}
 	}
-#endif
+
+	mdb_printf("\n");
+	mdb_printf("The smp child information\n");
+	for (psmp = (mptsas_smp_t *)krefhash_first(
+	    (uintptr_t)mp->m_smp_targets);
+	    psmp != NULL;
+	    psmp = krefhash_next((uintptr_t)mp->m_smp_targets, psmp)) {
+		mdb_printf("\n");
+		mdb_printf("devhdl %x, sasaddress %"PRIx64", phymask %x \n",
+		    psmp->m_devhdl, psmp->m_addr.mta_wwn,
+		    psmp->m_addr.mta_phymask);
+	}
 }
 
 int
-display_slotinfo()
+display_slotinfo(struct mptsas *mp, struct mptsas_slots *s)
 {
-#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;
+	int			i, nslots;
+	struct mptsas_cmd	c, *q, *slots;
+	mptsas_target_t		*ptgt;
+	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_normal;
-
 	slots = mdb_alloc(sizeof (mptsas_cmd_t) * nslots, UM_SLEEP);
 
 	for (i = 0; i < nslots; i++)
@@ -472,22 +447,29 @@
 				mismatch++;
 		}
 
-	for (q = m.m_waitq, wq = 0; q; q = c.cmd_linkp, wq++)
+	for (q = mp->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++)
+	for (q = mp->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;
+	for (ptgt = (mptsas_target_t *)krefhash_first(
+	    (uintptr_t)mp->m_targets);
+	    ptgt != NULL;
+	    ptgt = krefhash_next((uintptr_t)mp->m_targets, ptgt)) {
+		if (ptgt->m_addr.mta_wwn ||
+		    ptgt->m_deviceinfo) {
+			ncmds += ptgt->m_t_ncmds;
+		}
+	}
 
 	mdb_printf("\n");
 	mdb_printf("   mpt.  slot               mptsas_slots     slot");
@@ -498,8 +480,8 @@
 	mdb_printf("----------------------------------------------------");
 	mdb_printf("\n");
 
-	mdb_printf("%7d ", m.m_ncmds);
-	mdb_printf("%s", (m.m_ncmds == slots_in_use ? "  " : "!="));
+	mdb_printf("%7d ", mp->m_ncmds);
+	mdb_printf("%s", (mp->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);
@@ -532,8 +514,8 @@
 
 	/* print the wait queue */
 
-	for (q = m.m_waitq; q; q = c.cmd_linkp) {
-		if (q == m.m_waitq)
+	for (q = mp->m_waitq; q; q = c.cmd_linkp) {
+		if (q == mp->m_waitq)
 			mdb_printf("\n");
 		if (mdb_vread(&c, sizeof (mptsas_cmd_t), (uintptr_t)q)
 		    == -1) {
@@ -549,8 +531,8 @@
 
 	/* print the done queue */
 
-	for (q = m.m_doneq; q; q = c.cmd_linkp) {
-		if (q == m.m_doneq)
+	for (q = mp->m_doneq; q; q = c.cmd_linkp) {
+		if (q == mp->m_doneq)
 			mdb_printf("\n");
 		if (mdb_vread(&c, sizeof (mptsas_cmd_t), (uintptr_t)q)
 		    == -1) {
@@ -566,7 +548,7 @@
 
 	mdb_inc_indent(saved_indent);
 
-	if (m.m_ncmds != slots_in_use)
+	if (mp->m_ncmds != slots_in_use)
 		mdb_printf("WARNING: mpt.m_ncmds does not match the number of "
 		    "slots in use\n");
 
@@ -580,7 +562,7 @@
 
 	/* now check for corruptions */
 
-	for (q = m.m_waitq; q; q = c.cmd_linkp) {
+	for (q = mp->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"
@@ -594,7 +576,7 @@
 		}
 	}
 
-	for (q = m.m_doneq; q; q = c.cmd_linkp) {
+	for (q = mp->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 "
@@ -622,10 +604,6 @@
 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
@@ -639,80 +617,115 @@
 	}
 
 	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");
+	    " 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) ");
+	mdb_printf("%"PRIx64"     %2d  "
+	    "0x%04x 0x%04x ", mp->un.m_base_wwid, mp->m_num_phys,
+	    mp->m_productid, mp->m_devid);
+	switch (mp->m_devid) {
+		case MPI2_MFGPAGE_DEVID_SAS2004:
+			mdb_printf("(SAS2004) ");
+			break;
+		case MPI2_MFGPAGE_DEVID_SAS2008:
+			mdb_printf("(SAS2008) ");
+			break;
+		case MPI2_MFGPAGE_DEVID_SAS2108_1:
+		case MPI2_MFGPAGE_DEVID_SAS2108_2:
+		case MPI2_MFGPAGE_DEVID_SAS2108_3:
+			mdb_printf("(SAS2108) ");
+			break;
+		case MPI2_MFGPAGE_DEVID_SAS2116_1:
+		case MPI2_MFGPAGE_DEVID_SAS2116_2:
+			mdb_printf("(SAS2116) ");
+			break;
+		case MPI2_MFGPAGE_DEVID_SAS2208_1:
+		case MPI2_MFGPAGE_DEVID_SAS2208_2:
+		case MPI2_MFGPAGE_DEVID_SAS2208_3:
+		case MPI2_MFGPAGE_DEVID_SAS2208_4:
+		case MPI2_MFGPAGE_DEVID_SAS2208_5:
+		case MPI2_MFGPAGE_DEVID_SAS2208_6:
+#if 0
+		/* Same as 2308_1/2 ?? */
+		case MPI2_MFGPAGE_DEVID_SAS2208_7:
+		case MPI2_MFGPAGE_DEVID_SAS2208_8:
+#endif
+			mdb_printf("(SAS2208) ");
 			break;
 		default:
-			mdb_printf("(?????) ");
+			mdb_printf("(SAS????) ");
 			break;
 	}
-	mdb_printf("0x%02x 0x%04x\n", m.m_revid, m.m_ssid);
+	mdb_printf("0x%02x 0x%04x\n", mp->m_revid, mp->m_ssid);
 	mdb_printf("%s\n", device_path);
 
+#if 0
 	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]) {
+		switch (mp->m_port_type[i]) {
 			case MPI2_PORTFACTS_PORTTYPE_INACTIVE:
 				mdb_printf("inactive     ",
-				    m.m_protocol_flags[i]);
+				    mp->m_protocol_flags[i]);
 				break;
 			case MPI2_PORTFACTS_PORTTYPE_SCSI:
 				mdb_printf("SCSI (0x%1x)   ",
-				    m.m_protocol_flags[i]);
+				    mp->m_protocol_flags[i]);
 				break;
 			case MPI2_PORTFACTS_PORTTYPE_FC:
 				mdb_printf("FC (0x%1x)     ",
-				    m.m_protocol_flags[i]);
+				    mp->m_protocol_flags[i]);
 				break;
 			case MPI2_PORTFACTS_PORTTYPE_ISCSI:
 				mdb_printf("iSCSI (0x%1x)  ",
-				    m.m_protocol_flags[i]);
+				    mp->m_protocol_flags[i]);
 				break;
 			case MPI2_PORTFACTS_PORTTYPE_SAS:
 				mdb_printf("SAS (0x%1x)    ",
-				    m.m_protocol_flags[i]);
+				    mp->m_protocol_flags[i]);
 				break;
 			default:
 				mdb_printf("unknown      ");
 		}
 	}
+	mdb_printf("\n");
 #endif
+}
+
+void
+dump_debug_log(struct mptsas *mp)
+{
+	uint_t	idx;
+	char	*logbuf;
+	int	i;
+
+	if (mdb_readsym(&idx, sizeof (uint_t),
+		"mptsas_dbglog_idx") == -1) {
+		mdb_warn("No debug log buffer present");
+		return;
+	}
+	logbuf = mdb_alloc(16*256, UM_SLEEP);
+	if (idx == 0) {
+		mdb_warn("Logging turned off");
+		return;
+	}
+	
+	if (mdb_readsym(logbuf, 16*256,
+		"mptsas_dbglog_bufs") == -1) {
+		mdb_warn("No debug log buffer present");
+		return;
+	}
 	mdb_printf("\n");
+	idx &= 0xf;
+	for (i = 0; i < 16; i++) {
+		mdb_printf("%s\n", &logbuf[idx*256]);
+		idx = (idx+1) & 0xf;
+	}
+	mdb_free(logbuf, 16*256);
 }
 
 static int
@@ -728,17 +741,19 @@
 	uint_t			slot_info = FALSE;
 	uint_t			device_info = FALSE;
 	uint_t			port_info = FALSE;
+	uint_t			debug_log = FALSE;
 	int			rv = DCMD_OK;
-	void			*mptsas_state;
 
 	if (!(flags & DCMD_ADDRSPEC)) {
-		mptsas_state = NULL;
+		void		*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) {
+		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);
 		}
@@ -751,6 +766,7 @@
 	    't', MDB_OPT_SETBITS, TRUE, &target_info,
 	    'p', MDB_OPT_SETBITS, TRUE, &port_info,
 	    'v', MDB_OPT_SETBITS, TRUE, &verbose,
+	    'D', MDB_OPT_SETBITS, TRUE, &debug_log,
 	    NULL) != argc)
 		return (DCMD_USAGE);
 
@@ -823,7 +839,7 @@
 	mdb_inc_indent(17);
 
 	if (target_info)
-		display_targets(&m);
+		display_targets(&m, verbose);
 
 	if (port_info)
 		display_ports(&m);
@@ -832,7 +848,10 @@
 		display_deviceinfo(&m);
 
 	if (slot_info)
-		display_slotinfo();
+		display_slotinfo(&m, s);
+
+	if (debug_log)
+		dump_debug_log(&m);
 
 	mdb_dec_indent(17);
 
@@ -850,13 +869,15 @@
 	    "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");
+	    "  -t[v]  includes information about targets, v = be more verbose\n"
+	    "  -p     includes information about port\n"
+	    "  -s     includes information about mpt slots\n"
+	    "  -d     includes information about the hardware\n"
+	    "  -D     print the mptsas specific debug log\n");
 }
 
 static const mdb_dcmd_t dcmds[] = {
-	{ "mptsas", "?[-tpd]", "print mpt_sas information", mptsas_dcmd,
+	{ "mptsas", "?[-tpsdD]", "print mpt_sas information", mptsas_dcmd,
 	    mptsas_help}, { NULL }
 };
 
--- /dev/null	2014-06-12 17:42:14.000000000 +0100
+++ new/usr/src/cmd/mdb/common/modules/mpt_sas3/mpt_sas3.c	2014-06-12 17:42:14.143870790 +0100
@@ -0,0 +1,912 @@
+/*
+ * 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 2014 Joyent, Inc.  All rights reserved.
+ * Copyright (c) 2014, Tegile Systems Inc. All rights reserved.
+ */
+
+#include <limits.h>
+#include <sys/mdb_modapi.h>
+#include <sys/sysinfo.h>
+#include <sys/sunmdi.h>
+#include <sys/list.h>
+#include <sys/scsi/scsi.h>
+
+#pragma pack(1)
+#include <sys/scsi/adapters/mpt_sas3/mpi/mpi2_type.h>
+#include <sys/scsi/adapters/mpt_sas3/mpi/mpi2.h>
+#include <sys/scsi/adapters/mpt_sas3/mpi/mpi2_cnfg.h>
+#include <sys/scsi/adapters/mpt_sas3/mpi/mpi2_init.h>
+#include <sys/scsi/adapters/mpt_sas3/mpi/mpi2_ioc.h>
+#include <sys/scsi/adapters/mpt_sas3/mpi/mpi2_sas.h>
+#include <sys/scsi/adapters/mpt_sas3/mpi/mpi2_raid.h>
+#include <sys/scsi/adapters/mpt_sas3/mpi/mpi2_tool.h>
+#pragma pack()
+
+#include <sys/scsi/adapters/mpt_sas3/mptsas3_var.h>
+#include <sys/scsi/adapters/mpt_sas3/mptsas3_hash.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" }
+};
+
+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 = (int)mdb_strtoull(string);
+	mdi_lun = (int)mdb_strtoull(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 *mp, int target)
+{
+	struct	dev_info	d;
+	struct	mdi_phci	p;
+
+	if (mdb_vread(&d, sizeof (d), (uintptr_t)mp->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 *mp)
+{
+	int i;
+	mdb_printf("\n");
+	mdb_printf("phy number and port mapping table\n");
+	for (i = 0; i < MPTSAS_MAX_PHYS; i++) {
+		if (mp->m_phy_info[i].attached_devhdl) {
+			mdb_printf("phy %x --> port %x, phymask %x,"
+			"attached_devhdl %x\n", i, mp->m_phy_info[i].port_num,
+			    mp->m_phy_info[i].phy_mask,
+			    mp->m_phy_info[i].attached_devhdl);
+		}
+	}
+	mdb_printf("\n");
+}
+
+static uintptr_t
+klist_head(list_t *lp, uintptr_t klp)
+{
+	if ((uintptr_t)lp->list_head.list_next ==
+	    klp + offsetof(struct list, list_head))
+		return (NULL);
+
+	return ((uintptr_t)(((char *)lp->list_head.list_next) -
+	    lp->list_offset));
+}
+
+static uintptr_t
+klist_next(list_t *lp, uintptr_t klp, void *op)
+{
+	/* LINTED E_BAD_PTR_CAST_ALIG */
+	struct list_node *np = (struct list_node *)(((char *)op) +
+	    lp->list_offset);
+
+	if ((uintptr_t)np->list_next == klp + offsetof(struct list, list_head))
+		return (NULL);
+
+	return (((uintptr_t)(np->list_next)) - lp->list_offset);
+}
+
+static void *
+krefhash_first(uintptr_t khp, uintptr_t *addr)
+{
+	refhash_t mh;
+	uintptr_t klp;
+	uintptr_t kop;
+	void *rp;
+
+	mdb_vread(&mh, sizeof (mh), khp);
+	klp = klist_head(&mh.rh_objs, khp + offsetof(refhash_t, rh_objs));
+	if (klp == 0)
+		return (NULL);
+
+	kop = klp - mh.rh_link_off;
+	if (addr)
+		*addr = kop;
+	rp = mdb_alloc(mh.rh_obj_size, UM_SLEEP);
+	mdb_vread(rp, mh.rh_obj_size, kop);
+
+	return (rp);
+}
+
+static void *
+krefhash_next(uintptr_t khp, void *op, uintptr_t *addr)
+{
+	refhash_t mh;
+	void *prev = op;
+	refhash_link_t *lp;
+	uintptr_t klp;
+	uintptr_t kop;
+	refhash_link_t ml;
+	void *rp;
+
+	mdb_vread(&mh, sizeof (mh), khp);
+	/* LINTED E_BAD_PTR_CAST_ALIG */
+	lp = (refhash_link_t *)(((char *)(op)) + mh.rh_link_off);
+	ml = *lp;
+	while ((klp = klist_next(&mh.rh_objs,
+	    khp + offsetof(refhash_t, rh_objs), &ml)) != NULL) {
+		mdb_vread(&ml, sizeof (ml), klp);
+		if (!(ml.rhl_flags & RHL_F_DEAD))
+			break;
+	}
+
+	if (klp == 0) {
+		mdb_free(prev, mh.rh_obj_size);
+		return (NULL);
+	}
+
+	kop = klp - mh.rh_link_off;
+	if (addr)
+		*addr = kop;
+	rp = mdb_alloc(mh.rh_obj_size, UM_SLEEP);
+	mdb_vread(rp, mh.rh_obj_size, kop);
+
+	mdb_free(prev, mh.rh_obj_size);
+	return (rp);
+}
+
+void
+display_targets(struct mptsas *mp, uint_t verbose)
+{
+	mptsas_target_t *ptgt;
+	mptsas_smp_t *psmp;
+	int loop, comma;
+	uintptr_t p_addr;
+
+	mdb_printf("\n");
+	mdb_printf(" mptsas_target_t slot devhdl      wwn     ncmds throttle   "
+	    "dr_flag dups\n");
+	mdb_printf("---------------------------------------"
+	    "-------------------------------\n");
+	for (ptgt = (mptsas_target_t *)krefhash_first(
+		(uintptr_t)mp->m_targets, &p_addr);
+	    ptgt != NULL;
+	    ptgt = krefhash_next((uintptr_t)mp->m_targets, ptgt, &p_addr)) {
+		if (ptgt->m_addr.mta_wwn ||
+		    ptgt->m_deviceinfo) {
+			mdb_printf("%16p ", p_addr);
+			mdb_printf("%4d ", ptgt->m_slot_num);
+			mdb_printf("%4d ", ptgt->m_devhdl);
+			if (ptgt->m_addr.mta_wwn)
+				mdb_printf("%"PRIx64" ",
+				    ptgt->m_addr.mta_wwn);
+			mdb_printf("%3d", ptgt->m_t_ncmds);
+			switch (ptgt->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;
+				default:
+					mdb_printf("%8d ",
+					    ptgt->m_t_throttle);
+			}
+			switch (ptgt->m_dr_flag) {
+				case MPTSAS_DR_INACTIVE:
+					mdb_printf("  INACTIVE ");
+					break;
+				case MPTSAS_DR_INTRANSITION:
+					mdb_printf("TRANSITION ");
+					break;
+				default:
+					mdb_printf("   UNKNOWN ");
+					break;
+				}
+			mdb_printf("%d\n",
+			    ptgt->m_dups);
+
+			if (verbose) {
+				mdb_inc_indent(5);
+				if ((ptgt->m_deviceinfo &
+				    MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) ==
+				    MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER)
+					mdb_printf("Fanout expander: ");
+				if ((ptgt->m_deviceinfo &
+				    MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) ==
+				    MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER)
+					mdb_printf("Edge expander: ");
+				if ((ptgt->m_deviceinfo &
+				    MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) ==
+				    MPI2_SAS_DEVICE_INFO_END_DEVICE)
+					mdb_printf("End device: ");
+				if ((ptgt->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 (ptgt->m_deviceinfo &
+					    devinfo_array[loop].value) {
+						mdb_printf("%s%s",
+						    (comma ? ", " : ""),
+						    devinfo_array[loop].text);
+						comma++;
+					}
+				}
+				mdb_printf("\n");
+				mdi_info(mp, ptgt->m_slot_num);
+				mdb_dec_indent(5);
+			}
+		}
+	}
+
+	mdb_printf("\n");
+	mdb_printf("    mptsas_smp_t devhdl      wwn          phymask\n");
+	mdb_printf("---------------------------------------"
+	    "------------------\n");
+	for (psmp = (mptsas_smp_t *)krefhash_first(
+	    (uintptr_t)mp->m_smp_targets, &p_addr);
+	    psmp != NULL;
+	    psmp = krefhash_next((uintptr_t)mp->m_smp_targets, psmp,
+	    &p_addr)) {
+		mdb_printf("%16p   ", p_addr);
+		mdb_printf("%4d  %"PRIx64"    %04x\n",
+		    psmp->m_devhdl, psmp->m_addr.mta_wwn,
+		    psmp->m_addr.mta_phymask);
+		if (verbose) {
+			mdb_inc_indent(5);
+			if ((psmp->m_deviceinfo &
+				MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) ==
+			    MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER)
+				mdb_printf("Fanout expander: ");
+			if ((psmp->m_deviceinfo &
+				MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) ==
+			    MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER)
+				mdb_printf("Edge expander: ");
+			if ((psmp->m_deviceinfo &
+				MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) ==
+			    MPI2_SAS_DEVICE_INFO_END_DEVICE)
+				mdb_printf("End device: ");
+			if ((psmp->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 (psmp->m_deviceinfo &
+				    devinfo_array[loop].value) {
+					mdb_printf("%s%s",
+					    (comma ? ", " : ""),
+					    devinfo_array[loop].text);
+					comma++;
+				}
+			}
+			mdb_printf("\n");
+			mdb_dec_indent(5);
+		}
+	}
+}
+
+int
+display_slotinfo(struct mptsas *mp, struct mptsas_slots *s)
+{
+	int			i, nslots;
+	struct mptsas_cmd	c, *q, *slots;
+	mptsas_target_t		*ptgt;
+	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_normal;
+	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 = mp->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 = mp->m_dlist.dl_q, 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 (ptgt = (mptsas_target_t *)krefhash_first(
+		(uintptr_t)mp->m_targets, NULL);
+	    ptgt != NULL;
+	     ptgt = krefhash_next((uintptr_t)mp->m_targets, ptgt, NULL)) {
+		if (ptgt->m_addr.mta_wwn ||
+		    ptgt->m_deviceinfo) {
+			ncmds += ptgt->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 ", mp->m_ncmds);
+	mdb_printf("%s", (mp->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_normal; 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 = mp->m_waitq; q; q = c.cmd_linkp) {
+		if (q == mp->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 = mp->m_dlist.dl_q; q; q = c.cmd_linkp) {
+		if (q == mp->m_dlist.dl_q)
+			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 (mp->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 = mp->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 = mp->m_dlist.dl_q; 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);
+}
+
+void
+display_deviceinfo(struct mptsas *mp)
+{
+	char	device_path[PATH_MAX];
+
+	*device_path = 0;
+	if (construct_path((uintptr_t)mp->m_dip, device_path) != DCMD_OK) {
+		strcpy(device_path, "couldn't determine device path");
+	}
+
+	mdb_printf("\n");
+	mdb_printf("base_wwid          phys "
+	    " prodid  devid          revid   ssid\n");
+	mdb_printf("-----------------------------"
+	    "----------------------------------\n");
+	mdb_printf("%"PRIx64"     %2d  "
+	    "0x%04x 0x%04x ", mp->un.m_base_wwid, mp->m_num_phys,
+	    mp->m_productid, mp->m_devid);
+	switch (mp->m_devid) {
+		case MPI2_MFGPAGE_DEVID_SAS2004:
+			mdb_printf("(SAS2004) ");
+			break;
+		case MPI2_MFGPAGE_DEVID_SAS2008:
+			mdb_printf("(SAS2008) ");
+			break;
+		case MPI2_MFGPAGE_DEVID_SAS2108_1:
+		case MPI2_MFGPAGE_DEVID_SAS2108_2:
+		case MPI2_MFGPAGE_DEVID_SAS2108_3:
+			mdb_printf("(SAS2108) ");
+			break;
+		case MPI2_MFGPAGE_DEVID_SAS2116_1:
+		case MPI2_MFGPAGE_DEVID_SAS2116_2:
+			mdb_printf("(SAS2116) ");
+			break;
+		case MPI2_MFGPAGE_DEVID_SSS6200:
+			mdb_printf("(SSS6200) ");
+			break;
+		case MPI2_MFGPAGE_DEVID_SAS2208_1:
+		case MPI2_MFGPAGE_DEVID_SAS2208_2:
+		case MPI2_MFGPAGE_DEVID_SAS2208_3:
+		case MPI2_MFGPAGE_DEVID_SAS2208_4:
+		case MPI2_MFGPAGE_DEVID_SAS2208_5:
+		case MPI2_MFGPAGE_DEVID_SAS2208_6:
+#if 0
+		/* Same as 2308_1/2 ?? */
+		case MPI2_MFGPAGE_DEVID_SAS2208_7:
+		case MPI2_MFGPAGE_DEVID_SAS2208_8:
+#endif
+			mdb_printf("(SAS2208) ");
+			break;
+		case MPI2_MFGPAGE_DEVID_SAS2308_1:
+		case MPI2_MFGPAGE_DEVID_SAS2308_2:
+		case MPI2_MFGPAGE_DEVID_SAS2308_3:
+			mdb_printf("(SAS2308) ");
+			break;
+		case MPI25_MFGPAGE_DEVID_SAS3004:
+			mdb_printf("(SAS3004) ");
+			break;
+		case MPI25_MFGPAGE_DEVID_SAS3008:
+			mdb_printf("(SAS3008) ");
+			break;
+		case MPI25_MFGPAGE_DEVID_SAS3108_1:
+		case MPI25_MFGPAGE_DEVID_SAS3108_2:
+		case MPI25_MFGPAGE_DEVID_SAS3108_3:
+		case MPI25_MFGPAGE_DEVID_SAS3108_4:
+		case MPI25_MFGPAGE_DEVID_SAS3108_5:
+		case MPI25_MFGPAGE_DEVID_SAS3108_6:
+			mdb_printf("(SAS3108) ");
+			break;
+		default:
+			mdb_printf("(SAS????) ");
+			break;
+	}
+	mdb_printf("0x%02x 0x%04x\n", mp->m_revid, mp->m_ssid);
+	mdb_printf("%s\n", device_path);
+}
+
+void
+dump_debug_log(struct mptsas *mp)
+{
+	uint_t	idx;
+	char	*logbuf;
+	int	i;
+
+	if (mdb_readsym(&idx, sizeof (uint_t),
+		"mptsas_dbglog_idx") == -1) {
+		mdb_warn("No debug log buffer present");
+		return;
+	}
+	logbuf = mdb_alloc(32*256, UM_SLEEP);
+	if (idx == 0) {
+		mdb_warn("Logging turned off");
+		return;
+	}
+
+	if (mdb_readsym(logbuf, 32*256,
+		"mptsas_dbglog_bufs") == -1) {
+		mdb_warn("No debug log buffer present");
+		return;
+	}
+	mdb_printf("\n");
+	idx &= 0x1f;
+	for (i = 0; i < 32; i++) {
+		mdb_printf("%s\n", &logbuf[idx*256]);
+		idx = (idx+1) & 0x1f;
+	}
+	mdb_free(logbuf, 32*256);
+}
+
+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;
+	uint_t			debug_log = FALSE;
+	int			rv = DCMD_OK;
+
+	if (!(flags & DCMD_ADDRSPEC)) {
+		void		*mptsas3_state = NULL;
+
+		if (mdb_readvar(&mptsas3_state, "mptsas3_state") == -1) {
+			mdb_warn("can't read mptsas3_state");
+			return (DCMD_ERR);
+		}
+		if (mdb_pwalk_dcmd("genunix`softstate",
+			"mpt_sas3`mptsas3", argc,
+			argv, (uintptr_t)mptsas3_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,
+	    'D', MDB_OPT_SETBITS, TRUE, &debug_log,
+	    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_normal;
+
+	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(&m, verbose);
+
+	if (port_info)
+		display_ports(&m);
+
+	if (device_info)
+		display_deviceinfo(&m);
+
+	if (slot_info)
+		display_slotinfo(&m, s);
+
+	if (debug_log)
+		dump_debug_log(&m);
+
+	mdb_dec_indent(17);
+
+	mdb_free(s, slot_size);
+
+	return (rv);
+}
+
+void
+mptsas_help()
+{
+	mdb_printf("Prints summary information about each mpt_sas3 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[v]  includes information about targets, v = be more verbose\n"
+	    "  -p     includes information about port\n"
+	    "  -s     includes information about mpt slots\n"
+	    "  -d     includes information about the hardware\n"
+	    "  -D     print the mptsas specific debug log\n");
+}
+
+static const mdb_dcmd_t dcmds[] = {
+	{ "mptsas3", "?[-tpsdD]", "print mpt_sas3 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	2014-06-12 17:42:14.000000000 +0100
+++ new/usr/src/cmd/mdb/intel/amd64/mpt_sas3/Makefile	2014-06-12 17:42:14.230230958 +0100
@@ -0,0 +1,37 @@
+#
+# 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_sas3.so
+MDBTGT = kvm
+
+MODSRCS = mpt_sas3.c
+
+include ../../../../Makefile.cmd
+include ../../../../Makefile.cmd.64
+include ../../Makefile.amd64
+include ../../../Makefile.module
+
+CPPFLAGS += -I$(SRC)/uts/common
+
+CERRWARN += -_gcc=-Wno-trigraphs
--- /dev/null	2014-06-12 17:42:14.000000000 +0100
+++ new/usr/src/cmd/mdb/intel/ia32/mpt_sas3/Makefile	2014-06-12 17:42:14.305850563 +0100
@@ -0,0 +1,37 @@
+#
+# 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_sas3.so
+MDBTGT = kvm
+
+MODSRCS = mpt_sas3.c
+
+include ../../../../Makefile.cmd
+include ../../Makefile.ia32
+include ../../../Makefile.module
+
+CPPFLAGS += -I$(SRC)/uts/common
+
+CERRWARN += -_gcc=-Wno-trigraphs
--- /dev/null	2014-06-12 17:42:14.000000000 +0100
+++ new/usr/src/cmd/mdb/sparc/v9/mpt_sas3/Makefile	2014-06-12 17:42:14.385154470 +0100
@@ -0,0 +1,37 @@
+#
+# 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_sas3.so
+MDBTGT = kvm
+
+MODSRCS = mpt_sas3.c
+
+include ../../../../Makefile.cmd
+include ../../../../Makefile.cmd.64
+include ../../Makefile.sparcv9
+include ../../../Makefile.module
+
+CPPFLAGS += -I$(SRC)/uts/common
+
+CERRWARN += -_gcc=-Wno-trigraphs
--- old/usr/src/man/man7d/Makefile	2014-06-12 17:42:14.459323278 +0100
+++ new/usr/src/man/man7d/Makefile	2014-06-12 17:42:14.465825498 +0100
@@ -83,6 +83,7 @@
 		mediator.7d	\
 		mem.7d		\
 		mpt_sas.7d	\
+		mpt_sas3.7d	\
 		mr_sas.7d	\
 		msglog.7d	\
 		mt.7d		\
--- /dev/null	2014-06-12 17:42:14.000000000 +0100
+++ new/usr/src/man/man7d/mpt_sas3.7d	2014-06-12 17:42:14.622457944 +0100
@@ -0,0 +1,140 @@
+'\" te
+.\" Copyright (c) 2009, Sun Microsystems, Inc. All Rights Reserved
+.\" 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]
+.TH MPT_SAS3 7D "Jun 2, 2014"
+.SH NAME
+mpt_sas3 \- SAS-3 host bus adapter driver
+.SH SYNOPSIS
+.sp
+.in +2
+.nf
+scsi@unit-address
+.fi
+.in -2
+
+.SH DESCRIPTION
+.sp
+.LP
+The \fBmpt_sas3\fR host bus adapter driver is a nexus driver that supports the
+LSI SAS300x/3108 series of chips. These chips support SAS/SATA interfaces,
+including tagged and untagged queuing, multiple MSI-X interrupts, LSI
+fastpath and SATA 3G/6G/12G.
+.SS "Configuration"
+.sp
+.LP
+The \fBmpt_sas3\fR driver is configured by defining properties in
+\fBmpt_sas3.conf\fR. These properties override the global SCSI settings. The
+\fBmpt_sas3\fR driver supports one modifiable property:
+.sp
+.ne 2
+.na
+\fB\fBmpxio-disable\fR\fR
+.ad
+.sp .6
+.RS 4n
+Solaris I/O multipathing is enabled or disabled on SAS devices with the
+\fBmpxio-disable\fR property. Specifying \fBmpxio-disable="no"\fR activates I/O
+multipathing, while \fBmpxio-disable="yes"\fR disables I/O multipathing.
+.sp
+Solaris I/O multipathing can be enabled or disabled on a per port basis. Per
+port settings override the global setting for the specified ports.
+.sp
+The following example shows how to disable multipathing on port 0 whose parent
+is \fB/pci@0,0/pci8086,2940@1c/pci1000,90@0\fR:
+.sp
+.in +2
+.nf
+name="mpt_sas3"    parent="/pci@0,0/pci8086,2940@1c/pci1000,90@0"
+mpxio-disable="yes";
+.fi
+.in -2
+
+The \fBmpt_sas3\fR host bus adapter driver is also capable of driving older
+SAS2 controllers cards such as 2008 - 2308. Replacing the older mpt_sas driver
+with mpt_sas3 will automatically enhance the performance where the card
+is capable.
+
+.RE
+
+.SH EXAMPLES
+.LP
+\fBExample 1 \fRUsing the \fBmpt_sas3\fR Configuration File to Disable MPXIO
+.sp
+.LP
+Create a file called \fB/kernel/drv/mpt_sas3.conf\fR and add the following line:
+
+.sp
+.in +2
+.nf
+name="mpt_sas3"    parent="/pci@0,0/pci8086,2940@1c/pci1000,90@0"
+mpxio-disable="yes";
+.fi
+.in -2
+
+.SH FILES
+.sp
+.ne 2
+.na
+\fB\fB/kernel/drv/mpt_sas3\fR\fR
+.ad
+.sp .6
+.RS 4n
+32-bit ELF kernel module
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB/kernel/drv/sparcv9/mpt_sas3\fR\fR
+.ad
+.sp .6
+.RS 4n
+64-bit SPARC ELF kernel module
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB/kernel/drv/amd64/mpt_sas3\fR\fR
+.ad
+.sp .6
+.RS 4n
+64-bit x86 ELF kernel module
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB/kernel/drv/mpt_sas3.conf\fR\fR
+.ad
+.sp .6
+.RS 4n
+Optional configuration file
+.RE
+
+.SH ATTRIBUTES
+.sp
+.LP
+See \fBattributes\fR(5) for a description of the following attributes:
+.sp
+
+.sp
+.TS
+box;
+l | l
+l | l .
+ATTRIBUTE TYPE	ATTRIBUTE VALUE
+_
+Architecture	SPARC, x86
+.TE
+
+.SH SEE ALSO
+.sp
+.LP
+\fBprtconf\fR(1M), \fBdriver.conf\fR(4), \fBpci\fR(4), \fBattributes\fR(5),
+\fBscsi_abort\fR(9F), \fBscsi_device\fR(9S), \fBscsi_extended_sense\fR(9S),
+\fBscsi_inquiry\fR(9S), \fBscsi_hba_attach_setup\fR(9F), \fBupdate_drv\fR(1M),
+\fBscsi_ifgetcap\fR(9F), \fBscsi_ifsetcap\fR(9F), \fBscsi_pkt\fR(9S),
+\fBscsi_reset\fR(9F), \fBscsi_sync_pkt\fR(9F), \fBscsi_transport\fR(9F),
--- old/usr/src/pkg/manifests/developer-debug-mdb.mf	2014-06-12 17:42:14.696288592 +0100
+++ new/usr/src/pkg/manifests/developer-debug-mdb.mf	2014-06-12 17:42:14.703062438 +0100
@@ -110,6 +110,7 @@
 file path=kernel/kmdb/$(ARCH64)/mdb_ds group=sys mode=0555
 file path=kernel/kmdb/$(ARCH64)/mpt group=sys mode=0555
 file path=kernel/kmdb/$(ARCH64)/mpt_sas group=sys mode=0555
+file path=kernel/kmdb/$(ARCH64)/mpt_sas3 group=sys mode=0555
 file path=kernel/kmdb/$(ARCH64)/mr_sas group=sys mode=0555
 file path=kernel/kmdb/$(ARCH64)/nca group=sys mode=0555
 file path=kernel/kmdb/$(ARCH64)/neti group=sys mode=0555
@@ -146,6 +147,7 @@
 $(i386_ONLY)file path=kernel/kmdb/mdb_ds group=sys mode=0555
 $(i386_ONLY)file path=kernel/kmdb/mpt group=sys mode=0555
 $(i386_ONLY)file path=kernel/kmdb/mpt_sas group=sys mode=0555
+$(i386_ONLY)file path=kernel/kmdb/mpt_sas3 group=sys mode=0555
 $(i386_ONLY)file path=kernel/kmdb/mr_sas group=sys mode=0555
 $(i386_ONLY)file path=kernel/kmdb/nca group=sys mode=0555
 $(i386_ONLY)file path=kernel/kmdb/neti group=sys mode=0555
@@ -227,6 +229,7 @@
 file path=usr/lib/mdb/kvm/$(ARCH64)/mdb_ks.so group=sys mode=0555
 file path=usr/lib/mdb/kvm/$(ARCH64)/mpt.so group=sys mode=0555
 file path=usr/lib/mdb/kvm/$(ARCH64)/mpt_sas.so group=sys mode=0555
+file path=usr/lib/mdb/kvm/$(ARCH64)/mpt_sas3.so group=sys mode=0555
 file path=usr/lib/mdb/kvm/$(ARCH64)/mr_sas.so group=sys mode=0555
 file path=usr/lib/mdb/kvm/$(ARCH64)/nca.so group=sys mode=0555
 file path=usr/lib/mdb/kvm/$(ARCH64)/neti.so group=sys mode=0555
@@ -265,6 +268,7 @@
 $(i386_ONLY)file path=usr/lib/mdb/kvm/mdb_ks.so group=sys mode=0555
 $(i386_ONLY)file path=usr/lib/mdb/kvm/mpt.so group=sys mode=0555
 $(i386_ONLY)file path=usr/lib/mdb/kvm/mpt_sas.so group=sys mode=0555
+$(i386_ONLY)file path=usr/lib/mdb/kvm/mpt_sas3.so group=sys mode=0555
 $(i386_ONLY)file path=usr/lib/mdb/kvm/mr_sas.so group=sys mode=0555
 $(i386_ONLY)file path=usr/lib/mdb/kvm/nca.so group=sys mode=0555
 $(i386_ONLY)file path=usr/lib/mdb/kvm/neti.so group=sys mode=0555
--- /dev/null	2014-06-12 17:42:14.000000000 +0100
+++ new/usr/src/pkg/manifests/driver-storage-mpt_sas3.mf	2014-06-12 17:42:14.863417973 +0100
@@ -0,0 +1,50 @@
+#
+# 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) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+#
+# The default for payload-bearing actions in this package is to appear in the
+# global zone only.  See the include file for greater detail, as well as
+# information about overriding the defaults.
+#
+<include global_zone_only_component>
+set name=pkg.fmri value=pkg:/driver/storage/mpt_sas3@$(PKGVERS)
+set name=pkg.description value="LSI MPT SAS 3.0 Controller HBA Driver"
+set name=pkg.summary value="LSI MPT SAS 3.0 Controller HBA Driver"
+set name=info.classification \
+    value=org.opensolaris.category.2008:Drivers/Storage
+set name=variant.arch value=$(ARCH)
+dir path=kernel group=sys
+dir path=kernel/drv group=sys
+dir path=kernel/drv/$(ARCH64) group=sys
+dir path=usr/share/man
+dir path=usr/share/man/man7d
+driver name=mpt_sas3 class=scsi-self-identifying \
+    alias=pciex1000,90 \
+    alias=pciex1000,97
+file path=kernel/drv/$(ARCH64)/mpt_sas3 group=sys
+$(i386_ONLY)file path=kernel/drv/mpt_sas3 group=sys
+file path=kernel/drv/mpt_sas3.conf group=sys preserve=true
+file path=usr/share/man/man7d/mpt_sas3.7d
+license lic_CDDL license=lic_CDDL
--- old/usr/src/uts/common/Makefile.files	2014-06-12 17:42:14.936375970 +0100
+++ new/usr/src/uts/common/Makefile.files	2014-06-12 17:42:14.942845534 +0100
@@ -1849,6 +1849,9 @@
 MPTSAS_OBJS += mptsas.o mptsas_hash.o mptsas_impl.o mptsas_init.o \
 		mptsas_raid.o mptsas_smhba.o
 
+MPTSAS3_OBJS += mptsas3.o mptsas3_hash.o mptsas3_impl.o mptsas3_init.o \
+		mptsas3_raid.o mptsas3_smhba.o
+
 SFE_OBJS += sfe.o sfe_util.o
 
 BFE_OBJS += bfe.o
--- old/usr/src/uts/common/Makefile.rules	2014-06-12 17:42:15.147378304 +0100
+++ new/usr/src/uts/common/Makefile.rules	2014-06-12 17:42:15.155040466 +0100
@@ -938,6 +938,10 @@
 	$(COMPILE.c) -o $@ $<
 	$(CTFCONVERT_O)
 
+$(OBJS_DIR)/%.o:		$(UTSBASE)/common/io/scsi/adapters/mpt_sas3/%.c
+	$(COMPILE.c) -o $@ $<
+	$(CTFCONVERT_O)
+
 $(OBJS_DIR)/%.o:		$(UTSBASE)/common/io/mxfe/%.c
 	$(COMPILE.c) -o $@ $<
 	$(CTFCONVERT_O)
@@ -2234,6 +2238,9 @@
 $(LINTS_DIR)/%.ln:		$(UTSBASE)/common/io/scsi/adapters/mpt_sas/%.c
 	@($(LHEAD) $(LINT.c) $< $(LTAIL))
 
+$(LINTS_DIR)/%.ln:		$(UTSBASE)/common/io/scsi/adapters/mpt_sas3/%.c
+	@($(LHEAD) $(LINT.c) $< $(LTAIL))
+
 $(LINTS_DIR)/%.ln:		$(UTSBASE)/common/io/mxfe/%.c
 	@($(LHEAD) $(LINT.c) $< $(LTAIL))
 
--- old/usr/src/uts/common/io/scsi/adapters/mpt_sas3/mptsas3.c	2014-06-12 17:42:15.393924923 +0100
+++ new/usr/src/uts/common/io/scsi/adapters/mpt_sas3/mptsas3.c	2014-06-12 17:42:15.405774308 +0100
@@ -21,8 +21,10 @@
 
 /*
  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
  * Copyright (c) 2014, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2014, Tegile Systems Inc. All rights reserved.
+ * Copyright 2014 OmniTI Computer Consulting, Inc. All rights reserved.
  */
 
 /*
@@ -53,7 +55,7 @@
  */
 
 /*
- * mptsas - This is a driver based on LSI Logic's MPT2.0 interface.
+ * mptsas3 - This is a driver based on LSI Logic's MPT2.0/2.5 interface.
  *
  */
 
@@ -78,14 +80,14 @@
 #include <sys/scsi/impl/scsi_sas.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>
-#include <sys/scsi/adapters/mpt_sas/mpi/mpi2_tool.h>
-#include <sys/scsi/adapters/mpt_sas/mpi/mpi2_raid.h>
+#include <sys/scsi/adapters/mpt_sas3/mpi/mpi2_type.h>
+#include <sys/scsi/adapters/mpt_sas3/mpi/mpi2.h>
+#include <sys/scsi/adapters/mpt_sas3/mpi/mpi2_cnfg.h>
+#include <sys/scsi/adapters/mpt_sas3/mpi/mpi2_init.h>
+#include <sys/scsi/adapters/mpt_sas3/mpi/mpi2_ioc.h>
+#include <sys/scsi/adapters/mpt_sas3/mpi/mpi2_sas.h>
+#include <sys/scsi/adapters/mpt_sas3/mpi/mpi2_tool.h>
+#include <sys/scsi/adapters/mpt_sas3/mpi/mpi2_raid.h>
 #pragma pack()
 
 /*
@@ -93,10 +95,10 @@
  *
  */
 #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/scsi/adapters/mpt_sas/mptsas_smhba.h>
-#include <sys/scsi/adapters/mpt_sas/mptsas_hash.h>
+#include <sys/scsi/adapters/mpt_sas3/mptsas3_var.h>
+#include <sys/scsi/adapters/mpt_sas3/mptsas3_ioctl.h>
+#include <sys/scsi/adapters/mpt_sas3/mptsas3_smhba.h>
+#include <sys/scsi/adapters/mpt_sas3/mptsas3_hash.h>
 #include <sys/raidioctl.h>
 
 #include <sys/fs/dv_node.h>	/* devfs_clean */
@@ -144,9 +146,11 @@
 static int mptsas_cache_create(mptsas_t *mpt);
 static void mptsas_cache_destroy(mptsas_t *mpt);
 static int mptsas_alloc_request_frames(mptsas_t *mpt);
+static int mptsas_alloc_sense_bufs(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 void mptsas_free_post_queue(mptsas_t *mpt);
 static void mptsas_alloc_reply_args(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);
@@ -201,9 +205,14 @@
 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 void mptsas_retry_pkt(mptsas_t *mpt, mptsas_cmd_t *sp);
+static int mptsas_save_cmd_to_slot(mptsas_t *mpt, mptsas_cmd_t *cmd);
+static int mptsas_accept_pkt(mptsas_t *mpt, mptsas_cmd_t *sp,
+    int *tran_rval);
+static void mptsas_accept_tx_waitqs(mptsas_t *mpt);
+static void mptsas_unblock_tx_waitqs(mptsas_t *mpt);
+static void mptsas_drain_tx_waitq(mptsas_t *mpt, mptsas_tx_waitqueue_t *txwq);
+static int mptsas_check_targ_intxtion(mptsas_target_t *ptgt, int cmd_pkt_flags);
 
 static int mptsas_do_detach(dev_info_t *dev);
 static int mptsas_do_scsi_reset(mptsas_t *mpt, uint16_t devhdl);
@@ -227,10 +236,10 @@
     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,
+static void mptsas_process_intr(mptsas_t *mpt, mptsas_reply_pqueue_t *rpqp,
     pMpi2ReplyDescriptorsUnion_t reply_desc_union);
 static void mptsas_handle_scsi_io_success(mptsas_t *mpt,
-    pMpi2ReplyDescriptorsUnion_t reply_desc);
+    mptsas_reply_pqueue_t *rpqp, 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);
@@ -239,12 +248,12 @@
 
 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_cmd_timeout(mptsas_t *mpt, mptsas_target_t *ptgt);
 
 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 data_size, uint8_t direction, uint8_t *dataout,
     uint32_t dataout_size, short timeout, int mode);
 static int mptsas_free_devhdl(mptsas_t *mpt, uint16_t devhdl);
 
@@ -299,24 +308,32 @@
 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_deliver_doneq_thread(mptsas_t *mpt,
+    mptsas_done_list_t *dlist);
 static void mptsas_doneq_add(mptsas_t *mpt, mptsas_cmd_t *cmd);
-static void mptsas_doneq_mv(mptsas_t *mpt, uint64_t t);
+static void mptsas_rpdoneq_add(mptsas_t *mpt, mptsas_reply_pqueue_t *rpqp,
+    mptsas_cmd_t *cmd);
+static void mptsas_doneq_mv(mptsas_done_list_t *from,
+    mptsas_doneq_thread_list_t *item);
 
 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 void mptsas_rpdoneq_empty(mptsas_reply_pqueue_t *rpqp);
+static void mptsas_doneq_thread(mptsas_thread_arg_t *arg);
+static void mptsas_tx_waitq_thread(mptsas_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);
+static void mptsas_set_throttle(struct mptsas *mpt, mptsas_target_t *ptgt,
+    int what);
+static void mptsas_set_throttle_mtx(struct mptsas *mpt, mptsas_target_t *ptgt,
+    int what);
+static void mptsas_remove_cmd_nomtx(mptsas_t *mpt, mptsas_cmd_t *cmd);
 
 /*
  * helper functions
@@ -369,7 +386,9 @@
     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_offline_targetdev(dev_info_t *pdip, char *name);
+static void mptsas_offline_target(mptsas_t *mpt, mptsas_target_t *ptgt,
+    uint8_t topo_flags, dev_info_t *parent);
 
 static int mptsas_config_raid(dev_info_t *pdip, uint16_t target,
     dev_info_t **dip);
@@ -425,8 +444,14 @@
  * By default MSI is enabled on all supported platforms.
  */
 boolean_t mptsas_enable_msi = B_TRUE;
+boolean_t mptsas_enable_msix = B_TRUE;
 boolean_t mptsas_physical_bind_failed_page_83 = B_FALSE;
 
+/*
+ * Global switch for use of MPI2.5 FAST PATH.
+ */
+boolean_t mptsas3_use_fastpath = B_TRUE;
+
 static int mptsas_register_intrs(mptsas_t *);
 static void mptsas_unregister_intrs(mptsas_t *);
 static int mptsas_add_intrs(mptsas_t *, int);
@@ -440,6 +465,14 @@
 static int mptsas_fm_error_cb(dev_info_t *, ddi_fm_error_t *, const void *);
 
 extern pri_t minclsyspri, maxclsyspri;
+/*
+ * NCPUS is used to determine some optimal configurations for number
+ * of threads created to perform specific jobs. If we are invoked because
+ * a disk is part of the root file system ncpus may still be 1 so check
+ * boot_ncpus as well.
+ */
+extern int ncpus, boot_ncpus;
+#define	NCPUS	max(ncpus, boot_ncpus)
 
 /*
  * This device is created by the SCSI pseudo nexus driver (SCSI vHCI).  It is
@@ -455,6 +488,13 @@
 int mptsas_inq83_retry_timeout = 30;
 
 /*
+ * Tunable for default SCSI pkt timeout. Defaults to 5 seconds, which should
+ * be plenty for INQUIRY and REPORT_LUNS, which are the only commands currently
+ * issued by mptsas directly.
+ */
+int mptsas_scsi_pkt_time = 5;
+
+/*
  * 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.
@@ -490,7 +530,7 @@
 	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 */
+	0		/* flags, set to 0 */
 };
 
 ddi_device_acc_attr_t mptsas_dev_attr = {
@@ -545,7 +585,7 @@
 };
 
 
-#define	MPTSAS_MOD_STRING "MPTSAS HBA Driver 00.00.00.24"
+#define	MPTSAS_MOD_STRING "MPTSAS3 HBA Driver 00.00.01"
 
 static struct modldrv modldrv = {
 	&mod_driverops,	/* Type of module. This one is a driver */
@@ -568,12 +608,19 @@
  * Local static data
  */
 #if defined(MPTSAS_DEBUG)
-uint32_t mptsas_debug_flags = 0;
+uint32_t mptsas_debug_flags = 0x0;
+/*
+ * Flags to ignore these messages in local debug ring buffer.
+ * Default is to ignore the watchsubr() output which normally happens
+ * every second.
+ */
+uint32_t mptsas_dbglog_imask = 0x40000000;
+uint32_t mptsas_test_timeout = 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 void		*mptsas3_state;		/* soft	state ptr */
 static krwlock_t	mptsas_global_rwlock;
 
 static kmutex_t		mptsas_log_mutex;
@@ -586,6 +633,35 @@
 static timeout_id_t mptsas_reset_watch;
 static timeout_id_t mptsas_timeout_id;
 static int mptsas_timeouts_enabled = 0;
+
+/*
+ * Maximum number of MSI-X interrupts any instance of mptsas3 can use.
+ * Note that if you want to increase this you may have to also bump the
+ * value of ddi_msix_alloc_limit which defaults to 8.
+ * Set to zero to fall back to other interrupt types.
+ */
+int mptsas3_max_msix_intrs = 8;
+
+/*
+ * Default length for extended auto request sense buffers.
+ * All sense buffers need to be under the same alloc because there
+ * is only one common top 32bits (of 64bits) address register.
+ * Most requests only require 32 bytes, but some request >256.
+ * We use rmalloc()/rmfree() on this additional memory to manage the
+ * "extended" requests.
+ */
+int mptsas_extreq_sense_bufsize = 256*64;
+
+/*
+ * Believe that all software resrictions of having to run with DMA
+ * attributes to limit allocation to the first 4G are removed.
+ * However, this flag remains to enable quick switchback should suspicious
+ * problems emerge.
+ * Note that scsi_alloc_consistent_buf() does still adhering to allocating
+ * 32 bit addressable memory, but we can cope if that is changed now.
+ */
+int mptsas_use_64bit_msgaddr = 1;
+
 /*
  * warlock directives
  */
@@ -619,14 +695,14 @@
 
 	NDBG0(("_init"));
 
-	status = ddi_soft_state_init(&mptsas_state, MPTSAS_SIZE,
+	status = ddi_soft_state_init(&mptsas3_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);
+		ddi_soft_state_fini(&mptsas3_state);
 		return (status);
 	}
 
@@ -638,7 +714,7 @@
 		mutex_destroy(&mptsas_log_mutex);
 		rw_destroy(&mptsas_global_rwlock);
 		mutex_destroy(&mptsas_global_mutex);
-		ddi_soft_state_fini(&mptsas_state);
+		ddi_soft_state_fini(&mptsas3_state);
 		scsi_hba_fini(&modlinkage);
 	}
 
@@ -659,7 +735,7 @@
 	NDBG0(("_fini"));
 
 	if ((status = mod_remove(&modlinkage)) == 0) {
-		ddi_soft_state_fini(&mptsas_state);
+		ddi_soft_state_fini(&mptsas3_state);
 		scsi_hba_fini(&modlinkage);
 		mutex_destroy(&mptsas_global_mutex);
 		rw_destroy(&mptsas_global_rwlock);
@@ -765,6 +841,7 @@
 
 	for (tp = refhash_first(mpt->m_targets); tp != NULL;
 	    tp = refhash_next(mpt->m_targets, tp)) {
+		mutex_destroy(&tp->m_t_mutex);
 		refhash_remove(mpt->m_targets, tp);
 	}
 	for (sp = refhash_first(mpt->m_smp_targets); sp != NULL;
@@ -799,7 +876,7 @@
 	uint64_t		attached_sas_wwn;
 	uint16_t		dev_hdl;
 	uint16_t		pdev_hdl;
-	uint16_t		bay_num, enclosure;
+	uint16_t		bay_num, enclosure, io_flags;
 	char			attached_wwnstr[MPTSAS_WWN_STRLEN];
 
 	/* CONSTCOND */
@@ -961,7 +1038,7 @@
 	    MPI2_SAS_DEVICE_PGAD_FORM_MASK) | (uint32_t)attached_devhdl;
 	rval = mptsas_get_sas_device_page0(mpt, page_address, &dev_hdl,
 	    &attached_sas_wwn, &dev_info, &phy_port, &phy_id,
-	    &pdev_hdl, &bay_num, &enclosure);
+	    &pdev_hdl, &bay_num, &enclosure, &io_flags);
 	if (rval != DDI_SUCCESS) {
 		mptsas_log(mpt, CE_WARN,
 		    "Failed to get device page0 for handle:%d",
@@ -1018,8 +1095,7 @@
 {
 	mptsas_t		*mpt = NULL;
 	int			instance, i, j;
-	int			doneq_thread_num;
-	char			intr_added = 0;
+	int			q_thread_num;
 	char			map_setup = 0;
 	char			config_setup = 0;
 	char			hba_attach_setup = 0;
@@ -1028,6 +1104,8 @@
 	char			event_taskq_create = 0;
 	char			dr_taskq_create = 0;
 	char			doneq_thread_create = 0;
+	char			txwq_thread_create = 0;
+	char			added_watchdog = 0;
 	scsi_hba_tran_t		*hba_tran;
 	uint_t			mem_bar = MEM_SPACE;
 	int			rval = DDI_FAILURE;
@@ -1142,13 +1220,13 @@
 	/*
 	 * Allocate softc information.
 	 */
-	if (ddi_soft_state_zalloc(mptsas_state, instance) != DDI_SUCCESS) {
+	if (ddi_soft_state_zalloc(mptsas3_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);
+	mpt = ddi_get_soft_state(mptsas3_state, instance);
 
 	if (mpt == NULL) {
 		mptsas_log(NULL, CE_WARN,
@@ -1164,11 +1242,20 @@
 
 	/* Make a per-instance copy of the structures */
 	mpt->m_io_dma_attr = mptsas_dma_attrs64;
-	mpt->m_msg_dma_attr = mptsas_dma_attrs;
+	if (mptsas_use_64bit_msgaddr) {
+		mpt->m_msg_dma_attr = mptsas_dma_attrs64;
+	} else {
+		mpt->m_msg_dma_attr = mptsas_dma_attrs;
+	}
 	mpt->m_reg_acc_attr = mptsas_dev_attr;
 	mpt->m_dev_acc_attr = mptsas_dev_attr;
 
 	/*
+	 * Round down the arq sense buffer size to nearest 16 bytes.
+	 */
+	mpt->m_req_sense_size = EXTCMDS_STATUS_SIZE;
+
+	/*
 	 * Initialize FMA
 	 */
 	mpt->m_fm_capabilities = ddi_getprop(DDI_DEV_T_ANY, mpt->m_dip,
@@ -1222,18 +1309,63 @@
 	}
 	dr_taskq_create++;
 
+	cv_init(&mpt->m_qthread_cv, NULL, CV_DRIVER, NULL);
+	mutex_init(&mpt->m_qthread_mutex, NULL, MUTEX_DRIVER, NULL);
+
+	i = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
+	    0, "mptsas_enable_txwq_prop", NCPUS > 1);
+	if (i) {
+		mpt->m_txwq_thread_n = NUM_TX_WAITQ;
+		mpt->m_txwq_enabled = FALSE;
+		if (ddi_prop_get_int(DDI_DEV_T_ANY, dip,
+		    0, "mptsas_allow_txwq_jumping", 0)) {
+			mpt->m_txwq_allow_q_jumping = TRUE;
+		}
+		i = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
+		    0, "mptsas_txwq_threashold_prop", 80000);
+		mpt->m_txwq_thread_threshold = (uint16_t)i;
+	} else {
+		mpt->m_txwq_thread_n = 0;
+		mpt->m_txwq_enabled = FALSE;
+	}
+
+	if (mpt->m_txwq_thread_n) {
+		mutex_enter(&mpt->m_qthread_mutex);
+		for (j = 0; j < NUM_TX_WAITQ; j++) {
+			mutex_init(&mpt->m_tx_waitq[j].txwq_mutex, NULL,
+			    MUTEX_DRIVER,
+			    NULL);
+			cv_init(&mpt->m_tx_waitq[j].txwq_cv, NULL, CV_DRIVER,
+			    NULL);
+			cv_init(&mpt->m_tx_waitq[j].txwq_drain_cv, NULL,
+			    CV_DRIVER, NULL);
+			mpt->m_tx_waitq[j].txwq_active = TRUE;
+			mpt->m_tx_waitq[j].txwq_draining = FALSE;
+			mpt->m_tx_waitq[j].txwq_cmdq = NULL;
+			mpt->m_tx_waitq[j].txwq_qtail =
+			    &mpt->m_tx_waitq[j].txwq_cmdq;
+			mutex_enter(&mpt->m_tx_waitq[j].txwq_mutex);
+			mpt->m_tx_waitq[j].arg.mpt = mpt;
+			mpt->m_tx_waitq[j].arg.t = j;
+			mpt->m_tx_waitq[j].txwq_threadp =
+			    thread_create(NULL, 0, mptsas_tx_waitq_thread,
+			    &mpt->m_tx_waitq[j].arg,
+			    0, &p0, TS_RUN, maxclsyspri - 10);
+			mutex_exit(&mpt->m_tx_waitq[j].txwq_mutex);
+		}
+		mutex_exit(&mpt->m_qthread_mutex);
+		txwq_thread_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);
+	    0, "mptsas_doneq_thread_n_prop", min(NCPUS, 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);
+		mutex_enter(&mpt->m_qthread_mutex);
 		mpt->m_doneq_thread_id =
 		    kmem_zalloc(sizeof (mptsas_doneq_thread_list_t)
 		    * mpt->m_doneq_thread_n, KM_SLEEP);
@@ -1251,25 +1383,34 @@
 			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;
+			    0, &p0, TS_RUN, maxclsyspri - 10);
+			mpt->m_doneq_thread_id[j].dlist.dl_tail =
+			    &mpt->m_doneq_thread_id[j].dlist.dl_q;
 			mutex_exit(&mpt->m_doneq_thread_id[j].mutex);
 		}
-		mutex_exit(&mpt->m_doneq_mutex);
+		mutex_exit(&mpt->m_qthread_mutex);
 		doneq_thread_create++;
 	}
 
-	/* Initialize mutex used in interrupt handler */
-	mutex_init(&mpt->m_mutex, NULL, MUTEX_DRIVER,
-	    DDI_INTR_PRI(mpt->m_intr_pri));
+	/*
+	 * Disable hardware interrupt since we're not ready to
+	 * handle it yet.
+	 */
+	MPTSAS_DISABLE_INTR(mpt);
+
+	/*
+	 * Initialize mutex used in interrupt handler.
+	 * We don't support hi-level so the mutex's are all adaptive
+	 * and we don't want to register the interrupts until we get
+	 * the chip type information from _init_chip() below.
+	 * Otherwise we would use DDI_INTR_PRI(mpt->m_intr_pri)
+	 * rather than NULL in the mutex_init() calls.
+	 */
+	mutex_init(&mpt->m_mutex, NULL, MUTEX_DRIVER, NULL);
 	mutex_init(&mpt->m_passthru_mutex, NULL, MUTEX_DRIVER, NULL);
-	mutex_init(&mpt->m_tx_waitq_mutex, NULL, MUTEX_DRIVER,
-	    DDI_INTR_PRI(mpt->m_intr_pri));
 	for (i = 0; i < MPTSAS_MAX_PHYS; i++) {
 		mutex_init(&mpt->m_phy_info[i].smhba_info.phy_mutex,
-		    NULL, MUTEX_DRIVER,
-		    DDI_INTR_PRI(mpt->m_intr_pri));
+		    NULL, MUTEX_DRIVER, NULL);
 	}
 
 	cv_init(&mpt->m_cv, NULL, CV_DRIVER, NULL);
@@ -1279,15 +1420,6 @@
 	cv_init(&mpt->m_fw_diag_cv, NULL, CV_DRIVER, NULL);
 	mutex_init_done++;
 
-	/*
-	 * Disable hardware interrupt since we're not ready to
-	 * handle it yet.
-	 */
-	MPTSAS_DISABLE_INTR(mpt);
-	if (mptsas_register_intrs(mpt) == FALSE)
-		goto fail;
-	intr_added++;
-
 	mutex_enter(&mpt->m_mutex);
 	/*
 	 * Initialize power management component
@@ -1332,6 +1464,19 @@
 		goto fail;
 	}
 
+	/*
+	 * If we only have one interrupt the default for doneq_thread_threshold
+	 * should be 0 so that all completion processing goes to the threads.
+	 * Only change it if it wasn't set from .conf file.
+	 */
+	if (mpt->m_doneq_thread_n != 0 &&
+	    ddi_prop_exists(DDI_DEV_T_ANY, dip,
+	    0, "mptsas_doneq_length_threshold_prop") == 0 &&
+	    mpt->m_intr_cnt == 1) {
+		mpt->m_doneq_length_threshold = 0;
+	}
+
+
 	mutex_exit(&mpt->m_mutex);
 
 	/*
@@ -1365,10 +1510,8 @@
 	/*
 	 * Initialize the wait and done FIFO queue
 	 */
-	mpt->m_donetail = &mpt->m_doneq;
+	mpt->m_dlist.dl_tail = &mpt->m_dlist.dl_q;
 	mpt->m_waitqtail = &mpt->m_waitq;
-	mpt->m_tx_waitqtail = &mpt->m_tx_waitq;
-	mpt->m_tx_draining = 0;
 
 	/*
 	 * ioc cmd queue initialize
@@ -1389,7 +1532,28 @@
 	mutex_exit(&mpt->m_mutex);
 
 	/*
-	 * Initialize PHY info for smhba
+	 * used for mptsas_watch
+	 */
+	mptsas_list_add(mpt);
+
+	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);
+	added_watchdog++;
+
+	/*
+	 * Initialize PHY info for smhba.
+	 * This requires watchdog to be enabled otherwise if interrupts
+	 * don't work the system will hang.
 	 */
 	if (mptsas_smhba_setup(mpt)) {
 		mptsas_log(mpt, CE_WARN, "mptsas phy initialization "
@@ -1400,6 +1564,8 @@
 	/* 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_req_sense_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)
@@ -1415,6 +1581,8 @@
 	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_req_sense_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)
@@ -1431,23 +1599,6 @@
 	/*
 	 * After this point, we are not going to fail the attach.
 	 */
-	/*
-	 * used for mptsas_watch
-	 */
-	mptsas_list_add(mpt);
-
-	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);
@@ -1464,18 +1615,22 @@
 	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);
+		/* deallocate in reverse order */
+		if (added_watchdog) {
+			mptsas_list_del(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;
+			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);
-			(void) untimeout(tid);
-			mutex_enter(&mptsas_global_mutex);
 		}
-		mutex_exit(&mptsas_global_mutex);
-		/* deallocate in reverse order */
+
 		mptsas_cache_destroy(mpt);
 
 		if (smp_attach_setup) {
@@ -1493,14 +1648,14 @@
 		if (mpt->m_active) {
 			mptsas_free_active_slots(mpt);
 		}
-		if (intr_added) {
+		if (mpt->m_intr_cnt) {
 			mptsas_unregister_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_qthread_mutex);
+			q_thread_num = mpt->m_doneq_thread_n;
+			for (j = 0; j < q_thread_num; j++) {
 				mutex_enter(&mpt->m_doneq_thread_id[j].mutex);
 				mpt->m_doneq_thread_id[j].flag &=
 				    (~MPTSAS_DONEQ_THREAD_ACTIVE);
@@ -1508,19 +1663,36 @@
 				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);
+				cv_wait(&mpt->m_qthread_cv,
+				    &mpt->m_qthread_mutex);
 			}
-			for (j = 0; j < doneq_thread_num; j++) {
+			for (j = 0; j < q_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);
+			    * q_thread_num);
+			mutex_exit(&mpt->m_qthread_mutex);
+		}
+		if (txwq_thread_create) {
+			mutex_enter(&mpt->m_qthread_mutex);
+			q_thread_num = mpt->m_txwq_thread_n;
+			for (j = 0; j < q_thread_num; j++) {
+				mutex_enter(&mpt->m_tx_waitq[j].txwq_mutex);
+				mpt->m_tx_waitq[j].txwq_active = FALSE;
+				cv_signal(&mpt->m_tx_waitq[j].txwq_cv);
+				mutex_exit(&mpt->m_tx_waitq[j].txwq_mutex);
+			}
+			while (mpt->m_txwq_thread_n) {
+				cv_wait(&mpt->m_qthread_cv,
+				    &mpt->m_qthread_mutex);
+			}
+			for (j = 0; j < q_thread_num; j++) {
+				cv_destroy(&mpt->m_tx_waitq[j].txwq_cv);
+				cv_destroy(&mpt->m_tx_waitq[j].txwq_drain_cv);
+				mutex_destroy(&mpt->m_tx_waitq[j].txwq_mutex);
+			}
 		}
 		if (event_taskq_create) {
 			ddi_taskq_destroy(mpt->m_event_taskq);
@@ -1529,13 +1701,14 @@
 			ddi_taskq_destroy(mpt->m_dr_taskq);
 		}
 		if (mutex_init_done) {
-			mutex_destroy(&mpt->m_tx_waitq_mutex);
+			mutex_destroy(&mpt->m_qthread_mutex);
 			mutex_destroy(&mpt->m_passthru_mutex);
 			mutex_destroy(&mpt->m_mutex);
 			for (i = 0; i < MPTSAS_MAX_PHYS; i++) {
 				mutex_destroy(
 				    &mpt->m_phy_info[i].smhba_info.phy_mutex);
 			}
+			cv_destroy(&mpt->m_qthread_cv);
 			cv_destroy(&mpt->m_cv);
 			cv_destroy(&mpt->m_passthru_cv);
 			cv_destroy(&mpt->m_fw_cv);
@@ -1553,7 +1726,7 @@
 		mptsas_hba_fini(mpt);
 
 		mptsas_fm_fini(mpt);
-		ddi_soft_state_free(mptsas_state, instance);
+		ddi_soft_state_free(mptsas3_state, instance);
 		ddi_prop_remove_all(dip);
 	}
 	return (DDI_FAILURE);
@@ -1767,7 +1940,7 @@
 	int		circ1 = 0;
 	mdi_pathinfo_t	*pip = NULL;
 	int		i;
-	int		doneq_thread_num = 0;
+	int		q_thread_num = 0;
 
 	NDBG0(("mptsas_do_detach: dip=0x%p", (void *)dip));
 
@@ -1815,7 +1988,7 @@
 			if (pm_raise_power(dip, 0, PM_LEVEL_D0) !=
 			    DDI_SUCCESS) {
 				mptsas_log(mpt, CE_WARN,
-				    "mptsas%d: Raise power request failed.",
+				    "mptsas3%d: Raise power request failed.",
 				    mpt->m_instance);
 				(void) pm_idle_component(dip, 0);
 				return (DDI_FAILURE);
@@ -1839,8 +2012,8 @@
 	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;
+		mutex_enter(&mpt->m_qthread_mutex);
+		q_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 &=
@@ -1849,19 +2022,36 @@
 			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);
+			cv_wait(&mpt->m_qthread_cv,
+			    &mpt->m_qthread_mutex);
 		}
-		for (i = 0;  i < doneq_thread_num; i++) {
+		for (i = 0;  i < q_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);
+		    * q_thread_num);
+		mutex_exit(&mpt->m_qthread_mutex);
+	}
+	if (mpt->m_txwq_thread_n) {
+		mutex_enter(&mpt->m_qthread_mutex);
+		q_thread_num = mpt->m_txwq_thread_n;
+		for (i = 0; i < q_thread_num; i++) {
+			mutex_enter(&mpt->m_tx_waitq[i].txwq_mutex);
+			mpt->m_tx_waitq[i].txwq_active = FALSE;
+			cv_signal(&mpt->m_tx_waitq[i].txwq_cv);
+			mutex_exit(&mpt->m_tx_waitq[i].txwq_mutex);
+		}
+		while (mpt->m_txwq_thread_n) {
+			cv_wait(&mpt->m_qthread_cv,
+			    &mpt->m_qthread_mutex);
+		}
+		for (i = 0; i < q_thread_num; i++) {
+			cv_destroy(&mpt->m_tx_waitq[i].txwq_cv);
+			cv_destroy(&mpt->m_tx_waitq[i].txwq_drain_cv);
+			mutex_destroy(&mpt->m_tx_waitq[i].txwq_mutex);
+		}
 	}
 
 	scsi_hba_reset_notify_tear_down(mpt->m_reset_notify_listf);
@@ -1942,17 +2132,18 @@
 	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 "
+			    "!mptsas3%d: Lower power request failed "
 			    "during detach, ignoring.",
 			    mpt->m_instance);
 	}
 
-	mutex_destroy(&mpt->m_tx_waitq_mutex);
+	mutex_destroy(&mpt->m_qthread_mutex);
 	mutex_destroy(&mpt->m_passthru_mutex);
 	mutex_destroy(&mpt->m_mutex);
 	for (i = 0; i < MPTSAS_MAX_PHYS; i++) {
 		mutex_destroy(&mpt->m_phy_info[i].smhba_info.phy_mutex);
 	}
+	cv_destroy(&mpt->m_qthread_cv);
 	cv_destroy(&mpt->m_cv);
 	cv_destroy(&mpt->m_passthru_cv);
 	cv_destroy(&mpt->m_fw_cv);
@@ -1968,7 +2159,7 @@
 	mptsas_free_handshake_msg(mpt);
 
 	mptsas_fm_fini(mpt);
-	ddi_soft_state_free(mptsas_state, ddi_get_instance(dip));
+	ddi_soft_state_free(mptsas3_state, ddi_get_instance(dip));
 	ddi_prop_remove_all(dip);
 
 	return (DDI_SUCCESS);
@@ -2021,6 +2212,7 @@
 {
 	ddi_dma_attr_t	task_dma_attrs;
 
+	mpt->m_hshk_dma_size = 0;
 	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);
@@ -2039,6 +2231,8 @@
 static void
 mptsas_free_handshake_msg(mptsas_t *mpt)
 {
+	if (mpt->m_hshk_dma_size == 0)
+		return;
 	mptsas_dma_addr_destroy(&mpt->m_hshk_dma_hdl, &mpt->m_hshk_acc_hdl);
 	mpt->m_hshk_dma_size = 0;
 }
@@ -2216,9 +2410,9 @@
 	/*
 	 * create kmem cache for packets
 	 */
-	(void) sprintf(buf, "mptsas%d_cache", instance);
+	(void) sprintf(buf, "mptsas3%d_cache", instance);
 	mpt->m_kmem_cache = kmem_cache_create(buf,
-	    sizeof (struct mptsas_cmd) + scsi_pkt_size(), 8,
+	    sizeof (struct mptsas_cmd) + scsi_pkt_size(), 16,
 	    mptsas_kmem_cache_constructor, mptsas_kmem_cache_destructor,
 	    NULL, (void *)mpt, NULL, 0);
 
@@ -2231,9 +2425,9 @@
 	 * create kmem cache for extra SGL frames if SGL cannot
 	 * be accomodated into main request frame.
 	 */
-	(void) sprintf(buf, "mptsas%d_cache_frames", instance);
+	(void) sprintf(buf, "mptsas3%d_cache_frames", instance);
 	mpt->m_cache_frames = kmem_cache_create(buf,
-	    sizeof (mptsas_cache_frames_t), 8,
+	    sizeof (mptsas_cache_frames_t), 16,
 	    mptsas_cache_frames_constructor, mptsas_cache_frames_destructor,
 	    NULL, (void *)mpt, NULL, 0);
 
@@ -2273,7 +2467,7 @@
 	if (scsi_hba_iport_unit_address(dip) != 0)
 		return (DDI_SUCCESS);
 
-	mpt = ddi_get_soft_state(mptsas_state, ddi_get_instance(dip));
+	mpt = ddi_get_soft_state(mptsas3_state, ddi_get_instance(dip));
 	if (mpt == NULL) {
 		return (DDI_FAILURE);
 	}
@@ -2289,7 +2483,7 @@
 	}
 	switch (level) {
 	case PM_LEVEL_D0:
-		NDBG11(("mptsas%d: turning power ON.", mpt->m_instance));
+		NDBG11(("mptsas3%d: turning power ON.", mpt->m_instance));
 		MPTSAS_POWER_ON(mpt);
 		/*
 		 * Wait up to 30 seconds for IOC to come out of reset.
@@ -2318,11 +2512,11 @@
 		mpt->m_power_level = PM_LEVEL_D0;
 		break;
 	case PM_LEVEL_D3:
-		NDBG11(("mptsas%d: turning power OFF.", mpt->m_instance));
+		NDBG11(("mptsas3%d: turning power OFF.", mpt->m_instance));
 		MPTSAS_POWER_OFF(mpt);
 		break;
 	default:
-		mptsas_log(mpt, CE_WARN, "mptsas%d: unknown power level <%x>.",
+		mptsas_log(mpt, CE_WARN, "mptsas3%d: unknown power level <%x>.",
 		    mpt->m_instance, level);
 		rval = DDI_FAILURE;
 		break;
@@ -2500,8 +2694,11 @@
 	/*
 	 * re-alloc when it has already alloced
 	 */
-	mptsas_dma_addr_destroy(&mpt->m_dma_req_frame_hdl,
-	    &mpt->m_acc_req_frame_hdl);
+	if (mpt->m_dma_flags & MPTSAS_REQ_FRAME) {
+		mptsas_dma_addr_destroy(&mpt->m_dma_req_frame_hdl,
+		    &mpt->m_acc_req_frame_hdl);
+		mpt->m_dma_flags &= ~MPTSAS_REQ_FRAME;
+	}
 
 	/*
 	 * The size of the request frame pool is:
@@ -2539,6 +2736,81 @@
 	 */
 	bzero(mpt->m_req_frame, mem_size);
 
+	mpt->m_dma_flags |= MPTSAS_REQ_FRAME;
+	return (DDI_SUCCESS);
+}
+
+static int
+mptsas_alloc_sense_bufs(mptsas_t *mpt)
+{
+	ddi_dma_attr_t		sense_dma_attrs;
+	caddr_t			memp;
+	ddi_dma_cookie_t	cookie;
+	size_t			mem_size;
+	int			num_extrqsense_bufs;
+
+	/*
+	 * re-alloc when it has already alloced
+	 */
+	if (mpt->m_dma_flags & MPTSAS_REQ_SENSE) {
+		rmfreemap(mpt->m_erqsense_map);
+		mptsas_dma_addr_destroy(&mpt->m_dma_req_sense_hdl,
+		    &mpt->m_acc_req_sense_hdl);
+		mpt->m_dma_flags &= ~MPTSAS_REQ_SENSE;
+	}
+
+	/*
+	 * The size of the request sense pool is:
+	 *   (Number of Request Frames - 2 ) * Request Sense Size +
+	 *   extra memory for extended sense requests.
+	 */
+	mem_size = ((mpt->m_max_requests - 2) * mpt->m_req_sense_size) +
+	    mptsas_extreq_sense_bufsize;
+
+	/*
+	 * set the DMA attributes.  ARQ buffers
+	 * aligned on a 16-byte boundry.
+	 */
+	sense_dma_attrs = mpt->m_msg_dma_attr;
+	sense_dma_attrs.dma_attr_align = 16;
+	sense_dma_attrs.dma_attr_sgllen = 1;
+
+	/*
+	 * allocate the request sense buffer pool.
+	 */
+	if (mptsas_dma_addr_create(mpt, sense_dma_attrs,
+	    &mpt->m_dma_req_sense_hdl, &mpt->m_acc_req_sense_hdl, &memp,
+	    mem_size, &cookie) == FALSE) {
+		return (DDI_FAILURE);
+	}
+
+	/*
+	 * Store the request sense base memory address.  This chip uses this
+	 * address to dma the request sense data.  The second
+	 * address is the address mpt uses to access the data.
+	 * The third is the base for the extended rqsense buffers.
+	 */
+	mpt->m_req_sense_dma_addr = cookie.dmac_laddress;
+	mpt->m_req_sense = memp;
+	memp += (mpt->m_max_requests - 2) * mpt->m_req_sense_size;
+	mpt->m_extreq_sense = memp;
+
+	/*
+	 * The extra memory is divided up into multiples of the base
+	 * buffer size in order to allocate via rmalloc().
+	 * Note that the rmallocmap cannot start at zero!
+	 */
+	num_extrqsense_bufs = mptsas_extreq_sense_bufsize /
+	    mpt->m_req_sense_size;
+	mpt->m_erqsense_map = rmallocmap_wait(num_extrqsense_bufs);
+	rmfree(mpt->m_erqsense_map, num_extrqsense_bufs, 1);
+
+	/*
+	 * Clear the pool.
+	 */
+	bzero(mpt->m_req_sense, mem_size);
+
+	mpt->m_dma_flags |= MPTSAS_REQ_SENSE;
 	return (DDI_SUCCESS);
 }
 
@@ -2553,8 +2825,11 @@
 	/*
 	 * re-alloc when it has already alloced
 	 */
-	mptsas_dma_addr_destroy(&mpt->m_dma_reply_frame_hdl,
-	    &mpt->m_acc_reply_frame_hdl);
+	if (mpt->m_dma_flags & MPTSAS_REPLY_FRAME) {
+		mptsas_dma_addr_destroy(&mpt->m_dma_reply_frame_hdl,
+		    &mpt->m_acc_reply_frame_hdl);
+		mpt->m_dma_flags &= ~MPTSAS_REPLY_FRAME;
+	}
 
 	/*
 	 * The size of the reply frame pool is:
@@ -2591,6 +2866,7 @@
 	 */
 	bzero(mpt->m_reply_frame, mem_size);
 
+	mpt->m_dma_flags |= MPTSAS_REPLY_FRAME;
 	return (DDI_SUCCESS);
 }
 
@@ -2605,8 +2881,11 @@
 	/*
 	 * re-alloc when it has already alloced
 	 */
-	mptsas_dma_addr_destroy(&mpt->m_dma_free_queue_hdl,
-	    &mpt->m_acc_free_queue_hdl);
+	if (mpt->m_dma_flags & MPTSAS_FREE_QUEUE) {
+		mptsas_dma_addr_destroy(&mpt->m_dma_free_queue_hdl,
+		    &mpt->m_acc_free_queue_hdl);
+		mpt->m_dma_flags &= ~MPTSAS_FREE_QUEUE;
+	}
 
 	/*
 	 * The reply free queue size is:
@@ -2646,9 +2925,31 @@
 	 */
 	bzero(mpt->m_free_queue, mem_size);
 
+	mpt->m_dma_flags |= MPTSAS_FREE_QUEUE;
 	return (DDI_SUCCESS);
 }
 
+static void
+mptsas_free_post_queue(mptsas_t *mpt)
+{
+	mptsas_reply_pqueue_t	*rpqp;
+	int			i;
+
+	if (mpt->m_dma_flags & MPTSAS_POST_QUEUE) {
+		mptsas_dma_addr_destroy(&mpt->m_dma_post_queue_hdl,
+		    &mpt->m_acc_post_queue_hdl);
+		rpqp = mpt->m_rep_post_queues;
+		for (i = 0; i < mpt->m_post_reply_qcount; i++) {
+			mutex_destroy(&rpqp->rpq_mutex);
+			rpqp++;
+		}
+		kmem_free(mpt->m_rep_post_queues,
+		    sizeof (mptsas_reply_pqueue_t) *
+		    mpt->m_post_reply_qcount);
+		mpt->m_dma_flags &= ~MPTSAS_POST_QUEUE;
+	}
+}
+
 static int
 mptsas_alloc_post_queue(mptsas_t *mpt)
 {
@@ -2656,19 +2957,21 @@
 	caddr_t			memp;
 	ddi_dma_cookie_t	cookie;
 	size_t			mem_size;
+	mptsas_reply_pqueue_t	*rpqp;
+	int			i;
 
 	/*
 	 * re-alloc when it has already alloced
 	 */
-	mptsas_dma_addr_destroy(&mpt->m_dma_post_queue_hdl,
-	    &mpt->m_acc_post_queue_hdl);
+	mptsas_free_post_queue(mpt);
 
 	/*
 	 * 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;
+	mpt->m_post_reply_qcount = mpt->m_intr_cnt;
+	mem_size = mpt->m_post_queue_depth * 8 * mpt->m_post_reply_qcount;
 
 	/*
 	 * set the DMA attributes.  The Reply Descriptor Post Queue must be
@@ -2679,7 +2982,12 @@
 	frame_dma_attrs.dma_attr_sgllen = 1;
 
 	/*
-	 * allocate the reply post queue
+	 * Allocate the reply post queue(s).
+	 * MPI2.5 introduces a method to allocate multiple queues
+	 * using a redirect table. For now stick to one contiguous
+	 * chunck. This can get as big as 1Mbyte for 16 queues.
+	 * The spec gives no indication that the queue size can be
+	 * reduced if you have many of them.
 	 */
 	if (mptsas_dma_addr_create(mpt, frame_dma_attrs,
 	    &mpt->m_dma_post_queue_hdl, &mpt->m_acc_post_queue_hdl, &memp,
@@ -2695,11 +3003,24 @@
 	mpt->m_post_queue_dma_addr = cookie.dmac_laddress;
 	mpt->m_post_queue = memp;
 
+	mpt->m_rep_post_queues = kmem_zalloc(sizeof (mptsas_reply_pqueue_t) *
+	    mpt->m_post_reply_qcount, KM_SLEEP);
+	rpqp = mpt->m_rep_post_queues;
+	for (i = 0; i < mpt->m_post_reply_qcount; i++) {
+		rpqp->rpq_queue = memp;
+		mutex_init(&rpqp->rpq_mutex, NULL, MUTEX_DRIVER, NULL);
+		rpqp->rpq_dlist.dl_tail = &rpqp->rpq_dlist.dl_q;
+		rpqp->rpq_num = (uint8_t)i;
+		memp += (mpt->m_post_queue_depth * 8);
+		rpqp++;
+	}
+
 	/*
 	 * Clear the reply post queue memory.
 	 */
 	bzero(mpt->m_post_queue, mem_size);
 
+	mpt->m_dma_flags |= MPTSAS_POST_QUEUE;
 	return (DDI_SUCCESS);
 }
 
@@ -2709,6 +3030,9 @@
 	if (mpt->m_replyh_args == NULL) {
 		mpt->m_replyh_args = kmem_zalloc(sizeof (m_replyh_arg_t) *
 		    mpt->m_max_replies, KM_SLEEP);
+	} else {
+		bzero(mpt->m_replyh_args, sizeof (m_replyh_arg_t) *
+		    mpt->m_max_replies);
 	}
 }
 
@@ -2751,17 +3075,28 @@
 	/*
 	 * Free up any allocated memory
 	 */
-	mptsas_dma_addr_destroy(&mpt->m_dma_req_frame_hdl,
-	    &mpt->m_acc_req_frame_hdl);
+	if (mpt->m_dma_flags & MPTSAS_REQ_FRAME) {
+		mptsas_dma_addr_destroy(&mpt->m_dma_req_frame_hdl,
+		    &mpt->m_acc_req_frame_hdl);
+	}
+
+	if (mpt->m_dma_flags & MPTSAS_REQ_SENSE) {
+		rmfreemap(mpt->m_erqsense_map);
+		mptsas_dma_addr_destroy(&mpt->m_dma_req_sense_hdl,
+		    &mpt->m_acc_req_sense_hdl);
+	}
 
-	mptsas_dma_addr_destroy(&mpt->m_dma_reply_frame_hdl,
-	    &mpt->m_acc_reply_frame_hdl);
+	if (mpt->m_dma_flags & MPTSAS_REPLY_FRAME) {
+		mptsas_dma_addr_destroy(&mpt->m_dma_reply_frame_hdl,
+		    &mpt->m_acc_reply_frame_hdl);
+	}
 
-	mptsas_dma_addr_destroy(&mpt->m_dma_free_queue_hdl,
-	    &mpt->m_acc_free_queue_hdl);
+	if (mpt->m_dma_flags & MPTSAS_FREE_QUEUE) {
+		mptsas_dma_addr_destroy(&mpt->m_dma_free_queue_hdl,
+		    &mpt->m_acc_free_queue_hdl);
+	}
 
-	mptsas_dma_addr_destroy(&mpt->m_dma_post_queue_hdl,
-	    &mpt->m_acc_post_queue_hdl);
+	mptsas_free_post_queue(mpt);
 
 	if (mpt->m_replyh_args != NULL) {
 		kmem_free(mpt->m_replyh_args, sizeof (m_replyh_arg_t)
@@ -3040,8 +3375,10 @@
 #endif
 	mptsas_t	*mpt = PKT2MPT(pkt);
 	mptsas_cmd_t	*cmd = PKT2CMD(pkt);
-	int		rval;
+	int		rval, start;
+	uint8_t		pref;
 	mptsas_target_t	*ptgt = cmd->cmd_tgt_addr;
+	mptsas_tx_waitqueue_t *txwq;
 
 	NDBG1(("mptsas_scsi_start: pkt=0x%p", (void *)pkt));
 	ASSERT(ptgt);
@@ -3090,114 +3427,82 @@
 	 * 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.
+	 * per instance, per queue mutex m_tx_waitq[i].txwq_mutex is
+	 * introduced to protect the txwq_qtail, txwq_cmdq, txwq_len
 	 */
 
-	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_txwq_enabled == TRUE) {
+		int gotmtx = 0;
+
+		if (mpt->m_txwq_allow_q_jumping) {
+			gotmtx = mutex_tryenter(&mpt->m_mutex);
+		}
+		if (gotmtx == 0) {
+			/* We didn't get the mutex or didn't try */
+			if (cmd->cmd_pkt_flags & FLAG_NOINTR) {
+				mutex_enter(&mpt->m_mutex);
+				/* Polled commands queue jump */
+				mptsas_accept_tx_waitqs(mpt);
+			} else {
+				rval = mptsas_check_targ_intxtion(
+				    cmd->cmd_tgt_addr,
+				    cmd->cmd_pkt_flags);
+				if (rval != TRAN_ACCEPT) {
+					return (rval);
 				}
-			}
-			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);
+				pref = mpt->m_pref_tx_waitq;
+				txwq = &mpt->m_tx_waitq[pref];
+
+				if (mutex_tryenter(&txwq->txwq_mutex) == 0) {
+					txwq = &mpt->m_tx_waitq[pref^1];
+					mutex_enter(&txwq->txwq_mutex);
+				} else {
+					pref ^= 1;
+					mpt->m_pref_tx_waitq = pref;
+				}
+
+				*txwq->txwq_qtail = cmd;
+				txwq->txwq_qtail = &cmd->cmd_linkp;
+				txwq->txwq_len++;
+				if (!txwq->txwq_draining) {
+					cv_signal(&txwq->txwq_cv);
+				}
+				mutex_exit(&txwq->txwq_mutex);
+				return (rval);
 			}
 		}
 	} 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);
+	}
+	rval = mptsas_check_targ_intxtion(cmd->cmd_tgt_addr,
+	    cmd->cmd_pkt_flags);
+	if (rval != TRAN_ACCEPT) {
 		mutex_exit(&mpt->m_mutex);
+		return (rval);
+	}
+
+	start = mptsas_accept_pkt(mpt, cmd, &rval);
+	mutex_exit(&mpt->m_mutex);
+	if (start) {
+		(void) mptsas_start_cmd(mpt, cmd);
 	}
 
 	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)
+mptsas_check_targ_intxtion(mptsas_target_t *ptgt, int cmd_pkt_flags)
 {
-	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.
+	 * ptgt->m_dr_flag is a variable that is only ever changed by
+	 * direct write under the main m_mutex.
+	 * It doesn't need a mutex hold to protect this read.
 	 */
+
 	if (ptgt->m_dr_flag == MPTSAS_DR_INTRANSITION) {
-		if (cmd->cmd_pkt_flags & FLAG_NOQUEUE) {
+		if (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
@@ -3213,13 +3518,48 @@
 			return (TRAN_FATAL_ERROR);
 		}
 	}
-	rval = mptsas_accept_pkt(mpt, cmd);
+	return (TRAN_ACCEPT);
+}
 
-	return (rval);
+/*
+ * Note that this function has a side effect of releasing the
+ * per target mutex.
+ */
+static void
+mptsas_offline_target_direct(mptsas_t *mpt, mptsas_target_t *ptgt)
+{
+	char				phy_mask_name[MPTSAS_MAX_PHYS];
+	mptsas_phymask_t		phymask = ptgt->m_addr.mta_phymask;
+	dev_info_t			*parent;
+
+	ASSERT(mutex_owned(&mpt->m_mutex));
+
+	ptgt->m_dr_flag = MPTSAS_DR_INTRANSITION;
+	bzero(phy_mask_name, MPTSAS_MAX_PHYS);
+	(void) sprintf(phy_mask_name, "%x", phymask);
+	parent = scsi_hba_iport_find(mpt->m_dip, phy_mask_name);
+
+	if (parent != NULL) {
+		mptsas_offline_target(mpt, ptgt,
+		    ptgt->m_deviceinfo & DEVINFO_DIRECT_ATTACHED ?
+		    MPTSAS_TOPO_FLAG_DIRECT_ATTACHED_DEVICE :
+		    MPTSAS_TOPO_FLAG_EXPANDER_ATTACHED_DEVICE,
+		    parent);
+	} else {
+		mptsas_log(mpt, CE_WARN, "Failed to find an "
+		    "iport for \"%s\", should not happen!",
+		    phy_mask_name);
+	}
 }
 
+/*
+ * In order to be efficient with the m_mutex (which can be dropped before
+ * calling mptsas_start_cmd()) indicate if start_cmd should be called via the
+ * returned value (FALSE or TRUE). Caller is then responsible for doing the
+ * right thing with the m_mutex.
+ */
 static int
-mptsas_accept_pkt(mptsas_t *mpt, mptsas_cmd_t *cmd)
+mptsas_accept_pkt(mptsas_t *mpt, mptsas_cmd_t *cmd, int *tran_rval)
 {
 	int		rval = TRAN_ACCEPT;
 	mptsas_target_t	*ptgt = cmd->cmd_tgt_addr;
@@ -3232,20 +3572,26 @@
 		rval = mptsas_prepare_pkt(cmd);
 		if (rval != TRAN_ACCEPT) {
 			cmd->cmd_flags &= ~CFLAG_TRANFLAG;
-			return (rval);
+			goto set_tranrval;
 		}
 	}
 
 	/*
-	 * reset the throttle if we were draining
+	 * If the command came from the tx wait q it may have slipped
+	 * by the check for dr_flag before being added to the queue.
+	 * Fail here with abort status.
 	 */
-	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 (cmd->cmd_flags & CFLAG_TXQ) {
+		rval = mptsas_check_targ_intxtion(cmd->cmd_tgt_addr,
+		    cmd->cmd_pkt_flags);
+		if (rval != TRAN_ACCEPT) {
+			mptsas_set_pkt_reason(mpt, cmd, CMD_ABORTED,
+			    STAT_ABORTED);
+			mptsas_doneq_add(mpt, cmd);
+			mptsas_doneq_empty(mpt);
+			goto set_tranrval;
+		}
 	}
-
 	/*
 	 * If HBA is being reset, the DevHandles are being re-initialized,
 	 * which means that they could be invalid even if the target is still
@@ -3258,30 +3604,42 @@
 		if (cmd->cmd_flags & CFLAG_TXQ) {
 			mptsas_doneq_add(mpt, cmd);
 			mptsas_doneq_empty(mpt);
-			return (rval);
 		} else {
-			return (TRAN_BUSY);
+			rval = TRAN_BUSY;
 		}
+		goto set_tranrval;
+	}
+
+	mutex_enter(&ptgt->m_t_mutex);
+	/*
+	 * 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
+	 * fail the command. In theory, for a command from scsi_vhci
+	 * client it's impossible to receive a command with an invalid
 	 * devhdl since devhdl is set after path offline, target
-	 * driver is not suppose to select a offlined path.
+	 * driver is not supposed to select an offlined path.
 	 */
 	if (ptgt->m_devhdl == MPTSAS_INVALID_DEVHDL) {
-		NDBG20(("rejecting command, it might because invalid devhdl "
+		NDBG3(("rejecting command, it might because invalid devhdl "
 		    "request."));
+		mutex_exit(&ptgt->m_t_mutex);
 		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);
+			rval = TRAN_FATAL_ERROR;
 		}
+		goto set_tranrval;
 	}
 	/*
 	 * The first case is the normal case.  mpt gets a command from the
@@ -3292,15 +3650,22 @@
 	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_reset_delay == 0) && (mpt->m_polled_intr == 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);
+		ASSERT((cmd->cmd_flags & CFLAG_CMDIOC) == 0);
+		if (mptsas_save_cmd_to_slot(mpt, cmd) == TRUE) {
+			ptgt->m_t_ncmds++;
+			mutex_exit(&ptgt->m_t_mutex);
+			cmd->cmd_active_expiration = 0;
+			*tran_rval = rval;
+			return (TRUE);
 		} else {
+			mutex_exit(&ptgt->m_t_mutex);
 			mptsas_waitq_add(mpt, cmd);
 		}
 	} else {
+		mutex_exit(&ptgt->m_t_mutex);
 		/*
 		 * Add this pkt to the work queue
 		 */
@@ -3319,17 +3684,36 @@
 			}
 		}
 	}
-	return (rval);
+set_tranrval:
+	*tran_rval = rval;
+	return (FALSE);
 }
 
-int
-mptsas_save_cmd(mptsas_t *mpt, mptsas_cmd_t *cmd)
+static void
+mptsas_retry_pkt(mptsas_t *mpt, mptsas_cmd_t *cmd)
 {
-	mptsas_slots_t *slots = mpt->m_active;
-	uint_t slot, start_rotor;
-	mptsas_target_t *ptgt = cmd->cmd_tgt_addr;
+	int		rval;
 
-	ASSERT(MUTEX_HELD(&mpt->m_mutex));
+	cmd->cmd_pkt_flags |= FLAG_HEAD;
+	cmd->cmd_flags |= CFLAG_RETRY;
+	cmd->cmd_flags &= ~CFLAG_TXQ;
+	if (mptsas_accept_pkt(mpt, cmd, &rval)) {
+		(void) mptsas_start_cmd(mpt, cmd);
+	}
+
+	/*
+	 * If there was a problem clear the retry flag so that the
+	 * command will be completed with error rather than get lost!
+	 */
+	if (rval != TRAN_ACCEPT)
+		cmd->cmd_flags &= ~CFLAG_RETRY;
+}
+
+static int
+mptsas_save_cmd_to_slot(mptsas_t *mpt, mptsas_cmd_t *cmd)
+{
+	mptsas_slots_t *slots = mpt->m_active;
+	uint_t slot, start_rotor, rotor, n_normal;
 
 	/*
 	 * Account for reserved TM request slot and reserved SMID of 0.
@@ -3344,15 +3728,17 @@
 	 * the normal slot after the one we select, unless we select the last
 	 * normal slot in which case it returns to slot 1.
 	 */
-	start_rotor = slots->m_rotor;
+	start_rotor = rotor = slots->m_rotor;
+	n_normal = slots->m_n_normal;
 	do {
-		slot = slots->m_rotor++;
-		if (slots->m_rotor > slots->m_n_normal)
-			slots->m_rotor = 1;
+		slot = rotor++;
+		if (rotor > n_normal)
+			rotor = 1;
 
-		if (slots->m_rotor == start_rotor)
+		if (rotor == start_rotor)
 			break;
 	} while (slots->m_slot[slot] != NULL);
+	slots->m_rotor = rotor;
 
 	if (slots->m_slot[slot] != NULL)
 		return (FALSE);
@@ -3361,25 +3747,51 @@
 
 	cmd->cmd_slot = slot;
 	slots->m_slot[slot] = cmd;
-	mpt->m_ncmds++;
+	atomic_inc_32(&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)
+	 * Distribute the commands amongst the reply queues (Interrupt vectors).
+	 * Stick to 0 for polled.
 	 */
-	if ((cmd->cmd_flags & CFLAG_CMDIOC) == 0) {
-		ptgt->m_t_ncmds++;
+	if (!(cmd->cmd_pkt_flags & FLAG_NOINTR) &&
+	    !(cmd->cmd_flags & (CFLAG_PASSTHRU|CFLAG_CONFIG|CFLAG_FW_DIAG)) &&
+	    (mpt->m_post_reply_qcount > 1)) {
+		cmd->cmd_rpqidx = slot % mpt->m_post_reply_qcount;
+	}
+	atomic_inc_32(&mpt->m_rep_post_queues[cmd->cmd_rpqidx].rpq_ncmds);
+	return (TRUE);
+}
+
+int
+mptsas_save_cmd(mptsas_t *mpt, mptsas_cmd_t *cmd)
+{
+	mptsas_target_t *ptgt = cmd->cmd_tgt_addr;
+
+	ASSERT(MUTEX_HELD(&mpt->m_mutex));
+
+	if (!mptsas_save_cmd_to_slot(mpt, cmd)) {
+		return (FALSE);
 	}
-	cmd->cmd_active_timeout = cmd->cmd_pkt->pkt_time;
 
 	/*
-	 * If initial timout is less than or equal to one tick, bump
-	 * the timeout by a tick so that command doesn't timeout before
-	 * its allotted time.
+	 * only increment per target ncmds if this is not a
+	 * command that has no target associated with it (i.e. a
+	 * event acknoledgement)
 	 */
-	if (cmd->cmd_active_timeout <= mptsas_scsi_watchdog_tick) {
-		cmd->cmd_active_timeout += mptsas_scsi_watchdog_tick;
+	if ((cmd->cmd_flags & CFLAG_CMDIOC) == 0) {
+		/*
+		 * Expiration time is set in mptsas_start_cmd
+		 */
+		mutex_enter(&ptgt->m_t_mutex);
+		ptgt->m_t_ncmds++;
+		mutex_exit(&ptgt->m_t_mutex);
+		cmd->cmd_active_expiration = 0;
+	} else {
+		/*
+		 * Initialize expiration time for passthrough commands,
+		 */
+		cmd->cmd_active_expiration = gethrtime() +
+		    (hrtime_t)cmd->cmd_pkt->pkt_time * NANOSEC;
 	}
 	return (TRUE);
 }
@@ -3484,22 +3896,13 @@
 	 */
 	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));
@@ -3779,7 +4182,8 @@
 		 * 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));
+		NDBG3(("mptsas_scsi_init_pkt: cmd_dmacount=%d.",
+		    cmd->cmd_dmacount));
 	}
 	return (pkt);
 }
@@ -3832,19 +4236,12 @@
 {
 	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
 	 */
@@ -3853,41 +4250,6 @@
 		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);
 }
 
@@ -3901,15 +4263,6 @@
 
 	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;
@@ -3967,7 +4320,7 @@
 	 * 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;
+	p->m_phys_addr = cookie.dmac_laddress;
 
 	return (DDI_SUCCESS);
 }
@@ -4002,12 +4355,7 @@
     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",
@@ -4042,38 +4390,20 @@
 
 		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;
+		if (senselength > mpt->m_req_sense_size) {
+			unsigned long i;
+			cmd->cmd_extrqslen = (uint16_t)senselength;
+			cmd->cmd_extrqschunks = (senselength +
+			    (mpt->m_req_sense_size - 1))/mpt->m_req_sense_size;
+			i = rmalloc_wait(mpt->m_erqsense_map,
+			    cmd->cmd_extrqschunks);
+			ASSERT(i != 0);
+			cmd->cmd_extrqsidx = i - 1;
+			cmd->cmd_arq_buf = mpt->m_extreq_sense +
+			    (cmd->cmd_extrqsidx * mpt->m_req_sense_size);
+		} else {
+			cmd->cmd_rqslen = (uchar_t)senselength;
 		}
-		cmd->cmd_flags |= CFLAG_EXTARQBUFVALID;
 	}
 	return (0);
 fail:
@@ -4095,20 +4425,15 @@
 		_NOTE(NOT_REACHED)
 		/* NOTREACHED */
 	}
+	if (cmd->cmd_extrqslen != 0) {
+		rmfree(mpt->m_erqsense_map, cmd->cmd_extrqschunks,
+		    cmd->cmd_extrqsidx + 1);
+	}
 	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);
@@ -4154,11 +4479,6 @@
 		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);
 }
 
@@ -4174,167 +4494,324 @@
 }
 
 static void
-mptsas_sge_setup(mptsas_t *mpt, mptsas_cmd_t *cmd, uint32_t *control,
-	pMpi2SCSIIORequest_t frame, ddi_acc_handle_t acc_hdl)
+mptsas_sge_mainframe(mptsas_cmd_t *cmd, pMpi2SCSIIORequest_t frame,
+		ddi_acc_handle_t acc_hdl, uint_t cookiec,
+		uint32_t end_flags)
 {
-	uint_t			cookiec;
+	pMpi2SGESimple64_t	sge;
 	mptti_t			*dmap;
 	uint32_t		flags;
+
+	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 |= end_flags;
+		}
+		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++;
+	}
+}
+
+static void
+mptsas_sge_chain(mptsas_t *mpt, mptsas_cmd_t *cmd,
+    pMpi2SCSIIORequest_t frame, ddi_acc_handle_t acc_hdl)
+{
 	pMpi2SGESimple64_t	sge;
 	pMpi2SGEChain64_t	sgechain;
-	ASSERT(cmd->cmd_flags & CFLAG_DMAVALID);
+	uint64_t		nframe_phys_addr;
+	uint_t			cookiec;
+	mptti_t			*dmap;
+	uint32_t		flags;
+	int			i, j, k, l, frames, sgemax;
+	int			temp, maxframe_sges;
+	uint8_t			chainflags;
+	uint16_t		chainlength;
+	mptsas_cache_frames_t	*p;
+
+	cookiec = cmd->cmd_cookiec;
 
 	/*
-	 * Save the number of entries in the DMA
-	 * Scatter/Gather list
+	 * 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.
 	 */
-	cookiec = cmd->cmd_cookiec;
 
-	NDBG1(("mptsas_sge_setup: cookiec=%d", cookiec));
+	/*
+	 * 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);
+	maxframe_sges = MPTSAS_MAX_FRAME_SGES64(mpt);
+	temp = (cookiec - (maxframe_sges - 1)) / sgemax;
 
 	/*
-	 * Set read/write bit in control.
+	 * A little check to see if we need to round up the number
+	 * of frames we need
 	 */
-	if (cmd->cmd_flags & CFLAG_DMASEND) {
-		*control |= MPI2_SCSIIO_CONTROL_WRITE;
+	if ((cookiec - (maxframe_sges - 1)) - (temp * sgemax) > 1) {
+		frames = (temp + 1);
 	} else {
-		*control |= MPI2_SCSIIO_CONTROL_READ;
+		frames = temp;
 	}
+	dmap = cmd->cmd_sg;
+	sge = (pMpi2SGESimple64_t)(&frame->SGL);
 
-	ddi_put32(acc_hdl, &frame->DataLength, cmd->cmd_dmacount);
+	/*
+	 * First fill in the main frame
+	 */
+	j = maxframe_sges - 1;
+	mptsas_sge_mainframe(cmd, frame, acc_hdl, j,
+	    ((uint32_t)(MPI2_SGE_FLAGS_LAST_ELEMENT) <<
+	    MPI2_SGE_FLAGS_SHIFT));
+	dmap += j;
+	sge += j;
+	j++;
+
+	/*
+	 * 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&0xffffffffull));
+	ddi_put32(acc_hdl, &sgechain->Address.High, p->m_phys_addr>>32);
 
 	/*
-	 * 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 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 (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 (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 this is the last cookie, we set the flags
-			 * to indicate so
+			 * 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 (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);
+			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.
+				 */
+				nframe_phys_addr = p->m_phys_addr +
+				    (mpt->m_req_frame_size * k);
+				ddi_put32(p->m_acc_hdl,
+				    &sgechain->Address.Low,
+				    nframe_phys_addr&0xffffffffull);
+				ddi_put32(p->m_acc_hdl,
+				    &sgechain->Address.High,
+				    nframe_phys_addr>>32);
+
+				/*
+				 * 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(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,
+			ddi_put32(p->m_acc_hdl,
+			    &sge->Address.Low,
 			    dmap->addr.address64.Low);
-			ddi_put32(acc_hdl, &sge->Address.High,
+			ddi_put32(p->m_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 |
+			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 this is the last SGE of this frame
-			 * we set the end of list flag
+			 * 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 (j == (MPTSAS_MAX_FRAME_SGES64(mpt) - 1)) {
+			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 <<
@@ -4344,222 +4821,384 @@
 				    (MPI2_SGE_FLAGS_IOC_TO_HOST <<
 				    MPI2_SGE_FLAGS_SHIFT);
 			}
-			ddi_put32(acc_hdl, &sge->FlagsLength, flags);
+			ddi_put32(p->m_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);
+	/*
+	 * Sync DMA with the chain buffers that were just created
+	 */
+	(void) ddi_dma_sync(p->m_dma_hdl, 0, 0, DDI_DMA_SYNC_FORDEV);
+}
 
-		/*
-		 * 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));
-		}
+static void
+mptsas_ieee_sge_mainframe(mptsas_cmd_t *cmd, pMpi2SCSIIORequest_t frame,
+    ddi_acc_handle_t acc_hdl, uint_t cookiec,
+    uint8_t end_flag)
+{
+	pMpi2IeeeSgeSimple64_t	ieeesge;
+	mptti_t			*dmap;
+	uint8_t			flags;
+
+	dmap = cmd->cmd_sg;
 
-		p = cmd->cmd_extra_frames;
+	NDBG1(("mptsas_ieee_sge_mainframe: cookiec=%d, %s", cookiec,
+	    cmd->cmd_flags & CFLAG_DMASEND?"Out":"In"));
 
-		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);
+	ieeesge = (pMpi2IeeeSgeSimple64_t)(&frame->SGL);
+	while (cookiec--) {
+		ddi_put32(acc_hdl, &ieeesge->Address.Low,
+		    dmap->addr.address64.Low);
+		ddi_put32(acc_hdl, &ieeesge->Address.High,
+		    dmap->addr.address64.High);
+		ddi_put32(acc_hdl, &ieeesge->Length, dmap->count);
+		NDBG1(("mptsas_ieee_sge_mainframe: len=%d, high=0x%x",
+		    dmap->count, dmap->addr.address64.High));
+		flags = (MPI2_IEEE_SGE_FLAGS_SIMPLE_ELEMENT |
+		    MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR);
 
 		/*
-		 * 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 this is the last cookie, we set the flags
+		 * to indicate so
 		 */
-		if (frames >= 2) {
-			ddi_put8(acc_hdl, &sgechain->NextChainOffset,
-			    (sgemax * sizeof (MPI2_SGE_SIMPLE64)) >> 2);
-		} else {
-			ddi_put8(acc_hdl, &sgechain->NextChainOffset, 0);
+		if (cookiec == 0) {
+			flags |= end_flag;
 		}
 
 		/*
-		 * Jump to next frame;
-		 * Starting here, chain buffers go into the per command SGL.
-		 * This buffer is allocated when chain buffers are needed.
+		 * XXX: Hmmm, what about the direction based on
+		 * cmd->cmd_flags & CFLAG_DMASEND?
 		 */
-		sge = (pMpi2SGESimple64_t)p->m_frames_addr;
-		i = cookiec;
+		ddi_put8(acc_hdl, &ieeesge->Flags, flags);
+		dmap++;
+		ieeesge++;
+	}
+}
 
-		/*
-		 * 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++) {
+static void
+mptsas_ieee_sge_chain(mptsas_t *mpt, mptsas_cmd_t *cmd,
+    pMpi2SCSIIORequest_t frame, ddi_acc_handle_t acc_hdl)
+{
+	pMpi2IeeeSgeSimple64_t	ieeesge;
+	pMpi25IeeeSgeChain64_t	ieeesgechain;
+	uint64_t		nframe_phys_addr;
+	uint_t			cookiec;
+	mptti_t			*dmap;
+	uint8_t			flags;
+	int			i, j, k, l, frames, sgemax;
+	int			temp, maxframe_sges;
+	uint8_t			chainflags;
+	uint32_t		chainlength;
+	mptsas_cache_frames_t	*p;
 
-				/*
-				 * 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);
+	cookiec = cmd->cmd_cookiec;
 
-					/*
-					 * 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));
-					}
+	NDBG1(("mptsas_ieee_sge_chain: cookiec=%d", cookiec));
 
-					/* Jump to the next frame */
-					sge = (pMpi2SGESimple64_t)
-					    ((char *)p->m_frames_addr +
-					    (int)mpt->m_req_frame_size * k);
+	/*
+	 * 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
+	 *    4 double-words (16 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 4 double-words (16 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.
+	 */
 
-					continue;
-				}
+	/*
+	 * 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_IEEE_SGE_SIMPLE64))
+	    - 1);
+	maxframe_sges = MPTSAS_MAX_FRAME_SGES64(mpt);
+	temp = (cookiec - (maxframe_sges - 1)) / sgemax;
 
-				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);
+	/*
+	 * A little check to see if we need to round up the number
+	 * of frames we need
+	 */
+	if ((cookiec - (maxframe_sges - 1)) - (temp * sgemax) > 1) {
+		frames = (temp + 1);
+	} else {
+		frames = temp;
+	}
+	NDBG1(("mptsas_ieee_sge_chain: temp=%d, frames=%d", temp, frames));
+	dmap = cmd->cmd_sg;
+	ieeesge = (pMpi2IeeeSgeSimple64_t)(&frame->SGL);
+
+	/*
+	 * First fill in the main frame
+	 */
+	j = maxframe_sges - 1;
+	mptsas_ieee_sge_mainframe(cmd, frame, acc_hdl, j, 0);
+	dmap += j;
+	ieeesge += j;
+	j++;
+
+	/*
+	 * 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 quad-words (16
+	 *    bytes) so the last value should be divided by 16.
+	 */
+	ddi_put8(acc_hdl, &frame->ChainOffset,
+	    (sizeof (MPI2_SCSI_IO_REQUEST) -
+	    sizeof (MPI2_SGE_IO_UNION) +
+	    (j - 1) * sizeof (MPI2_IEEE_SGE_SIMPLE64)) >> 4);
+	ieeesgechain = (pMpi25IeeeSgeChain64_t)ieeesge;
+	chainflags = (MPI2_IEEE_SGE_FLAGS_CHAIN_ELEMENT |
+	    MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR);
+	ddi_put8(acc_hdl, &ieeesgechain->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_IEEE_SGE_SIMPLE64) *
+		    sizeof (MPI2_IEEE_SGE_SIMPLE64);
+	} else {
+		chainlength = ((cookiec - (j - 1)) *
+		    sizeof (MPI2_IEEE_SGE_SIMPLE64));
+	}
+
+	p = cmd->cmd_extra_frames;
+
+	ddi_put32(acc_hdl, &ieeesgechain->Length, chainlength);
+	ddi_put32(acc_hdl, &ieeesgechain->Address.Low,
+	    p->m_phys_addr&0xffffffffull);
+	ddi_put32(acc_hdl, &ieeesgechain->Address.High, p->m_phys_addr>>32);
+
+	/*
+	 * 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, &ieeesgechain->NextChainOffset,
+		    (sgemax * sizeof (MPI2_IEEE_SGE_SIMPLE64)) >> 4);
+	} else {
+		ddi_put8(acc_hdl, &ieeesgechain->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.
+	 */
+	ieeesge = (pMpi2IeeeSgeSimple64_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)) {
+				ieeesgechain = (pMpi25IeeeSgeChain64_t)ieeesge;
+				j--;
+				chainflags =
+				    MPI2_IEEE_SGE_FLAGS_CHAIN_ELEMENT |
+				    MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR;
+				ddi_put8(p->m_acc_hdl,
+				    &ieeesgechain->Flags, chainflags);
 				/*
-				 * 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
+				 * k is the frame counter and (k + 1)
+				 * is the number of the next frame.
+				 * Note that frames are in contiguous
+				 * memory space.
 				 */
-				if ((l == sgemax) && (k != frames)) {
-					flags |= ((uint32_t)
-					    (MPI2_SGE_FLAGS_LAST_ELEMENT) <<
-					    MPI2_SGE_FLAGS_SHIFT);
-				}
+				nframe_phys_addr = p->m_phys_addr +
+				    (mpt->m_req_frame_size * k);
+				ddi_put32(p->m_acc_hdl,
+				    &ieeesgechain->Address.Low,
+				    nframe_phys_addr&0xffffffffull);
+				ddi_put32(p->m_acc_hdl,
+				    &ieeesgechain->Address.High,
+				    nframe_phys_addr>>32);
 
 				/*
-				 * If this is the final cookie we
-				 * indicate it by setting the flags
+				 * 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 (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);
+				if ((frames - k) >= 2) {
+					ddi_put8(p->m_acc_hdl,
+					    &ieeesgechain->NextChainOffset,
+					    (sgemax *
+					    sizeof (MPI2_IEEE_SGE_SIMPLE64))
+					    >> 4);
+					ddi_put32(p->m_acc_hdl,
+					    &ieeesgechain->Length,
+					    mpt->m_req_frame_size /
+					    sizeof (MPI2_IEEE_SGE_SIMPLE64) *
+					    sizeof (MPI2_IEEE_SGE_SIMPLE64));
 				} else {
-					flags |=
-					    (MPI2_SGE_FLAGS_IOC_TO_HOST <<
-					    MPI2_SGE_FLAGS_SHIFT);
+					/*
+					 * 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,
+					    &ieeesgechain->NextChainOffset,
+					    0);
+					ddi_put32(p->m_acc_hdl,
+					    &ieeesgechain->Length,
+					    (cookiec - j) *
+					    sizeof (MPI2_IEEE_SGE_SIMPLE64));
 				}
-				ddi_put32(p->m_acc_hdl,
-				    &sge->FlagsLength, flags);
-				dmap++;
-				sge++;
+
+				/* Jump to the next frame */
+				ieeesge = (pMpi2IeeeSgeSimple64_t)
+				    ((char *)p->m_frames_addr +
+				    (int)mpt->m_req_frame_size * k);
+
+				continue;
+			}
+
+			ddi_put32(p->m_acc_hdl,
+			    &ieeesge->Address.Low,
+			    dmap->addr.address64.Low);
+			ddi_put32(p->m_acc_hdl,
+			    &ieeesge->Address.High,
+			    dmap->addr.address64.High);
+			ddi_put32(p->m_acc_hdl,
+			    &ieeesge->Length, dmap->count);
+			flags = (MPI2_IEEE_SGE_FLAGS_SIMPLE_ELEMENT |
+			    MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR);
+
+			/*
+			 * If we are at the end of the frame and
+			 * there is another frame to fill in
+			 * do we need to do anything?
+			 * if ((l == sgemax) && (k != frames)) {
+			 * }
+			 */
+
+			/*
+			 * If this is the final cookie set end of list.
+			 */
+			if (j == i) {
+				flags |= MPI25_IEEE_SGE_FLAGS_END_OF_LIST;
 			}
+
+			ddi_put8(p->m_acc_hdl, &ieeesge->Flags, flags);
+			dmap++;
+			ieeesge++;
 		}
+	}
 
-		/*
-		 * Sync DMA with the chain buffers that were just created
-		 */
-		(void) ddi_dma_sync(p->m_dma_hdl, 0, 0, DDI_DMA_SYNC_FORDEV);
+	/*
+	 * Sync DMA with the chain buffers that were just created
+	 */
+	(void) ddi_dma_sync(p->m_dma_hdl, 0, 0, DDI_DMA_SYNC_FORDEV);
+}
+
+static void
+mptsas_sge_setup(mptsas_t *mpt, mptsas_cmd_t *cmd, uint32_t *control,
+    pMpi2SCSIIORequest_t frame, ddi_acc_handle_t acc_hdl)
+{
+	ASSERT(cmd->cmd_flags & CFLAG_DMAVALID);
+
+	NDBG1(("mptsas_sge_setup: cookiec=%d", cmd->cmd_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 4 cases here.  First where we can fit all the
+	 * SG elements into the main frame, and the case
+	 * where we can't. The SG element is also different when using
+	 * MPI2.5 interface.
+	 * 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 (cmd->cmd_cookiec <= MPTSAS_MAX_FRAME_SGES64(mpt)) {
+		if (mpt->m_MPI25) {
+			mptsas_ieee_sge_mainframe(cmd, frame, acc_hdl,
+			    cmd->cmd_cookiec,
+			    MPI25_IEEE_SGE_FLAGS_END_OF_LIST);
+		} else {
+			mptsas_sge_mainframe(cmd, frame, acc_hdl,
+			    cmd->cmd_cookiec,
+			    ((uint32_t)(MPI2_SGE_FLAGS_LAST_ELEMENT
+			    | MPI2_SGE_FLAGS_END_OF_BUFFER
+			    | MPI2_SGE_FLAGS_END_OF_LIST) <<
+			    MPI2_SGE_FLAGS_SHIFT));
+		}
+	} else {
+		if (mpt->m_MPI25) {
+			mptsas_ieee_sge_chain(mpt, cmd, frame, acc_hdl);
+		} else {
+			mptsas_sge_chain(mpt, cmd, frame, acc_hdl);
+		}
 	}
 }
 
@@ -4571,9 +5210,20 @@
 int
 mptsas_poll(mptsas_t *mpt, mptsas_cmd_t *poll_cmd, int polltime)
 {
-	int	rval = TRUE;
+	int		rval = TRUE;
+	uint32_t	int_mask;
 
-	NDBG5(("mptsas_poll: cmd=0x%p", (void *)poll_cmd));
+	NDBG5(("mptsas_poll: cmd=0x%p, flags 0x%x", (void *)poll_cmd,
+	    poll_cmd->cmd_flags));
+
+	/*
+	 * Get the current interrupt mask and disable interrupts.  When
+	 * re-enabling ints, set mask to saved value.
+	 */
+	int_mask = ddi_get32(mpt->m_datap, &mpt->m_reg->HostInterruptMask);
+	MPTSAS_DISABLE_INTR(mpt);
+
+	mpt->m_polled_intr = 1;
 
 	if ((poll_cmd->cmd_flags & CFLAG_TM_CMD) == 0) {
 		mptsas_restart_hba(mpt);
@@ -4625,6 +5275,20 @@
 
 	}
 	mptsas_fma_check(mpt, poll_cmd);
+
+	/*
+	 * Clear polling flag, re-enable interrupts.
+	 */
+	mpt->m_polled_intr = 0;
+	ddi_put32(mpt->m_datap, &mpt->m_reg->HostInterruptMask, int_mask);
+
+	/*
+	 * If there are queued cmd, start them now.
+	 */
+	if (mpt->m_waitq != NULL) {
+		mptsas_restart_waitq(mpt);
+	}
+
 	NDBG5(("mptsas_poll: done"));
 	return (rval);
 }
@@ -4635,30 +5299,33 @@
 static int
 mptsas_wait_intr(mptsas_t *mpt, int polltime)
 {
-	int				cnt;
+	int				cnt, rval = FALSE;
 	pMpi2ReplyDescriptorsUnion_t	reply_desc_union;
-	uint32_t			int_mask;
+	mptsas_reply_pqueue_t		*rpqp;
 
 	NDBG5(("mptsas_wait_intr"));
-
-	mpt->m_polled_intr = 1;
+	ASSERT(mutex_owned(&mpt->m_mutex));
 
 	/*
-	 * Get the current interrupt mask and disable interrupts.  When
-	 * re-enabling ints, set mask to saved value.
+	 * Keep polling for at least (polltime * 1000) seconds
 	 */
-	int_mask = ddi_get32(mpt->m_datap, &mpt->m_reg->HostInterruptMask);
-	MPTSAS_DISABLE_INTR(mpt);
+	rpqp = mpt->m_rep_post_queues;
 
 	/*
-	 * Keep polling for at least (polltime * 1000) seconds
+	 * Drop the main mutex and grab the mutex for reply queue 0
 	 */
+	mutex_exit(&mpt->m_mutex);
+	mutex_enter(&rpqp->rpq_mutex);
 	for (cnt = 0; cnt < polltime; cnt++) {
 		(void) ddi_dma_sync(mpt->m_dma_post_queue_hdl, 0, 0,
 		    DDI_DMA_SYNC_FORCPU);
 
+		/*
+		 * Polled requests should only come back through
+		 * the first interrupt.
+		 */
 		reply_desc_union = (pMpi2ReplyDescriptorsUnion_t)
-		    MPTSAS_GET_NEXT_REPLY(mpt, mpt->m_post_index);
+		    MPTSAS_GET_NEXT_REPLY(rpqp, rpqp->rpq_index);
 
 		if (ddi_get32(mpt->m_acc_post_queue_hdl,
 		    &reply_desc_union->Words.Low) == 0xFFFFFFFF ||
@@ -4672,38 +5339,39 @@
 		 * The reply is valid, process it according to its
 		 * type.
 		 */
-		mptsas_process_intr(mpt, reply_desc_union);
-
-		if (++mpt->m_post_index == mpt->m_post_queue_depth) {
-			mpt->m_post_index = 0;
-		}
+		mptsas_process_intr(mpt, rpqp, reply_desc_union);
 
 		/*
-		 * Update the global reply index
+		 * Clear the reply descriptor for re-use.
 		 */
-		ddi_put32(mpt->m_datap,
-		    &mpt->m_reg->ReplyPostHostIndex, mpt->m_post_index);
-		mpt->m_polled_intr = 0;
+		ddi_put64(mpt->m_acc_post_queue_hdl,
+		    &((uint64_t *)(void *)rpqp->rpq_queue)[rpqp->rpq_index],
+		    0xFFFFFFFFFFFFFFFF);
+		(void) ddi_dma_sync(mpt->m_dma_post_queue_hdl, 0, 0,
+		    DDI_DMA_SYNC_FORDEV);
+
+		if (++rpqp->rpq_index == mpt->m_post_queue_depth) {
+			rpqp->rpq_index = 0;
+		}
 
 		/*
-		 * Re-enable interrupts and quit.
+		 * Update the reply index
 		 */
-		ddi_put32(mpt->m_datap, &mpt->m_reg->HostInterruptMask,
-		    int_mask);
-		return (TRUE);
-
+		ddi_put32(mpt->m_datap,
+		    &mpt->m_reg->ReplyPostHostIndex, rpqp->rpq_index);
+		rval = TRUE;
+		break;
 	}
 
-	/*
-	 * Clear polling flag, re-enable interrupts and quit.
-	 */
-	mpt->m_polled_intr = 0;
-	ddi_put32(mpt->m_datap, &mpt->m_reg->HostInterruptMask, int_mask);
-	return (FALSE);
+	mutex_exit(&rpqp->rpq_mutex);
+	mutex_enter(&mpt->m_mutex);
+
+	return (rval);
 }
 
 static void
 mptsas_handle_scsi_io_success(mptsas_t *mpt,
+    mptsas_reply_pqueue_t *rpqp,
     pMpi2ReplyDescriptorsUnion_t reply_desc)
 {
 	pMpi2SCSIIOSuccessReplyDescriptor_t	scsi_io_success;
@@ -4712,8 +5380,6 @@
 	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);
 
@@ -4739,6 +5405,7 @@
 		    "in slot %d", SMID);
 		return;
 	}
+	ASSERT(cmd->cmd_rpqidx == rpqp->rpq_num);
 
 	pkt = CMD2PKT(cmd);
 	pkt->pkt_state |= (STATE_GOT_BUS | STATE_GOT_TARGET | STATE_SENT_CMD |
@@ -4752,8 +5419,30 @@
 		cmd->cmd_flags |= CFLAG_FINISHED;
 		cv_broadcast(&mpt->m_passthru_cv);
 		return;
-	} else {
-		mptsas_remove_cmd(mpt, cmd);
+	}
+	if (!(cmd->cmd_flags & CFLAG_TM_CMD)) {
+		if (cmd->cmd_flags & CFLAG_CMDIOC) {
+			mutex_enter(&mpt->m_mutex);
+			mptsas_remove_cmd(mpt, cmd);
+			mutex_exit(&mpt->m_mutex);
+		} else {
+#ifdef MPTSAS_DEBUG
+			/*
+			 * In order to test timeout for a command set
+			 * mptsas_test_timeout via mdb to avoid completion
+			 * processing here.
+			 */
+			if (mptsas_test_timeout) {
+				mptsas_test_timeout = 0;
+				return;
+			}
+#endif
+			/*
+			 * This is the normal path, avoid grabbing
+			 * the m_mutex.
+			 */
+			mptsas_remove_cmd_nomtx(mpt, cmd);
+		}
 	}
 
 	if (cmd->cmd_flags & CFLAG_RETRY) {
@@ -4768,7 +5457,7 @@
 		 */
 		cmd->cmd_flags &= ~CFLAG_RETRY;
 	} else {
-		mptsas_doneq_add(mpt, cmd);
+		mptsas_rpdoneq_add(mpt, rpqp, cmd);
 	}
 }
 
@@ -4779,7 +5468,7 @@
 	pMpi2AddressReplyDescriptor_t	address_reply;
 	pMPI2DefaultReply_t		reply;
 	mptsas_fw_diagnostic_buffer_t	*pBuffer;
-	uint32_t			reply_addr;
+	uint32_t			reply_addr, reply_frame_dma_baseaddr;
 	uint16_t			SMID, iocstatus;
 	mptsas_slots_t			*slots = mpt->m_active;
 	mptsas_cmd_t			*cmd = NULL;
@@ -4798,10 +5487,11 @@
 	 * 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 +
+	reply_frame_dma_baseaddr = mpt->m_reply_frame_dma_addr & 0xfffffffful;
+	if ((reply_addr < reply_frame_dma_baseaddr) ||
+	    (reply_addr >= (reply_frame_dma_baseaddr +
 	    (mpt->m_reply_frame_size * mpt->m_max_replies))) ||
-	    ((reply_addr - mpt->m_reply_frame_dma_addr) %
+	    ((reply_addr - reply_frame_dma_baseaddr) %
 	    mpt->m_reply_frame_size != 0)) {
 		mptsas_log(mpt, CE_WARN, "?Received invalid reply frame "
 		    "address 0x%x\n", reply_addr);
@@ -4812,9 +5502,12 @@
 	(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));
+	    reply_frame_dma_baseaddr));
 	function = ddi_get8(mpt->m_acc_reply_frame_hdl, &reply->Function);
 
+	NDBG31(("mptsas_handle_address_reply: function 0x%x, reply_addr=0x%x",
+	    function, reply_addr));
+
 	/*
 	 * don't get slot information and command for events since these values
 	 * don't exist
@@ -4843,9 +5536,8 @@
 			    "reply in slot %d", SMID);
 			return;
 		}
-		if ((cmd->cmd_flags & CFLAG_PASSTHRU) ||
-		    (cmd->cmd_flags & CFLAG_CONFIG) ||
-		    (cmd->cmd_flags & CFLAG_FW_DIAG)) {
+		if ((cmd->cmd_flags &
+		    (CFLAG_PASSTHRU | CFLAG_CONFIG | CFLAG_FW_DIAG))) {
 			cmd->cmd_rfm = reply_addr;
 			cmd->cmd_flags |= CFLAG_FINISHED;
 			cv_broadcast(&mpt->m_passthru_cv);
@@ -4875,7 +5567,7 @@
 		cv_signal(&mpt->m_fw_cv);
 		break;
 	case MPI2_FUNCTION_EVENT_NOTIFICATION:
-		reply_frame_no = (reply_addr - mpt->m_reply_frame_dma_addr) /
+		reply_frame_no = (reply_addr - reply_frame_dma_baseaddr) /
 		    mpt->m_reply_frame_size;
 		args = &mpt->m_replyh_args[reply_frame_no];
 		args->mpt = (void *)mpt;
@@ -4986,7 +5678,7 @@
 
 	if (cmd->cmd_flags & CFLAG_RETRY) {
 		/*
-		 * The target returned QFULL or busy, do not add tihs
+		 * The target returned QFULL or busy, do not add this
 		 * pkt to the doneq since the hba will retry
 		 * this cmd.
 		 *
@@ -5000,25 +5692,24 @@
 	}
 }
 
+#ifdef MPTSAS_DEBUG
+static uint8_t mptsas_last_sense[256];
+#endif
+
 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;
+	uint16_t		ioc_status, cmd_rqs_len;
 	uint32_t		xferred, sensecount, responsedata, 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;
-	}
+	uint64_t		sas_wwn;
+	uint8_t			phy;
+	char			wwn_str[MPTSAS_WWN_STRLEN];
 
 	scsi_status = ddi_get8(mpt->m_acc_reply_frame_hdl, &reply->SCSIStatus);
 	ioc_status = ddi_get16(mpt->m_acc_reply_frame_hdl, &reply->IOCStatus);
@@ -5029,12 +5720,19 @@
 	    &reply->ResponseInfo);
 
 	if (ioc_status & MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
+		sas_wwn = ptgt->m_addr.mta_wwn;
+		phy = ptgt->m_phynum;
+		if (sas_wwn == 0) {
+			(void) sprintf(wwn_str, "p%x", phy);
+		} else {
+			(void) sprintf(wwn_str, "w%016"PRIx64, sas_wwn);
+		}
 		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"
+		    "?Log info 0x%x received for target %d %s.\n"
 		    "\tscsi_status=0x%x, ioc_status=0x%x, scsi_state=0x%x",
-		    loginfo, Tgt(cmd), scsi_status, ioc_status,
+		    loginfo, Tgt(cmd), wwn_str, scsi_status, ioc_status,
 		    scsi_state);
 	}
 
@@ -5059,10 +5757,12 @@
 	    MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE)) {
 		pkt->pkt_reason = CMD_INCOMPLETE;
 		pkt->pkt_state |= STATE_GOT_BUS;
+		mutex_enter(&ptgt->m_t_mutex);
 		if (ptgt->m_reset_delay == 0) {
 			mptsas_set_throttle(mpt, ptgt,
 			    DRAIN_THROTTLE);
 		}
+		mutex_exit(&ptgt->m_t_mutex);
 		return;
 	}
 
@@ -5078,6 +5778,8 @@
 
 	switch (scsi_status) {
 	case MPI2_SCSI_STATUS_CHECK_CONDITION:
+		(void) ddi_dma_sync(mpt->m_dma_req_sense_hdl, 0, 0,
+		    DDI_DMA_SYNC_FORCPU);
 		pkt->pkt_resid = (cmd->cmd_dmacount - xferred);
 		arqstat = (void*)(pkt->pkt_scbp);
 		arqstat->sts_rqpkt_status = *((struct scsi_status *)
@@ -5095,11 +5797,19 @@
 		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,
+#ifdef MPTSAS_DEBUG
+		bcopy((uchar_t *)cmd->cmd_arq_buf, mptsas_last_sense,
+		    cmd->cmd_rqslen);
+#endif
+		if (cmd->cmd_extrqslen != 0) {
+			cmd_rqs_len = cmd->cmd_extrqslen;
+		} else {
+			cmd_rqs_len = cmd->cmd_rqslen;
+		}
+		bcopy((uchar_t *)cmd->cmd_arq_buf, sensedata,
 		    ((cmd->cmd_rqslen >= sensecount) ? sensecount :
-		    cmd->cmd_rqslen));
-		arqstat->sts_rqpkt_resid = (cmd->cmd_rqslen - sensecount);
+		    cmd_rqs_len));
+		arqstat->sts_rqpkt_resid = (cmd_rqs_len - sensecount);
 		cmd->cmd_flags |= CFLAG_CMDARQ;
 		/*
 		 * Set proper status for pkt if autosense was valid
@@ -5151,6 +5861,8 @@
 			    mptsas_handle_dr,
 			    (void *)topo_node,
 			    DDI_NOSLEEP)) != DDI_SUCCESS) {
+				kmem_free(topo_node,
+				    sizeof (mptsas_topo_change_list_t));
 				mptsas_log(mpt, CE_NOTE, "mptsas start taskq"
 				    "for handle SAS dynamic reconfigure"
 				    "failed. \n");
@@ -5162,9 +5874,11 @@
 		case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
 			pkt->pkt_reason = CMD_DEV_GONE;
 			pkt->pkt_state |= STATE_GOT_BUS;
+			mutex_enter(&ptgt->m_t_mutex);
 			if (ptgt->m_reset_delay == 0) {
 				mptsas_set_throttle(mpt, ptgt, DRAIN_THROTTLE);
 			}
+			mutex_exit(&ptgt->m_t_mutex);
 			NDBG31(("lost disk for target%d, command:%x",
 			    Tgt(cmd), pkt->pkt_cdbp[0]));
 			break;
@@ -5189,8 +5903,18 @@
 			}
 			break;
 		case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED:
-			mptsas_set_pkt_reason(mpt,
-			    cmd, CMD_RESET, STAT_BUS_RESET);
+			if (cmd->cmd_active_expiration <= gethrtime()) {
+				/*
+				 * When timeout requested, propagate
+				 * proper reason and statistics to
+				 * target drivers.
+				 */
+				mptsas_set_pkt_reason(mpt, cmd, CMD_TIMEOUT,
+				    STAT_BUS_RESET | STAT_TIMEOUT);
+			} else {
+				mptsas_set_pkt_reason(mpt, cmd, CMD_RESET,
+				    STAT_BUS_RESET);
+			}
 			break;
 		case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED:
 		case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED:
@@ -5210,16 +5934,14 @@
 			 */
 			for (ptgt = refhash_first(mpt->m_targets); ptgt != NULL;
 			    ptgt = refhash_next(mpt->m_targets, ptgt)) {
-				mptsas_set_throttle(mpt, ptgt, DRAIN_THROTTLE);
+				mptsas_set_throttle_mtx(mpt, ptgt,
+				    DRAIN_THROTTLE);
 			}
 
 			/*
 			 * retry command
 			 */
-			cmd->cmd_flags |= CFLAG_RETRY;
-			cmd->cmd_pkt_flags |= FLAG_HEAD;
-
-			(void) mptsas_accept_pkt(mpt, cmd);
+			mptsas_retry_pkt(mpt, cmd);
 			break;
 		default:
 			mptsas_log(mpt, CE_WARN,
@@ -5303,17 +6025,17 @@
 }
 
 static void
-mptsas_doneq_thread(mptsas_doneq_thread_arg_t *arg)
+mptsas_doneq_thread(mptsas_thread_arg_t *arg)
 {
 	mptsas_t			*mpt = arg->mpt;
-	uint64_t			t = arg->t;
+	uint32_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) {
+		if (!item->dlist.dl_q) {
 			cv_wait(&item->cv, &item->mutex);
 		}
 		pkt = NULL;
@@ -5328,10 +6050,10 @@
 		mutex_enter(&item->mutex);
 	}
 	mutex_exit(&item->mutex);
-	mutex_enter(&mpt->m_doneq_mutex);
+	mutex_enter(&mpt->m_qthread_mutex);
 	mpt->m_doneq_thread_n--;
-	cv_broadcast(&mpt->m_doneq_thread_cv);
-	mutex_exit(&mpt->m_doneq_mutex);
+	cv_broadcast(&mpt->m_qthread_cv);
+	mutex_exit(&mpt->m_qthread_mutex);
 }
 
 
@@ -5342,12 +6064,17 @@
 mptsas_intr(caddr_t arg1, caddr_t arg2)
 {
 	mptsas_t			*mpt = (void *)arg1;
+	mptsas_reply_pqueue_t		*rpqp;
+	int				reply_q = (int)(uintptr_t)arg2;
 	pMpi2ReplyDescriptorsUnion_t	reply_desc_union;
-	uchar_t				did_reply = FALSE;
+	int				found = 0, i, rpqidx;
+	size_t				dma_sync_len;
+	off_t				dma_sync_offset;
+	uint32_t			istat;
 
-	NDBG1(("mptsas_intr: arg1 0x%p arg2 0x%p", (void *)arg1, (void *)arg2));
+	NDBG18(("mptsas_intr: arg1 0x%p reply_q 0x%d", (void *)arg1, reply_q));
 
-	mutex_enter(&mpt->m_mutex);
+	rpqp = &mpt->m_rep_post_queues[reply_q];
 
 	/*
 	 * If interrupts are shared by two channels then check whether this
@@ -5356,8 +6083,23 @@
 	 */
 	if ((mpt->m_options & MPTSAS_OPT_PM) &&
 	    (mpt->m_power_level != PM_LEVEL_D0)) {
-		mutex_exit(&mpt->m_mutex);
+		mpt->m_unclaimed_pm_interrupt_count++;
+		return (DDI_INTR_UNCLAIMED);
+	}
+
+	istat = MPTSAS_GET_ISTAT(mpt);
+	if (!(istat & MPI2_HIS_REPLY_DESCRIPTOR_INTERRUPT)) {
+		NDBG18(("Interrupt bit not set, istat 0x%x", istat));
+		mpt->m_unclaimed_no_interrupt_count++;
+		/*
+		 * Really need a good definition of when this is valid.
+		 * It appears not to be if you have multiple reply post
+		 * queues, there may be a better way - need LSI info.
+		 * For now just count them.
+		 */
+#if 0
 		return (DDI_INTR_UNCLAIMED);
+#endif
 	}
 
 	/*
@@ -5367,64 +6109,114 @@
 	 * return with interrupt unclaimed.
 	 */
 	if (mpt->m_polled_intr) {
-		mutex_exit(&mpt->m_mutex);
-		mptsas_log(mpt, CE_WARN, "mpt_sas: Unclaimed interrupt");
+		mptsas_log(mpt, CE_WARN,
+		    "Unclaimed interrupt, rpq %d (Polling), istat 0x%x",
+		    reply_q, istat);
+		mpt->m_unclaimed_polled_interrupt_count++;
 		return (DDI_INTR_UNCLAIMED);
 	}
 
 	/*
-	 * Read the istat register.
+	 * At the moment this is the only place the mutex is grabbed.
+	 * So it should never fail!
 	 */
-	if ((INTPENDING(mpt)) != 0) {
-		/*
-		 * read fifo until empty.
-		 */
+	if (mutex_tryenter(&rpqp->rpq_mutex) == 0) {
+		mutex_enter(&rpqp->rpq_mutex);
+		rpqp->rpq_intr_mutexbusy++;
+	}
+
+	dma_sync_len = mpt->m_post_queue_depth * 8;
+	dma_sync_offset = dma_sync_len * reply_q;
+	(void) ddi_dma_sync(mpt->m_dma_post_queue_hdl,
+	    dma_sync_offset, dma_sync_len, DDI_DMA_SYNC_FORCPU);
+
+	/*
+	 * Go around the reply queue and process each descriptor until
+	 * we get to the next unused one.
+	 * It seems to be an occupational hazard that we get interrupts
+	 * with nothing to do. These are counted below.
+	 */
+	rpqidx = rpqp->rpq_index;
 #ifndef __lock_lint
-		_NOTE(CONSTCOND)
+	_NOTE(CONSTCOND)
 #endif
-		while (TRUE) {
-			(void) ddi_dma_sync(mpt->m_dma_post_queue_hdl, 0, 0,
-			    DDI_DMA_SYNC_FORCPU);
-			reply_desc_union = (pMpi2ReplyDescriptorsUnion_t)
-			    MPTSAS_GET_NEXT_REPLY(mpt, mpt->m_post_index);
+	while (TRUE) {
+		reply_desc_union = (pMpi2ReplyDescriptorsUnion_t)
+		    MPTSAS_GET_NEXT_REPLY(rpqp, rpqidx);
 
-			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;
-			}
+		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 updating the reply index
-			 * after they've all been processed.
-			 */
-			did_reply = TRUE;
+		found++;
 
-			mptsas_process_intr(mpt, reply_desc_union);
+		ASSERT(ddi_get8(mpt->m_acc_post_queue_hdl,
+		    &reply_desc_union->Default.MSIxIndex) == reply_q);
 
-			/*
-			 * Increment post index and roll over if needed.
-			 */
-			if (++mpt->m_post_index == mpt->m_post_queue_depth) {
-				mpt->m_post_index = 0;
-			}
-		}
+		/*
+		 * Process it according to its type.
+		 */
+		mptsas_process_intr(mpt, rpqp, reply_desc_union);
 
 		/*
-		 * Update the global reply index if at least one reply was
-		 * processed.
+		 * Clear the reply descriptor for re-use.
 		 */
-		if (did_reply) {
-			ddi_put32(mpt->m_datap,
-			    &mpt->m_reg->ReplyPostHostIndex, mpt->m_post_index);
+		ddi_put64(mpt->m_acc_post_queue_hdl,
+		    &((uint64_t *)(void *)rpqp->rpq_queue)[rpqidx],
+		    0xFFFFFFFFFFFFFFFF);
+
+		/*
+		 * Increment post index and roll over if needed.
+		 */
+		if (++rpqidx == mpt->m_post_queue_depth) {
+			rpqidx = 0;
 		}
-	} else {
-		mutex_exit(&mpt->m_mutex);
+	}
+
+	if (found == 0) {
+		rpqp->rpq_intr_unclaimed++;
+		mutex_exit(&rpqp->rpq_mutex);
+		mpt->m_unclaimed_nocmd_interrupt_count++;
 		return (DDI_INTR_UNCLAIMED);
 	}
-	NDBG1(("mptsas_intr complete"));
+	rpqp->rpq_index = rpqidx;
+
+	rpqp->rpq_intr_count++;
+	NDBG18(("mptsas_intr complete(%d), did %d loops", reply_q, found));
+
+	(void) ddi_dma_sync(mpt->m_dma_post_queue_hdl,
+	    dma_sync_offset, dma_sync_len, DDI_DMA_SYNC_FORDEV);
+
+	mpt->m_interrupt_count++;
+
+	/*
+	 * Update the reply index if at least one reply was processed.
+	 * For more than 8 reply queues on SAS3 controllers we have to do
+	 * things a little different. See Chapter 20 in the MPI 2.5 spec.
+	 */
+	if (mpt->m_post_reply_qcount > 8) {
+		/*
+		 * The offsets from the base are multiples of 0x10.
+		 * We are indexing into 32 bit quantities so calculate
+		 * the index for that.
+		 */
+		i = (reply_q&~0x7) >> 1;
+		ddi_put32(mpt->m_datap,
+		    &mpt->m_reg->SuppReplyPostHostIndex[i],
+		    rpqp->rpq_index |
+		    ((reply_q&0x7)<<MPI2_RPHI_MSIX_INDEX_SHIFT));
+		(void) ddi_get32(mpt->m_datap,
+		    &mpt->m_reg->SuppReplyPostHostIndex[i]);
+	} else {
+		ddi_put32(mpt->m_datap,
+		    &mpt->m_reg->ReplyPostHostIndex,
+		    rpqp->rpq_index | (reply_q<<MPI2_RPHI_MSIX_INDEX_SHIFT));
+		(void) ddi_get32(mpt->m_datap,
+		    &mpt->m_reg->ReplyPostHostIndex);
+	}
 
 	/*
 	 * If no helper threads are created, process the doneq in ISR. If
@@ -5433,32 +6225,65 @@
 	 * 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.
+	 * To always use the threads set mptsas_doneq_length_threshold_prop
+	 * to zero in the mpt_sas3.conf file.
+	 *
+	 * Check the current reply queue done queue.
 	 */
-	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 (rpqp->rpq_dlist.dl_len) {
+		if (!mpt->m_doneq_thread_n ||
+		    (rpqp->rpq_dlist.dl_len <= mpt->m_doneq_length_threshold)) {
+			mptsas_rpdoneq_empty(rpqp);
+		} else {
+			mptsas_deliver_doneq_thread(mpt, &rpqp->rpq_dlist);
+		}
+	}
+
+	mutex_exit(&rpqp->rpq_mutex);
+
+	/*
+	 * Check the main done queue. If we find something
+	 * grab the mutex and check again before processing.
+	 */
+	if (mpt->m_dlist.dl_len) {
+		mutex_enter(&mpt->m_mutex);
+		if (mpt->m_dlist.dl_len) {
+			if (!mpt->m_doneq_thread_n ||
+			    (mpt->m_dlist.dl_len <=
+			    mpt->m_doneq_length_threshold)) {
+				mptsas_doneq_empty(mpt);
+			} else {
+				mptsas_deliver_doneq_thread(mpt, &mpt->m_dlist);
+			}
+		}
+		mutex_exit(&mpt->m_mutex);
 	}
 
 	/*
 	 * If there are queued cmd, start them now.
 	 */
 	if (mpt->m_waitq != NULL) {
-		mptsas_restart_waitq(mpt);
+		mutex_enter(&mpt->m_mutex);
+		if (mpt->m_waitq != NULL && mpt->m_polled_intr == 0) {
+			mptsas_restart_waitq(mpt);
+		}
+		mutex_exit(&mpt->m_mutex);
 	}
-
-	mutex_exit(&mpt->m_mutex);
 	return (DDI_INTR_CLAIMED);
 }
 
 static void
-mptsas_process_intr(mptsas_t *mpt,
+mptsas_process_intr(mptsas_t *mpt, mptsas_reply_pqueue_t *rpqp,
     pMpi2ReplyDescriptorsUnion_t reply_desc_union)
 {
 	uint8_t	reply_type;
 
-	ASSERT(mutex_owned(&mpt->m_mutex));
+	/*
+	 * Should get here with the reply queue mutex held, but not
+	 * the main mpt mutex. Want to avoid grabbing that during
+	 * normal operations if possible.
+	 */
+	ASSERT(mutex_owned(&rpqp->rpq_mutex));
 
 	/*
 	 * The reply is valid, process it according to its
@@ -5467,25 +6292,20 @@
 	 */
 	reply_type = ddi_get8(mpt->m_acc_post_queue_hdl,
 	    &reply_desc_union->Default.ReplyFlags);
+	NDBG18(("mptsas_process_intr(rpq %d) reply_type 0x%x", rpqp->rpq_num,
+	    reply_type));
 	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);
+	if (reply_type == MPI2_RPY_DESCRIPT_FLAGS_SCSI_IO_SUCCESS ||
+	    reply_type == MPI25_RPY_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO_SUCCESS) {
+		mptsas_handle_scsi_io_success(mpt, rpqp, reply_desc_union);
 	} else if (reply_type == MPI2_RPY_DESCRIPT_FLAGS_ADDRESS_REPLY) {
+		mutex_enter(&mpt->m_mutex);
 		mptsas_handle_address_reply(mpt, reply_desc_union);
+		mutex_exit(&mpt->m_mutex);
 	} 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);
 }
 
 /*
@@ -5496,6 +6316,7 @@
 {
 	mptsas_target_t	*ptgt = cmd->cmd_tgt_addr;
 
+	mutex_enter(&ptgt->m_t_mutex);
 	if ((++cmd->cmd_qfull_retries > ptgt->m_qfull_retries) ||
 	    (ptgt->m_qfull_retries == 0)) {
 		/*
@@ -5513,13 +6334,13 @@
 			ptgt->m_t_throttle =
 			    max((ptgt->m_t_ncmds - 2), 0);
 		}
+		mutex_exit(&ptgt->m_t_mutex);
 
-		cmd->cmd_pkt_flags |= FLAG_HEAD;
 		cmd->cmd_flags &= ~(CFLAG_TRANFLAG);
-		cmd->cmd_flags |= CFLAG_RETRY;
 
-		(void) mptsas_accept_pkt(mpt, cmd);
+		mptsas_retry_pkt(mpt, cmd);
 
+		mutex_enter(&ptgt->m_t_mutex);
 		/*
 		 * when target gives queue full status with no commands
 		 * outstanding (m_t_ncmds == 0), throttle is set to 0
@@ -5542,6 +6363,7 @@
 			}
 		}
 	}
+	mutex_exit(&ptgt->m_t_mutex);
 }
 
 mptsas_phymask_t
@@ -5550,7 +6372,7 @@
 	mptsas_phymask_t	phy_mask = 0;
 	uint8_t			i = 0;
 
-	NDBG20(("mptsas%d physport_to_phymask enter", mpt->m_instance));
+	NDBG20(("mptsas3%d physport_to_phymask enter", mpt->m_instance));
 
 	ASSERT(mutex_owned(&mpt->m_mutex));
 
@@ -5569,7 +6391,7 @@
 			break;
 		}
 	}
-	NDBG20(("mptsas%d physport_to_phymask:physport :%x phymask :%x, ",
+	NDBG20(("mptsas3%d physport_to_phymask:physport :%x phymask :%x, ",
 	    mpt->m_instance, physport, phy_mask));
 	return (phy_mask);
 }
@@ -5623,7 +6445,7 @@
 	uint8_t		current_port;
 	int		i, j;
 
-	NDBG20(("mptsas%d update phymask ", mpt->m_instance));
+	NDBG20(("mptsas3%d update phymask ", mpt->m_instance));
 
 	ASSERT(mutex_owned(&mpt->m_mutex));
 
@@ -5669,7 +6491,7 @@
 		mutex_enter(&mpt->m_mutex);
 	}
 	kmem_free(phy_mask_name, MPTSAS_MAX_PHYS);
-	NDBG20(("mptsas%d update phymask return", mpt->m_instance));
+	NDBG20(("mptsas3%d update phymask return", mpt->m_instance));
 }
 
 /*
@@ -5689,7 +6511,7 @@
 	mptsas_t			*mpt;
 	dev_info_t			*parent = NULL;
 	mptsas_phymask_t		phymask = 0;
-	char				*phy_mask_name;
+	char				phy_mask_name[MPTSAS_MAX_PHYS];
 	uint8_t				flags = 0, physport = 0xff;
 	uint8_t				port_update = 0;
 	uint_t				event;
@@ -5700,9 +6522,7 @@
 	event = topo_node->event;
 	flags = topo_node->flags;
 
-	phy_mask_name = kmem_zalloc(MPTSAS_MAX_PHYS, KM_SLEEP);
-
-	NDBG20(("mptsas%d handle_dr enter", mpt->m_instance));
+	NDBG20(("mptsas3%d handle_dr enter", mpt->m_instance));
 
 	switch (event) {
 	case MPTSAS_DR_EVENT_RECONFIG_TARGET:
@@ -5744,12 +6564,26 @@
 
 	}
 	mutex_exit(&mpt->m_mutex);
+
 	while (topo_node) {
 		phymask = 0;
+		flags = topo_node->flags;
+		event = topo_node->event;
+		if (event == MPTSAS_DR_EVENT_REMOVE_HANDLE) {
+			goto handle_topo_change;
+		}
+		if ((event == MPTSAS_DR_EVENT_RECONFIG_TARGET) &&
+		    (flags == MPTSAS_TOPO_FLAG_RAID_PHYSDRV_ASSOCIATED)) {
+			/*
+			 * 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;
+		}
+
 		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)) {
 				/*
@@ -5758,25 +6592,11 @@
 				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) {
 				/*
@@ -5792,8 +6612,7 @@
 			 * Translate physport to phymask so that we can search
 			 * parent dip.
 			 */
-			phymask = mptsas_physport_to_phymask(mpt,
-			    physport);
+			phymask = mptsas_physport_to_phymask(mpt, physport);
 			mutex_exit(&mpt->m_mutex);
 
 find_parent:
@@ -5806,20 +6625,17 @@
 				(void) sprintf(phy_mask_name, "v0");
 			} else {
 				/*
-				 * phymask can bo 0 if the drive has been
+				 * phymask can be 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;
 				}
@@ -5829,43 +6645,137 @@
 			    phy_mask_name);
 			if (parent == NULL) {
 				mptsas_log(mpt, CE_WARN, "Failed to find an "
-				    "iport, should not happen!");
-				goto out;
+				    "iport for \"%s\", should not happen!",
+				    phy_mask_name);
+				save_node = topo_node;
+				topo_node = topo_node->next;
+				ASSERT(save_node);
+				kmem_free(save_node,
+				    sizeof (mptsas_topo_change_list_t));
+				continue;
 			}
 
 		}
-		ASSERT(parent);
-handle_topo_change:
+		ASSERT(parent);
+handle_topo_change:
+
+		mutex_enter(&mpt->m_mutex);
+		/*
+		 * If HBA is being reset, don't perform operations depending
+		 * on the IOC. We must free the topo list, however.
+		 */
+		if (!mpt->m_in_reset)
+			mptsas_handle_topo_change(topo_node, parent);
+		else
+			NDBG20(("skipping topo change received during reset"));
+		mutex_exit(&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));
+
+		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;
+		}
+	}
+}
+
+static void
+mptsas_offline_target(mptsas_t *mpt, mptsas_target_t *ptgt,
+    uint8_t topo_flags, dev_info_t *parent)
+{
+	uint64_t	sas_wwn = 0;
+	uint8_t		phy;
+	char		wwn_str[MPTSAS_WWN_STRLEN];
+	uint16_t	devhdl;
+	int		circ = 0, circ1 = 0;
+	int		rval = 0;
+
+	sas_wwn = ptgt->m_addr.mta_wwn;
+	phy = ptgt->m_phynum;
+	devhdl = ptgt->m_devhdl;
+
+	if (sas_wwn) {
+		(void) sprintf(wwn_str, "w%016"PRIx64, sas_wwn);
+	} else {
+		(void) sprintf(wwn_str, "p%x", phy);
+	}
+
+	/*
+	 * Abort all outstanding command on the device
+	 */
+	rval = mptsas_do_scsi_reset(mpt, devhdl);
+	if (rval) {
+		NDBG20(("mptsas3%d: mptsas_offline_target: reset target "
+		    "before offline devhdl:%x, phymask:%x, rval:%x",
+		    mpt->m_instance, ptgt->m_devhdl,
+		    ptgt->m_addr.mta_phymask, rval));
+	}
+
+	mutex_exit(&mpt->m_mutex);
+
+	ndi_devi_enter(scsi_vhci_dip, &circ);
+	ndi_devi_enter(parent, &circ1);
+	rval = mptsas_offline_targetdev(parent, wwn_str);
+	ndi_devi_exit(parent, circ1);
+	ndi_devi_exit(scsi_vhci_dip, circ);
+	NDBG20(("mptsas3%d: mptsas_offline_target %s devhdl:%x, "
+	    "phymask:%x, rval:%x", mpt->m_instance, wwn_str,
+	    ptgt->m_devhdl, ptgt->m_addr.mta_phymask, rval));
+
+	/*
+	 * Clear parent's props for SMHBA support
+	 */
+	if (topo_flags == MPTSAS_TOPO_FLAG_DIRECT_ATTACHED_DEVICE) {
+		if (ddi_prop_update_string(DDI_DEV_T_NONE, parent,
+		    SCSI_ADDR_PROP_ATTACHED_PORT, "") !=
+		    DDI_PROP_SUCCESS) {
+			(void) ddi_prop_remove(DDI_DEV_T_NONE, parent,
+			    SCSI_ADDR_PROP_ATTACHED_PORT);
+			mptsas_log(mpt, CE_WARN, "mptsas attached port "
+			    "prop update failed");
+		}
+		if (ddi_prop_update_int(DDI_DEV_T_NONE, parent,
+		    MPTSAS_NUM_PHYS, 0) != DDI_PROP_SUCCESS) {
+			(void) ddi_prop_remove(DDI_DEV_T_NONE, parent,
+			    MPTSAS_NUM_PHYS);
+			mptsas_log(mpt, CE_WARN, "mptsas num phys "
+			    "prop update failed");
+		}
+		if (ddi_prop_update_int(DDI_DEV_T_NONE, parent,
+		    MPTSAS_VIRTUAL_PORT, 1) != DDI_PROP_SUCCESS) {
+			(void) ddi_prop_remove(DDI_DEV_T_NONE, parent,
+			    MPTSAS_VIRTUAL_PORT);
+			mptsas_log(mpt, CE_WARN, "mptsas virtual port "
+			    "prop update failed");
+		}
+	}
 
-		mutex_enter(&mpt->m_mutex);
+	mutex_enter(&mpt->m_mutex);
+	ptgt->m_led_status = 0;
+	(void) mptsas_flush_led_status(mpt, ptgt);
+	if (rval == DDI_SUCCESS) {
+		mutex_destroy(&ptgt->m_t_mutex);
+		refhash_remove(mpt->m_targets, ptgt);
+		ptgt = NULL;
+	} else {
 		/*
-		 * If HBA is being reset, don't perform operations depending
-		 * on the IOC. We must free the topo list, however.
-		 */
-		if (!mpt->m_in_reset)
-			mptsas_handle_topo_change(topo_node, parent);
-		else
-			NDBG20(("skipping topo change received during reset"));
-		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;
-		}
+		 * clean DR_INTRANSITION flag to allow I/O down to
+		 * PHCI driver since failover finished.
+		 * Invalidate the devhdl
+		 */
+		ptgt->m_devhdl = MPTSAS_INVALID_DEVHDL;
+		ptgt->m_tgt_unconfigured = 0;
+		ptgt->m_dr_flag = MPTSAS_DR_INACTIVE;
 	}
-out:
-	kmem_free(phy_mask_name, MPTSAS_MAX_PHYS);
 }
 
 static void
@@ -5877,16 +6787,16 @@
 	mptsas_t	*mpt = (void *)topo_node->mpt;
 	uint16_t	devhdl;
 	uint16_t	attached_devhdl;
-	uint64_t	sas_wwn = 0;
 	int		rval = 0;
 	uint32_t	page_address;
-	uint8_t		phy, flags;
-	char		*addr = NULL;
+	uint8_t		flags;
 	dev_info_t	*lundip;
 	int		circ = 0, circ1 = 0;
 	char		attached_wwnstr[MPTSAS_WWN_STRLEN];
 
-	NDBG20(("mptsas%d handle_topo_change enter", mpt->m_instance));
+	NDBG20(("mptsas3%d handle_topo_change enter, devhdl 0x%x,"
+	    "event 0x%x, flags 0x%x", mpt->m_instance, topo_node->devhdl,
+	    topo_node->event, topo_node->flags));
 
 	ASSERT(mutex_owned(&mpt->m_mutex));
 
@@ -6046,7 +6956,7 @@
 		}
 		mutex_enter(&mpt->m_mutex);
 
-		NDBG20(("mptsas%d handle_topo_change to online devhdl:%x, "
+		NDBG20(("mptsas3%d handle_topo_change to online devhdl:%x, "
 		    "phymask:%x.", mpt->m_instance, ptgt->m_devhdl,
 		    ptgt->m_addr.mta_phymask));
 		break;
@@ -6059,16 +6969,6 @@
 		if (ptgt == NULL)
 			break;
 
-		sas_wwn = ptgt->m_addr.mta_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) ||
@@ -6080,83 +6980,8 @@
 			 */
 			(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_addr.mta_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 offline devhdl:%x, "
-		    "phymask:%x, rval:%x", mpt->m_instance,
-		    ptgt->m_devhdl, ptgt->m_addr.mta_phymask, rval));
-
-		kmem_free(addr, SCSI_MAXNAMELEN);
-
-		/*
-		 * Clear parent's props for SMHBA support
-		 */
-		flags = topo_node->flags;
-		if (flags == MPTSAS_TOPO_FLAG_DIRECT_ATTACHED_DEVICE) {
-			bzero(attached_wwnstr, sizeof (attached_wwnstr));
-			if (ddi_prop_update_string(DDI_DEV_T_NONE, parent,
-			    SCSI_ADDR_PROP_ATTACHED_PORT, attached_wwnstr) !=
-			    DDI_PROP_SUCCESS) {
-				(void) ddi_prop_remove(DDI_DEV_T_NONE, parent,
-				    SCSI_ADDR_PROP_ATTACHED_PORT);
-				mptsas_log(mpt, CE_WARN, "mptsas attached port "
-				    "prop update failed");
-				break;
-			}
-			if (ddi_prop_update_int(DDI_DEV_T_NONE, parent,
-			    MPTSAS_NUM_PHYS, 0) !=
-			    DDI_PROP_SUCCESS) {
-				(void) ddi_prop_remove(DDI_DEV_T_NONE, parent,
-				    MPTSAS_NUM_PHYS);
-				mptsas_log(mpt, CE_WARN, "mptsas num phys "
-				    "prop update failed");
-				break;
-			}
-			if (ddi_prop_update_int(DDI_DEV_T_NONE, parent,
-			    MPTSAS_VIRTUAL_PORT, 1) !=
-			    DDI_PROP_SUCCESS) {
-				(void) ddi_prop_remove(DDI_DEV_T_NONE, parent,
-				    MPTSAS_VIRTUAL_PORT);
-				mptsas_log(mpt, CE_WARN, "mptsas virtual port "
-				    "prop update failed");
-				break;
-			}
-		}
 
-		mutex_enter(&mpt->m_mutex);
-		ptgt->m_led_status = 0;
-		(void) mptsas_flush_led_status(mpt, ptgt);
-		if (rval == DDI_SUCCESS) {
-			refhash_remove(mpt->m_targets, ptgt);
-			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;
-			ptgt->m_tgt_unconfigured = 0;
-			mutex_enter(&mpt->m_tx_waitq_mutex);
-			ptgt->m_dr_flag = MPTSAS_DR_INACTIVE;
-			mutex_exit(&mpt->m_tx_waitq_mutex);
-		}
+		mptsas_offline_target(mpt, ptgt, topo_node->flags, parent);
 
 		/*
 		 * Send SAS IO Unit Control to free the dev handle
@@ -6165,33 +6990,29 @@
 		    (flags == MPTSAS_TOPO_FLAG_EXPANDER_ATTACHED_DEVICE)) {
 			rval = mptsas_free_devhdl(mpt, devhdl);
 
-			NDBG20(("mptsas%d handle_topo_change to remove "
+			NDBG20(("mptsas3%d handle_topo_change to remove "
 			    "devhdl:%x, rval:%x", mpt->m_instance, devhdl,
 			    rval));
 		}
 
 		break;
 	}
-	case MPTSAS_TOPO_FLAG_REMOVE_HANDLE:
+	case MPTSAS_DR_EVENT_REMOVE_HANDLE:
 	{
 		devhdl = topo_node->devhdl;
+
 		/*
-		 * If this is the remove handle event, do a reset first.
+		 * 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));
-			}
-		}
+		rval = mptsas_do_scsi_reset(mpt, devhdl);
+		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 "
+		NDBG20(("mptsas3%d handle_topo_change to remove "
 		    "devhdl:%x, rval:%x", mpt->m_instance, devhdl,
 		    rval));
 		break;
@@ -6284,7 +7105,7 @@
 		}
 
 		mutex_enter(&mpt->m_mutex);
-		NDBG20(("mptsas%d handle_topo_change to remove devhdl:%x, "
+		NDBG20(("mptsas3%d handle_topo_change to remove devhdl:%x, "
 		    "rval:%x", mpt->m_instance, psmp->m_devhdl, rval));
 		if (rval == DDI_SUCCESS) {
 			refhash_remove(mpt->m_smp_targets, psmp);
@@ -6320,7 +7141,8 @@
 	mpt = replyh_arg->mpt;
 
 	eventreply = (pMpi2EventNotificationReply_t)
-	    (mpt->m_reply_frame + (rfm - mpt->m_reply_frame_dma_addr));
+	    (mpt->m_reply_frame + (rfm -
+	    (mpt->m_reply_frame_dma_addr&0xfffffffful)));
 	event = ddi_get16(mpt->m_acc_reply_frame_hdl, &eventreply->Event);
 
 
@@ -6408,21 +7230,24 @@
 	ASSERT(mutex_owned(&mpt->m_mutex));
 
 	eventreply = (pMpi2EventNotificationReply_t)
-	    (mpt->m_reply_frame + (rfm - mpt->m_reply_frame_dma_addr));
+	    (mpt->m_reply_frame + (rfm -
+	    (mpt->m_reply_frame_dma_addr&0xfffffffful)));
 	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,
+			    "!mptsas_handle_event_sync: event 0x%x, "
+			    "IOCStatus=0x%x, "
+			    "IOCLogInfo=0x%x", event, 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,
+			    "mptsas_handle_event_sync: event 0x%x, "
+			    "IOCStatus=0x%x, "
+			    "(IOCLogInfo=0x%x)", event, iocstatus,
 			    ddi_get32(mpt->m_acc_reply_frame_hdl,
 			    &eventreply->IOCLogInfo));
 		}
@@ -6557,7 +7382,7 @@
 			switch (reason_code) {
 			case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED:
 			{
-				NDBG20(("mptsas%d phy %d physical_port %d "
+				NDBG20(("mptsas3%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,
@@ -6593,6 +7418,10 @@
 					(void) sprintf(curr, "is online at 6.0 "
 					    "Gbps");
 					break;
+				case MPI25_EVENT_SAS_TOPO_LR_RATE_12_0:
+					(void) sprintf(curr,
+					    "is online at 12.0 Gbps");
+					break;
 				default:
 					(void) sprintf(curr, "state is "
 					    "unknown");
@@ -6639,7 +7468,7 @@
 			}
 			case MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING:
 			{
-				NDBG20(("mptsas%d phy %d physical_port %d "
+				NDBG20(("mptsas3%d phy %d physical_port %d "
 				    "dev_handle %d removed", mpt->m_instance,
 				    phy, physport, dev_handle));
 				/*
@@ -6670,7 +7499,7 @@
 				 * 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.
+				 * MPTSAS_DR_EVENT_REMOVE_HANDLE event.
 				 */
 				if (ptgt == NULL) {
 					topo_node = kmem_zalloc(
@@ -6679,7 +7508,7 @@
 					topo_node->mpt = mpt;
 					topo_node->un.phymask = 0;
 					topo_node->event =
-					    MPTSAS_TOPO_FLAG_REMOVE_HANDLE;
+					    MPTSAS_DR_EVENT_REMOVE_HANDLE;
 					topo_node->devhdl = dev_handle;
 					topo_node->flags = flags;
 					topo_node->object = NULL;
@@ -6695,16 +7524,12 @@
 
 				/*
 				 * 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,
+				 * before failover finish. We won't add
+				 * any following commands 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),
@@ -6796,6 +7621,18 @@
 					    SAS_PHY_ONLINE,
 					    &mpt->m_phy_info[i].smhba_info);
 					break;
+				case MPI25_EVENT_SAS_TOPO_LR_RATE_12_0:
+					(void) sprintf(curr, "is online at "
+					    "12.0 Gbps");
+					if ((expd_handle == 0) &&
+					    (enc_handle == 1)) {
+						mpt->m_port_chng = 1;
+					}
+					mptsas_smhba_log_sysevent(mpt,
+					    ESC_SAS_PHY_EVENT,
+					    SAS_PHY_ONLINE,
+					    &mpt->m_phy_info[i].smhba_info);
+					break;
 				default:
 					(void) sprintf(curr, "state is "
 					    "unknown");
@@ -6833,6 +7670,10 @@
 					(void) sprintf(prev, ", was online at "
 					    "6.0 Gbps");
 					break;
+				case MPI25_EVENT_SAS_TOPO_LR_RATE_12_0:
+					(void) sprintf(prev, ", was online at "
+					    "12.0 Gbps");
+					break;
 				default:
 				break;
 				}
@@ -6847,7 +7688,7 @@
 				    "removal");
 				break;
 			}
-			NDBG20(("mptsas%d phy %d DevHandle %x, %s%s%s\n",
+			NDBG20(("mptsas3%d phy %d DevHandle %x, %s%s%s\n",
 			    mpt->m_instance, phy, dev_handle, string, curr,
 			    prev));
 		}
@@ -6858,6 +7699,12 @@
 			if ((ddi_taskq_dispatch(mpt->m_dr_taskq,
 			    mptsas_handle_dr, (void *)topo_head,
 			    DDI_NOSLEEP)) != DDI_SUCCESS) {
+				while (topo_head != NULL) {
+					topo_node = topo_head;
+					topo_head = topo_head->next;
+					kmem_free(topo_node,
+					    sizeof (mptsas_topo_change_list_t));
+				}
 				mptsas_log(mpt, CE_NOTE, "mptsas start taskq "
 				    "for handle SAS DR event failed. \n");
 			}
@@ -6879,7 +7726,7 @@
 		num_entries = ddi_get8(mpt->m_acc_reply_frame_hdl,
 		    &irChangeList->NumElements);
 
-		NDBG20(("mptsas%d IR_CONFIGURATION_CHANGE_LIST event received",
+		NDBG20(("mptsas3%d IR_CONFIGURATION_CHANGE_LIST event received",
 		    mpt->m_instance));
 
 		for (i = 0; i < num_entries; i++) {
@@ -6935,9 +7782,7 @@
 				/*
 				 * 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),
@@ -6970,9 +7815,7 @@
 				/*
 				 * 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),
@@ -7036,6 +7879,12 @@
 			if ((ddi_taskq_dispatch(mpt->m_dr_taskq,
 			    mptsas_handle_dr, (void *)topo_head,
 			    DDI_NOSLEEP)) != DDI_SUCCESS) {
+				while (topo_head != NULL) {
+					topo_node = topo_head;
+					topo_head = topo_head->next;
+					kmem_free(topo_node,
+					    sizeof (mptsas_topo_change_list_t));
+				}
 				mptsas_log(mpt, CE_NOTE, "mptsas start taskq "
 				    "for handle SAS DR event failed. \n");
 			}
@@ -7078,7 +7927,8 @@
 	}
 
 	eventreply = (pMpi2EventNotificationReply_t)
-	    (mpt->m_reply_frame + (rfm - mpt->m_reply_frame_dma_addr));
+	    (mpt->m_reply_frame + (rfm -
+	    (mpt->m_reply_frame_dma_addr&0xfffffffful)));
 	event = ddi_get16(mpt->m_acc_reply_frame_hdl, &eventreply->Event);
 
 	if (iocstatus = ddi_get16(mpt->m_acc_reply_frame_hdl,
@@ -7111,10 +7961,10 @@
 		    iocloginfo));
 		break;
 	case MPI2_EVENT_STATE_CHANGE:
-		NDBG20(("mptsas%d state change.", mpt->m_instance));
+		NDBG20(("mptsas3%d state change.", mpt->m_instance));
 		break;
 	case MPI2_EVENT_HARD_RESET_RECEIVED:
-		NDBG20(("mptsas%d event change.", mpt->m_instance));
+		NDBG20(("mptsas3%d event change.", mpt->m_instance));
 		break;
 	case MPI2_EVENT_SAS_DISCOVERY:
 	{
@@ -7151,7 +8001,7 @@
 		break;
 	}
 	case MPI2_EVENT_EVENT_CHANGE:
-		NDBG20(("mptsas%d event change.", mpt->m_instance));
+		NDBG20(("mptsas3%d event change.", mpt->m_instance));
 		break;
 	case MPI2_EVENT_TASK_SET_FULL:
 	{
@@ -7159,7 +8009,7 @@
 
 		taskfull = (pMpi2EventDataTaskSetFull_t)eventreply->EventData;
 
-		NDBG20(("TASK_SET_FULL received for mptsas%d, depth %d\n",
+		NDBG20(("TASK_SET_FULL received for mptsas3%d, depth %d\n",
 		    mpt->m_instance,  ddi_get16(mpt->m_acc_reply_frame_hdl,
 		    &taskfull->CurrentDepth)));
 		break;
@@ -7193,8 +8043,9 @@
 		default:
 		break;
 		}
-		NDBG20(("mptsas%d ENCLOSURE STATUS CHANGE for enclosure %x%s\n",
-		    mpt->m_instance, ddi_get16(mpt->m_acc_reply_frame_hdl,
+		NDBG20(("mptsas3%d ENCLOSURE STATUS CHANGE for enclosure "
+		    "%x%s\n", mpt->m_instance,
+		    ddi_get16(mpt->m_acc_reply_frame_hdl,
 		    &encstatus->EnclosureHandle), string));
 		break;
 	}
@@ -7319,7 +8170,7 @@
 				    rc);
 		}
 
-		NDBG20(("mptsas%d raid operational status: (%s)"
+		NDBG20(("mptsas3%d raid operational status: (%s)"
 		    "\thandle(0x%04x), percent complete(%d)\n",
 		    mpt->m_instance, reason_str, handle, percent));
 		break;
@@ -7388,12 +8239,12 @@
 			    &mpt->m_phy_info[phy_num].smhba_info);
 			break;
 		default:
-			NDBG20(("mptsas%d: unknown BROADCAST PRIMITIVE"
+			NDBG16(("mptsas3%d: unknown BROADCAST PRIMITIVE"
 			    " %x received",
 			    mpt->m_instance, primitive));
 			break;
 		}
-		NDBG20(("mptsas%d sas broadcast primitive: "
+		NDBG16(("mptsas3%d sas broadcast primitive: "
 		    "\tprimitive(0x%04x), phy(%d) complete\n",
 		    mpt->m_instance, primitive, phy_num));
 		break;
@@ -7599,7 +8450,7 @@
 		break;
 	}
 	default:
-		NDBG20(("mptsas%d: unknown event %x received",
+		NDBG20(("mptsas3%d: unknown event %x received",
 		    mpt->m_instance, event));
 		break;
 	}
@@ -7634,23 +8485,85 @@
 
 	for (ptgt = refhash_first(mpt->m_targets); ptgt != NULL;
 	    ptgt = refhash_next(mpt->m_targets, ptgt)) {
+		mutex_enter(&ptgt->m_t_mutex);
 		if (ptgt->m_reset_delay == 0) {
 			if (ptgt->m_t_throttle == QFULL_THROTTLE) {
 				mptsas_set_throttle(mpt, ptgt,
 				    MAX_THROTTLE);
 			}
 		}
+		mutex_exit(&ptgt->m_t_mutex);
 	}
 	mptsas_restart_hba(mpt);
 	mutex_exit(&mpt->m_mutex);
 }
 
+/*
+ * Assume some checks have been done prior to calling this
+ * function so we don't need to consider taking the m_mutex.
+ */
+static void
+mptsas_remove_cmd_nomtx(mptsas_t *mpt, mptsas_cmd_t *cmd)
+{
+	int		slot;
+	mptsas_slots_t	*slots = mpt->m_active;
+	mptsas_target_t	*ptgt = cmd->cmd_tgt_addr;
+
+	ASSERT(cmd != NULL);
+	ASSERT(cmd->cmd_queued == FALSE);
+	ASSERT((cmd->cmd_flags & CFLAG_CMDIOC) == 0);
+
+	slot = cmd->cmd_slot;
+
+	/*
+	 * remove the cmd.
+	 */
+	if (cmd == slots->m_slot[slot]) {
+		NDBG31(("mptsas_remove_cmd_nomtx: removing cmd=0x%p, flags "
+		    "0x%x", (void *)cmd, cmd->cmd_flags));
+		slots->m_slot[slot] = NULL;
+		ASSERT(mpt->m_ncmds != 0);
+		atomic_dec_32(&mpt->m_ncmds);
+		ASSERT(mpt->m_rep_post_queues[cmd->cmd_rpqidx].rpq_ncmds != 0);
+		atomic_dec_32(
+		    &mpt->m_rep_post_queues[cmd->cmd_rpqidx].rpq_ncmds);
+
+		/*
+		 * Decrement per target ncmds, we know this is not an
+		 * IOC cmd and it therefore has a target associated with it.
+		 */
+		mutex_enter(&ptgt->m_t_mutex);
+		ASSERT(ptgt->m_t_ncmds != 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);
+		}
+
+		/*
+		 * Remove this command from the active queue.
+		 */
+		if (cmd->cmd_active_expiration != 0) {
+			TAILQ_REMOVE(&ptgt->m_active_cmdq, cmd,
+			    cmd_active_link);
+			cmd->cmd_active_expiration = 0;
+		}
+		mutex_exit(&ptgt->m_t_mutex);
+	}
+
+	ASSERT(cmd != slots->m_slot[cmd->cmd_slot]);
+}
+
 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);
@@ -7664,23 +8577,30 @@
 		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));
+		NDBG31(("mptsas_remove_cmd: removing cmd=0x%p, flags 0x%x",
+		    (void *)cmd, cmd->cmd_flags));
 		slots->m_slot[slot] = NULL;
-		mpt->m_ncmds--;
+		ASSERT(mpt->m_ncmds != 0);
+		atomic_dec_32(&mpt->m_ncmds);
+		ASSERT(mpt->m_rep_post_queues[cmd->cmd_rpqidx].rpq_ncmds != 0);
+		atomic_dec_32(
+		    &mpt->m_rep_post_queues[cmd->cmd_rpqidx].rpq_ncmds);
 
 		/*
 		 * only decrement per target ncmds if command
 		 * has a target associated with it.
 		 */
 		if ((cmd->cmd_flags & CFLAG_CMDIOC) == 0) {
+			mutex_enter(&ptgt->m_t_mutex);
+			ASSERT(ptgt->m_t_ncmds != 0);
 			ptgt->m_t_ncmds--;
+
 			/*
 			 * reset throttle if we just ran an untagged command
 			 * to a tagged target
@@ -7689,6 +8609,16 @@
 			    ((cmd->cmd_pkt_flags & FLAG_TAGMASK) == 0)) {
 				mptsas_set_throttle(mpt, ptgt, MAX_THROTTLE);
 			}
+
+			/*
+			 * Remove this command from the active queue.
+			 */
+			if (cmd->cmd_active_expiration != 0) {
+				TAILQ_REMOVE(&ptgt->m_active_cmdq, cmd,
+				    cmd_active_link);
+				cmd->cmd_active_expiration = 0;
+			}
+			mutex_exit(&ptgt->m_t_mutex);
 		}
 
 	}
@@ -7701,50 +8631,6 @@
 		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_normal 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_normal + 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]);
 }
 
@@ -7762,11 +8648,7 @@
 {
 	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_accept_tx_waitqs(mpt);
 	mptsas_restart_waitq(mpt);
 }
 
@@ -7834,59 +8716,215 @@
 		}
 
 		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 (ptgt) {
+			mutex_enter(&ptgt->m_t_mutex);
+			if ((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->m_reset_delay == 0) &&
+			    (ptgt->m_t_ncmds < ptgt->m_t_throttle)) {
+				mutex_exit(&ptgt->m_t_mutex);
+
+				if (mptsas_save_cmd(mpt, cmd) == TRUE) {
+					mptsas_waitq_delete(mpt, cmd);
+					mutex_exit(&mpt->m_mutex);
+					(void) mptsas_start_cmd(mpt, cmd);
+					mutex_enter(&mpt->m_mutex);
+					cmd = mpt->m_waitq;
+					continue;
+				}
+			} else {
+				mutex_exit(&ptgt->m_t_mutex);
+			}
 		}
-		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);
+		cmd = next_cmd;
+	}
+}
+
+/*
+ * Cmds are queued if scsi_start() doesn't get the m_mutex lock(no wait)
+ * or if the decision has been made to always do that. Setting
+ * mptsas_allow_txq_jumping to zero will allow higher performance on
+ * a heavily loaded system as there is less disruption to the flow here.
+ * There are 2 threads that handle one queue each. The idea is that
+ * they take it in turn to grab the m_mutex to run the mptsas_accept_pkt()
+ * function and then drop it while the cmd is started in mptsas_start_cmd().
+ */
+static void
+mptsas_tx_waitq_thread(mptsas_thread_arg_t *arg)
+{
+	mptsas_t *mpt = arg->mpt;
+	mptsas_tx_waitqueue_t *txwq = &mpt->m_tx_waitq[arg->t];
+
+	mutex_enter(&txwq->txwq_mutex);
+	while (txwq->txwq_active) {
+		mptsas_drain_tx_waitq(mpt, txwq);
+		if (txwq->txwq_wdrain) {
+			cv_signal(&txwq->txwq_drain_cv);
+		}
+		cv_wait(&txwq->txwq_cv, &txwq->txwq_mutex);
+	}
+	mutex_exit(&txwq->txwq_mutex);
+	mutex_enter(&mpt->m_qthread_mutex);
+	mpt->m_txwq_thread_n--;
+	cv_broadcast(&mpt->m_qthread_cv);
+	mutex_exit(&mpt->m_qthread_mutex);
+}
+
+/*
+ * Set the draining flag, disconnect the list and process one at a time
+ * so that the cmds are sent in order.
+ */
+static void
+mptsas_drain_tx_waitq(mptsas_t *mpt, mptsas_tx_waitqueue_t *txwq)
+{
+	mptsas_cmd_t	*cmd, *ncmd;
+	int		rval, start;
+#ifdef MPTSAS_DEBUG
+	uint32_t	qlen;
+#endif
+
+	txwq->txwq_draining = TRUE;
+#ifndef __lock_lint
+	_NOTE(CONSTCOND)
+#endif
+	while (TRUE) {
+
+		/*
+		 * A Bus Reset could occur at any time but it will have to
+		 * wait for the main mutex before flushing the tx_waitq.
+		 * Pull all commands at once, then follow the list in order to
+		 * reduce txwq_mutex hold time. If there is a Bus Reset at
+		 * some point the commands will get to the waitq and then be
+		 * flushed.
+		 */
+		cmd = txwq->txwq_cmdq;
+
+		if (cmd == NULL) {
+			txwq->txwq_draining = FALSE;
+			return;
+		}
+		txwq->txwq_cmdq = NULL;
+		txwq->txwq_qtail = &txwq->txwq_cmdq;
+#ifdef MPTSAS_DEBUG
+		qlen = txwq->txwq_len;
+#endif
+		txwq->txwq_len = 0;
+		mutex_exit(&txwq->txwq_mutex);
+
+		while (cmd) {
+			ncmd = cmd->cmd_linkp;
+			cmd->cmd_linkp = NULL;
+			mutex_enter(&mpt->m_mutex);
+			start = mptsas_accept_pkt(mpt, cmd, &rval);
+			mutex_exit(&mpt->m_mutex);
+			if (start) {
 				(void) mptsas_start_cmd(mpt, cmd);
 			}
+			if (rval != TRAN_ACCEPT)
+				cmn_err(CE_WARN,
+				    "mpt: mptsas_drain_tx_waitq: failed "
+				    "(rval=0x%x) to accept cmd 0x%p on queue\n",
+				    rval, (void *)cmd);
+			cmd = ncmd;
+#ifdef MPTSAS_DEBUG
+			qlen--;
+#endif
 		}
-		cmd = next_cmd;
+		ASSERT(qlen == 0);
+		mutex_enter(&txwq->txwq_mutex);
 	}
 }
+
 /*
- * 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.
+ * Stop the drain threads from picking up a new list.
+ * Optionally wait for the current list being processed to drain through.
+ * Add to and processing the tx waitq is now on hold until unblock is called.
  */
 static void
-mptsas_accept_tx_waitq(mptsas_t *mpt)
+mptsas_block_tx_waitqs(mptsas_t *mpt, int wait)
 {
-	mptsas_cmd_t *cmd;
+	int		i;
+	uint8_t		wdrain = 0;
+	mptsas_tx_waitqueue_t *txwq;
 
 	ASSERT(mutex_owned(&mpt->m_mutex));
-	ASSERT(mutex_owned(&mpt->m_tx_waitq_mutex));
+
+	if (mpt->m_txwq_thread_n == 0) {
+		return;
+	}
 
 	/*
-	 * 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.
+	 * Turn off the use of the tx wait queues by scsi_start().
+	 * This is just a dynamic flag no need for a mutex.
 	 */
-	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;
+	mpt->m_txwq_enabled = BLOCKED;
+
+	for (i = 0; i < NUM_TX_WAITQ; i++) {
+		txwq = &mpt->m_tx_waitq[i];
+		mutex_enter(&txwq->txwq_mutex);
+		txwq->txwq_wdrain = TRUE;
+		if (txwq->txwq_draining && wait)
+			wdrain |= (1<<i);
+		mutex_exit(&txwq->txwq_mutex);
+	}
+
+	if (wdrain) {
+		/*
+		 * Because the threads disconnect the entire queue each time
+		 * round in order to drain to completely drain we have to
+		 * drop the main mutex otherwise the drain threads get stuck.
+		 */
+		mutex_exit(&mpt->m_mutex);
+		for (i = 0; i < NUM_TX_WAITQ; i++) {
+			if (wdrain & (1<<i)) {
+				txwq = &mpt->m_tx_waitq[i];
+				mutex_enter(&txwq->txwq_mutex);
+				while (txwq->txwq_draining) {
+					cv_wait(&txwq->txwq_drain_cv,
+					    &txwq->txwq_mutex);
+				}
+				mutex_exit(&txwq->txwq_mutex);
+			}
 		}
-		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);
+		mutex_enter(&mpt->m_mutex);
 	}
 }
 
+static void
+mptsas_unblock_tx_waitqs(mptsas_t *mpt)
+{
+	int			i;
+	mptsas_tx_waitqueue_t	*txwq;
+
+	if (mpt->m_txwq_thread_n == 0) {
+		return;
+	}
+
+	for (i = 0; i < NUM_TX_WAITQ; i++) {
+		txwq = &mpt->m_tx_waitq[i];
+		mutex_enter(&txwq->txwq_mutex);
+		txwq->txwq_wdrain = FALSE;
+		cv_signal(&txwq->txwq_cv);
+		mutex_exit(&txwq->txwq_mutex);
+	}
+
+	mpt->m_txwq_enabled = FALSE;
+}
+
+static void
+mptsas_accept_tx_waitqs(mptsas_t *mpt)
+{
+	/*
+	 * Block with drain and unblock will leave us in a state where
+	 * we have the main mutex, there is nothing on the tx wait queues
+	 * and they are not in use until watch notices high activity again.
+	 */
+	mptsas_block_tx_waitqs(mpt, 1);
+	mptsas_unblock_tx_waitqs(mpt);
+}
 
 /*
  * mpt tag type lookup
@@ -7899,22 +8937,26 @@
 {
 	struct scsi_pkt		*pkt = CMD2PKT(cmd);
 	uint32_t		control = 0;
-	int			n;
-	caddr_t			mem;
+	caddr_t			mem, arsbuf;
 	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;
+	uint16_t		SMID, io_flags = 0, ars_size;
+	uint8_t			MSIidx;
+	uint64_t		request_desc;
+	uint32_t		ars_dmaaddrlow;
+	mptsas_cmd_t		*c;
 
-	NDBG1(("mptsas_start_cmd: cmd=0x%p", (void *)cmd));
+	NDBG1(("mptsas_start_cmd: cmd=0x%p, flags 0x%x", (void *)cmd,
+	    cmd->cmd_flags));
 
 	/*
 	 * 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;
+	MSIidx = cmd->cmd_rpqidx;
 
 	/*
 	 * It is possible for back to back device reset to
@@ -7930,6 +8972,7 @@
 	 * then drain before submitting this cmd; SCSI-2 allows RQSENSE
 	 * to be untagged
 	 */
+	mutex_enter(&ptgt->m_t_mutex);
 	if (((cmd->cmd_pkt_flags & FLAG_TAGMASK) == 0) &&
 	    (ptgt->m_t_ncmds > 1) &&
 	    ((cmd->cmd_flags & CFLAG_TM_CMD) == 0) &&
@@ -7941,10 +8984,15 @@
 			if (ptgt->m_reset_delay == 0) {
 				mptsas_set_throttle(mpt, ptgt, DRAIN_THROTTLE);
 			}
+			mutex_exit(&ptgt->m_t_mutex);
 
+			mutex_enter(&mpt->m_mutex);
 			mptsas_remove_cmd(mpt, cmd);
 			cmd->cmd_pkt_flags |= FLAG_HEAD;
 			mptsas_waitq_add(mpt, cmd);
+			mutex_exit(&mpt->m_mutex);
+		} else {
+			mutex_exit(&ptgt->m_t_mutex);
 		}
 		return (DDI_FAILURE);
 	}
@@ -7975,14 +9023,71 @@
 		control |= MPI2_SCSIIO_CONTROL_SIMPLEQ;
 	}
 
+	/*
+	 * Set timeout.
+	 */
+	cmd->cmd_active_expiration =
+	    gethrtime() + (hrtime_t)pkt->pkt_time * NANOSEC;
+
+	c = TAILQ_FIRST(&ptgt->m_active_cmdq);
+	if (c == NULL ||
+	    c->cmd_active_expiration < cmd->cmd_active_expiration) {
+		/*
+		 * Common case is that this is the last pending expiration
+		 * (or queue is empty). Insert at head of the queue.
+		 */
+		TAILQ_INSERT_HEAD(&ptgt->m_active_cmdq, cmd, cmd_active_link);
+	} else {
+		/*
+		 * Queue is not empty and first element expires later than
+		 * this command. Search for element expiring sooner.
+		 */
+		while ((c = TAILQ_NEXT(c, cmd_active_link)) != NULL) {
+			if (c->cmd_active_expiration <
+			    cmd->cmd_active_expiration) {
+				TAILQ_INSERT_BEFORE(c, cmd, cmd_active_link);
+				break;
+			}
+		}
+		if (c == NULL) {
+			/*
+			 * No element found expiring sooner, append to
+			 * non-empty queue.
+			 */
+			TAILQ_INSERT_TAIL(&ptgt->m_active_cmdq, cmd,
+			    cmd_active_link);
+		}
+	}
+
+	mutex_exit(&ptgt->m_t_mutex);
+
 	if (cmd->cmd_pkt_flags & FLAG_TLR) {
 		control |= MPI2_SCSIIO_CONTROL_TLR_ON;
 	}
 
 	mem = mpt->m_req_frame + (mpt->m_req_frame_size * SMID);
 	io_request = (pMpi2SCSIIORequest_t)mem;
-
+	if (cmd->cmd_extrqslen != 0) {
+		/*
+		 * Mapping of the buffer was done in mptsas_pkt_alloc_extern().
+		 * Calculate the DMA address with the same offset.
+		 */
+		arsbuf = cmd->cmd_arq_buf;
+		ars_size = cmd->cmd_extrqslen;
+		ars_dmaaddrlow = (mpt->m_req_sense_dma_addr +
+		    ((uintptr_t)arsbuf - (uintptr_t)mpt->m_req_sense)) &
+		    0xffffffffull;
+	} else {
+		arsbuf = mpt->m_req_sense + (mpt->m_req_sense_size * (SMID-1));
+		cmd->cmd_arq_buf = arsbuf;
+		ars_size = mpt->m_req_sense_size;
+		ars_dmaaddrlow = (mpt->m_req_sense_dma_addr +
+		    (mpt->m_req_sense_size * (SMID-1))) &
+		    0xffffffffull;
+	}
 	bzero(io_request, sizeof (Mpi2SCSIIORequest_t));
+	bzero(arsbuf, ars_size);
+
 	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,
@@ -7992,6 +9097,13 @@
 	    io_request->CDB.CDB32, cmd->cmd_cdblen, DDI_DEV_AUTOINCR);
 
 	io_flags = cmd->cmd_cdblen;
+	if (mptsas3_use_fastpath &&
+	    ptgt->m_io_flags & MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH) {
+		io_flags |= MPI25_SCSIIO_IOFLAGS_FAST_PATH;
+		request_desc = MPI25_REQ_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO;
+	} else {
+		request_desc = MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO;
+	}
 	ddi_put16(acc_hdl, &io_request->IoFlags, io_flags);
 	/*
 	 * setup the Scatter/Gather DMA list for this request
@@ -8010,127 +9122,107 @@
 	 * 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->SenseBufferLowAddress, ars_dmaaddrlow);
 
 	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));
+	NDBG31(("starting message=%d(0x%p), with cmd=0x%p",
+	    SMID, (void *)io_request, (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
+	request_desc |= (SMID << 16) + (MSIidx << 8);
+	request_desc |= ((uint64_t)ptgt->m_devhdl << 48);
+	MPTSAS_START_CMD(mpt, request_desc);
 
+#if 0
+	/* Is this of any benefit here, what is it going to catch? */
 	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);
 	}
+#endif
 	return (DDI_SUCCESS);
 }
 
 /*
- * Select a helper thread to handle current doneq
+ * Select a helper thread to handle given doneq.
+ * Note that we don't require to have the main m_mutex here, but worst case
+ * is that we wont follow the thread rotation to the letter.
+ * However must ensure we have the mutex that covers the source dlist when
+ * we actually hand off.
  */
 static void
-mptsas_deliver_doneq_thread(mptsas_t *mpt)
+mptsas_deliver_doneq_thread(mptsas_t *mpt, mptsas_done_list_t *dlist)
 {
-	uint64_t			t, i;
+	uint32_t			t, i, j = mpt->m_doneq_next_thread;
 	uint32_t			min = 0xffffffff;
 	mptsas_doneq_thread_list_t	*item;
 
+	/*
+	 * No need to take indivudual list mutex's during the loop.
+	 * We are only reading values and the worst that will happen is that
+	 * we pick the wrong thread.
+	 */
 	for (i = 0; i < mpt->m_doneq_thread_n; i++) {
-		item = &mpt->m_doneq_thread_id[i];
+		item = &mpt->m_doneq_thread_id[j];
+
 		/*
 		 * If the completed command on help thread[i] less than
-		 * doneq_thread_threshold, then pick the thread[i]. Otherwise
+		 * doneq_thread_threshold, then pick the thread[j]. 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);
+		if (item->dlist.dl_len < mpt->m_doneq_thread_threshold) {
+			t = j;
 			break;
 		}
-		if (item->len < min) {
-			min = item->len;
-			t = i;
+		if (item->dlist.dl_len < min) {
+			min = item->dlist.dl_len;
+			t = j;
 		}
-		mutex_exit(&item->mutex);
+		if (++j == mpt->m_doneq_thread_n) {
+			j = 0;
+		}
+	}
+	item = &mpt->m_doneq_thread_id[t];
+	mutex_enter(&item->mutex);
+	mptsas_doneq_mv(dlist, item);
+	cv_signal(&item->cv);
+	mutex_exit(&item->mutex);
+
+	/*
+	 * Next time start at the next thread.
+	 * This will minimize the potential of grabing a lock
+	 * for a thread that is busy, either on a very busy systems
+	 * or on one that is configured to do all command completion
+	 * processing through threads.
+	 */
+	if (++t == mpt->m_doneq_thread_n) {
+		t = 0;
 	}
-	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);
+	mpt->m_doneq_next_thread = (uint16_t)t;
 }
 
 /*
- * move the current global doneq to the doneq of thead[t]
+ * move one doneq to another.
  */
 static void
-mptsas_doneq_mv(mptsas_t *mpt, uint64_t t)
+mptsas_doneq_mv(mptsas_done_list_t *from, mptsas_doneq_thread_list_t *item)
 {
+	mptsas_done_list_t		*to = &item->dlist;
 	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++;
+	if ((cmd = from->dl_q) != NULL) {
+		*to->dl_tail = cmd;
+		to->dl_tail = from->dl_tail;
+		to->dl_len += from->dl_len;
+		from->dl_q = NULL;
+		from->dl_tail = &from->dl_q;
+		from->dl_len = 0;
 	}
 }
 
@@ -8144,6 +9236,8 @@
 	    DDI_SUCCESS) ||
 	    (mptsas_check_acc_handle(mpt->m_acc_req_frame_hdl) !=
 	    DDI_SUCCESS) ||
+	    (mptsas_check_acc_handle(mpt->m_acc_req_sense_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) !=
@@ -8163,6 +9257,8 @@
 	}
 	if ((mptsas_check_dma_handle(mpt->m_dma_req_frame_hdl) !=
 	    DDI_SUCCESS) ||
+	    (mptsas_check_dma_handle(mpt->m_dma_req_sense_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) !=
@@ -8191,18 +9287,6 @@
 		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;
-	}
 }
 
 /*
@@ -8233,9 +9317,35 @@
 	 * the doneq.  no intr cmds do not have callbacks.
 	 */
 	if (pkt && (pkt->pkt_comp)) {
-		*mpt->m_donetail = cmd;
-		mpt->m_donetail = &cmd->cmd_linkp;
-		mpt->m_doneq_len++;
+		*mpt->m_dlist.dl_tail = cmd;
+		mpt->m_dlist.dl_tail = &cmd->cmd_linkp;
+		mpt->m_dlist.dl_len++;
+	}
+}
+
+static void
+mptsas_rpdoneq_add(mptsas_t *mpt, mptsas_reply_pqueue_t *rpqp,
+    mptsas_cmd_t *cmd)
+{
+	struct scsi_pkt	*pkt = CMD2PKT(cmd);
+
+	NDBG31(("mptsas_rpdoneq_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.
+	 */
+	if (pkt && (pkt->pkt_comp)) {
+		*rpqp->rpq_dlist.dl_tail = cmd;
+		rpqp->rpq_dlist.dl_tail = &cmd->cmd_linkp;
+		rpqp->rpq_dlist.dl_len++;
 	}
 }
 
@@ -8246,14 +9356,14 @@
 	mptsas_doneq_thread_list_t	*item = &mpt->m_doneq_thread_id[t];
 
 	/* pop one off the done queue */
-	if ((cmd = item->doneq) != NULL) {
+	if ((cmd = item->dlist.dl_q) != 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;
+		if ((item->dlist.dl_q = cmd->cmd_linkp) == NULL) {
+			item->dlist.dl_tail = &item->dlist.dl_q;
 		}
 		cmd->cmd_linkp = NULL;
-		item->len--;
+		item->dlist.dl_len--;
 	}
 	return (cmd);
 }
@@ -8261,15 +9371,14 @@
 static void
 mptsas_doneq_empty(mptsas_t *mpt)
 {
-	if (mpt->m_doneq && !mpt->m_in_callback) {
+	if (mpt->m_dlist.dl_q) {
 		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;
+		cmd = mpt->m_dlist.dl_q;
+		mpt->m_dlist.dl_q = NULL;
+		mpt->m_dlist.dl_tail = &mpt->m_dlist.dl_q;
+		mpt->m_dlist.dl_len = 0;
 
 		mutex_exit(&mpt->m_mutex);
 		/*
@@ -8286,7 +9395,36 @@
 			cmd = next;
 		}
 		mutex_enter(&mpt->m_mutex);
-		mpt->m_in_callback = 0;
+	}
+}
+
+static void
+mptsas_rpdoneq_empty(mptsas_reply_pqueue_t *rpqp)
+{
+	if (rpqp->rpq_dlist.dl_q) {
+		mptsas_cmd_t	*cmd, *next;
+		struct scsi_pkt *pkt;
+
+		cmd = rpqp->rpq_dlist.dl_q;
+		rpqp->rpq_dlist.dl_q = NULL;
+		rpqp->rpq_dlist.dl_tail = &rpqp->rpq_dlist.dl_q;
+		rpqp->rpq_dlist.dl_len = 0;
+
+		mutex_exit(&rpqp->rpq_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(&rpqp->rpq_mutex);
 	}
 }
 
@@ -8376,57 +9514,6 @@
 	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
  *
@@ -8542,7 +9629,7 @@
 	return (mptsas_get_name(sd, name, len));
 }
 
-void
+static void
 mptsas_set_throttle(mptsas_t *mpt, mptsas_target_t *ptgt, int what)
 {
 
@@ -8566,6 +9653,56 @@
 	}
 }
 
+static void
+mptsas_set_throttle_mtx(mptsas_t *mpt, mptsas_target_t *ptgt, int what)
+{
+	if (mpt->m_softstate & (MPTSAS_SS_QUIESCED | MPTSAS_SS_DRAINING)) {
+		return;
+	}
+
+	mutex_enter(&ptgt->m_t_mutex);
+	mptsas_set_throttle(mpt, ptgt, what);
+	mutex_exit(&ptgt->m_t_mutex);
+}
+
+/*
+ * Find all commands in the tx_waitq's for target and lun (if lun not -1),
+ * remove them from the queues and return the linked list.
+ */
+static mptsas_cmd_t *
+mptsas_strip_targetlun_from_txwqs(mptsas_t *mpt, ushort_t target, int lun)
+{
+	mptsas_cmd_t		*cmd, *clist, **tailp, **prev_tailp;
+	mptsas_tx_waitqueue_t	*txwq;
+	int			i;
+
+	clist = NULL;
+	tailp = &clist;
+
+	for (i = 0; i < NUM_TX_WAITQ; i++) {
+		txwq = &mpt->m_tx_waitq[i];
+		mutex_enter(&txwq->txwq_mutex);
+		prev_tailp = &txwq->txwq_cmdq;
+		cmd = txwq->txwq_cmdq;
+		while (cmd != NULL) {
+			if (Tgt(cmd) == target &&
+			    (lun == -1 || (Lun(cmd) == lun))) {
+				*prev_tailp = cmd->cmd_linkp;
+				*tailp = cmd;
+				tailp = &cmd->cmd_linkp;
+				cmd = cmd->cmd_linkp;
+				*tailp = NULL;
+			} else {
+				prev_tailp = &cmd->cmd_linkp;
+				cmd = cmd->cmd_linkp;
+			}
+		}
+		txwq->txwq_qtail = prev_tailp;
+		mutex_exit(&txwq->txwq_mutex);
+	}
+	return (clist);
+}
+
 /*
  * Clean up from a device reset.
  * For the case of target reset, this function clears the waitq of all
@@ -8580,9 +9717,12 @@
 	int		slot;
 	uchar_t		reason;
 	uint_t		stat;
+	hrtime_t	timestamp;
 
 	NDBG25(("mptsas_flush_target: target=%d lun=%d", target, lun));
 
+	timestamp = gethrtime();
+
 	/*
 	 * Make sure the I/O Controller has flushed all cmds
 	 * that are associated with this target for a target reset
@@ -8597,6 +9737,15 @@
 		switch (tasktype) {
 		case MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET:
 			if (Tgt(cmd) == target) {
+				if (cmd->cmd_active_expiration <= timestamp) {
+					/*
+					 * When timeout requested, propagate
+					 * proper reason and statistics to
+					 * target drivers.
+					 */
+					reason = CMD_TIMEOUT;
+					stat |= STAT_TIMEOUT;
+				}
 				NDBG25(("mptsas_flush_target discovered non-"
 				    "NULL cmd in slot %d, tasktype 0x%x", slot,
 				    tasktype));
@@ -8612,14 +9761,16 @@
 			/*FALLTHROUGH*/
 		case MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET:
 			if ((Tgt(cmd) == target) && (Lun(cmd) == lun)) {
+				if (cmd->cmd_active_expiration <= timestamp) {
+					stat |= STAT_TIMEOUT;
+				}
 
 				NDBG25(("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_set_pkt_reason(mpt, cmd, reason, stat);
 				mptsas_doneq_add(mpt, cmd);
 			}
 			break;
@@ -8648,21 +9799,13 @@
 			}
 			cmd = next_cmd;
 		}
-		mutex_enter(&mpt->m_tx_waitq_mutex);
-		cmd = mpt->m_tx_waitq;
+		cmd = mptsas_strip_targetlun_from_txwqs(mpt, target, -1);
 		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);
-			}
+			mptsas_set_pkt_reason(mpt, cmd, reason, stat);
+			mptsas_doneq_add(mpt, cmd);
 			cmd = next_cmd;
 		}
-		mutex_exit(&mpt->m_tx_waitq_mutex);
 		break;
 	case MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET:
 		reason = CMD_ABORTED;
@@ -8679,21 +9822,13 @@
 			}
 			cmd = next_cmd;
 		}
-		mutex_enter(&mpt->m_tx_waitq_mutex);
-		cmd = mpt->m_tx_waitq;
+		cmd = mptsas_strip_targetlun_from_txwqs(mpt, target, lun);
 		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);
-			}
+			mptsas_set_pkt_reason(mpt, cmd, reason, stat);
+			mptsas_doneq_add(mpt, cmd);
 			cmd = next_cmd;
 		}
-		mutex_exit(&mpt->m_tx_waitq_mutex);
 		break;
 	default:
 		mptsas_log(mpt, CE_WARN, "Unknown task management type %d.",
@@ -8710,8 +9845,8 @@
 mptsas_flush_hba(mptsas_t *mpt)
 {
 	mptsas_slots_t	*slots = mpt->m_active;
-	mptsas_cmd_t	*cmd;
-	int		slot;
+	mptsas_cmd_t	*cmd, *ncmd;
+	int		slot, i;
 
 	NDBG25(("mptsas_flush_hba"));
 
@@ -8736,9 +9871,8 @@
 			 */
 			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_FW_DIAG)) {
+			if ((cmd->cmd_flags &
+			    (CFLAG_PASSTHRU | CFLAG_CONFIG | CFLAG_FW_DIAG))) {
 				cmd->cmd_flags |= CFLAG_FINISHED;
 				cv_broadcast(&mpt->m_passthru_cv);
 				cv_broadcast(&mpt->m_config_cv);
@@ -8774,16 +9908,22 @@
 	}
 
 	/*
-	 * Flush the tx_waitq
+	 * Flush the tx_waitqs
 	 */
-	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);
+	for (i = 0; i < NUM_TX_WAITQ; i++) {
+		mutex_enter(&mpt->m_tx_waitq[i].txwq_mutex);
+		cmd = mpt->m_tx_waitq[i].txwq_cmdq;
+		mpt->m_tx_waitq[i].txwq_cmdq = NULL;
+		mpt->m_tx_waitq[i].txwq_qtail = &mpt->m_tx_waitq[i].txwq_cmdq;
+		mutex_exit(&mpt->m_tx_waitq[i].txwq_mutex);
+		while (cmd != NULL) {
+			ncmd = cmd->cmd_linkp;
+			mptsas_set_pkt_reason(mpt, cmd, CMD_RESET,
+			    STAT_BUS_RESET);
+			mptsas_doneq_add(mpt, cmd);
+			cmd = ncmd;
+		}
 	}
-	mutex_exit(&mpt->m_tx_waitq_mutex);
 
 	/*
 	 * Drain the taskqs prior to reallocating resources.
@@ -8841,8 +9981,10 @@
 	NDBG22(("mptsas_setup_bus_reset_delay"));
 	for (ptgt = refhash_first(mpt->m_targets); ptgt != NULL;
 	    ptgt = refhash_next(mpt->m_targets, ptgt)) {
+		mutex_enter(&ptgt->m_t_mutex);
 		mptsas_set_throttle(mpt, ptgt, HOLD_THROTTLE);
 		ptgt->m_reset_delay = mpt->m_scsi_reset_delay;
+		mutex_exit(&ptgt->m_t_mutex);
 	}
 
 	mptsas_start_watch_reset_delay();
@@ -8896,6 +10038,7 @@
 
 	for (ptgt = refhash_first(mpt->m_targets); ptgt != NULL;
 	    ptgt = refhash_next(mpt->m_targets, ptgt)) {
+		mutex_enter(&ptgt->m_t_mutex);
 		if (ptgt->m_reset_delay != 0) {
 			ptgt->m_reset_delay -=
 			    MPTSAS_WATCH_RESET_DELAY_TICK;
@@ -8908,6 +10051,7 @@
 				done = -1;
 			}
 		}
+		mutex_exit(&ptgt->m_t_mutex);
 	}
 
 	if (restart > 0) {
@@ -9124,6 +10268,7 @@
 mptsas_scsi_setcap(struct scsi_address *ap, char *cap, int value, int tgtonly)
 {
 	mptsas_t	*mpt = ADDR2MPT(ap);
+	mptsas_target_t	*ptgt;
 	int		ckey;
 	int		rval = FALSE;
 
@@ -9165,9 +10310,9 @@
 		}
 		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);
+		ptgt = ((mptsas_tgt_private_t *)
+		    (ap->a_hba_tran->tran_tgt_private))->t_private;
+		mptsas_set_throttle_mtx(mpt, ptgt, MAX_THROTTLE);
 		rval = TRUE;
 		break;
 	case SCSI_CAP_QFULL_RETRIES:
@@ -9255,7 +10400,7 @@
 /*
  * Error logging, printing, and debug print routines.
  */
-static char *mptsas_label = "mpt_sas";
+static char *mptsas_label = "mpt_sas3";
 
 /*PRINTFLIKE3*/
 void
@@ -9286,6 +10431,32 @@
 }
 
 #ifdef MPTSAS_DEBUG
+/*
+ * Use a circular buffer to log messages to private memory.
+ * No mutexes, so there is the opportunity for this to miss lines.
+ * But it's fast and does not hold up the proceedings too much.
+ */
+static char mptsas_dbglog_bufs[32][256];
+static uint32_t mptsas_dbglog_idx = 1;
+
+/*PRINTFLIKE1*/
+void
+mptsas_debug_log(char *fmt, ...)
+{
+	va_list		ap;
+	uint32_t	idx;
+
+	if (!mptsas_dbglog_idx) {
+		return;
+	}
+	idx = (mptsas_dbglog_idx++) & 0x1f;
+
+	va_start(ap, fmt);
+	(void) vsnprintf(mptsas_dbglog_bufs[idx],
+	    sizeof (mptsas_dbglog_bufs[0]), fmt, ap);
+	va_end(ap);
+}
+
 /*PRINTFLIKE1*/
 void
 mptsas_printf(char *fmt, ...)
@@ -9302,7 +10473,7 @@
 #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);
+	scsi_log(dev, mptsas_label, CE_CONT, "!%s\n", mptsas_log_buf);
 #endif
 	mutex_exit(&mptsas_log_mutex);
 }
@@ -9374,22 +10545,32 @@
 	mutex_exit(&mptsas_global_mutex);
 }
 
+int mptsas_monitor_for_txwqs = 1;
 static void
 mptsas_watchsubr(mptsas_t *mpt)
 {
 	int		i;
 	mptsas_cmd_t	*cmd;
 	mptsas_target_t	*ptgt = NULL;
+	hrtime_t	timestamp = gethrtime();
+	boolean_t	restart_hba = B_FALSE;
 
 	ASSERT(MUTEX_HELD(&mpt->m_mutex));
 
-	NDBG30(("mptsas_watchsubr: mpt=0x%p", (void *)mpt));
+	NDBG30(("mptsas_watchsubr: mpt=0x%p, ncmds %d, nstarted %d",
+	    (void *)mpt, mpt->m_ncmds, mpt->m_ncstarted));
 
-#ifdef MPTSAS_TEST
-	if (mptsas_enable_untagged) {
-		mptsas_test_untagged++;
+	mpt->m_lncstarted = mpt->m_ncstarted;
+	if (mpt->m_txwq_thread_n != 0 && mpt->m_txwq_enabled != BLOCKED &&
+	    mptsas_monitor_for_txwqs) {
+		i = mpt->m_ncstarted/mptsas_scsi_watchdog_tick;
+		if (i > mpt->m_txwq_thread_threshold) {
+			mpt->m_txwq_enabled = TRUE;
+		} else if (i < (mpt->m_txwq_thread_threshold>>1)) {
+			mpt->m_txwq_enabled = FALSE;
+		}
 	}
-#endif
+	mpt->m_ncstarted = 0;
 
 	/*
 	 * Check for commands stuck in active slot
@@ -9397,25 +10578,18 @@
 	 */
 	for (i = 0; i <= mpt->m_active->m_n_normal; 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) {
+			if (cmd->cmd_active_expiration <= timestamp) {
+				if ((cmd->cmd_flags & CFLAG_CMDIOC) == 0) {
 					/*
 					 * There seems to be a command stuck
 					 * in the active slot.  Drain throttle.
 					 */
-					mptsas_set_throttle(mpt,
-					    cmd->cmd_tgt_addr,
+					ptgt = cmd->cmd_tgt_addr;
+					mptsas_set_throttle_mtx(mpt, ptgt,
 					    DRAIN_THROTTLE);
-				}
-			}
-			if ((cmd->cmd_flags & CFLAG_PASSTHRU) ||
-			    (cmd->cmd_flags & CFLAG_CONFIG) ||
-			    (cmd->cmd_flags & CFLAG_FW_DIAG)) {
-				cmd->cmd_active_timeout -=
-				    mptsas_scsi_watchdog_tick;
-				if (cmd->cmd_active_timeout <= 0) {
+				} else if (cmd->cmd_flags &
+				    (CFLAG_PASSTHRU | CFLAG_CONFIG |
+				    CFLAG_FW_DIAG)) {
 					/*
 					 * passthrough command timeout
 					 */
@@ -9431,6 +10605,7 @@
 
 	for (ptgt = refhash_first(mpt->m_targets); ptgt != NULL;
 	    ptgt = refhash_next(mpt->m_targets, ptgt)) {
+		mutex_enter(&ptgt->m_t_mutex);
 		/*
 		 * If we were draining due to a qfull condition,
 		 * go back to full throttle.
@@ -9439,33 +10614,56 @@
 		    (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);
+			restart_hba = B_TRUE;
 		}
 
-		if ((ptgt->m_t_ncmds > 0) &&
-		    (ptgt->m_timebase)) {
-
-			if (ptgt->m_timebase <=
-			    mptsas_scsi_watchdog_tick) {
-				ptgt->m_timebase +=
-				    mptsas_scsi_watchdog_tick;
-				continue;
-			}
+		cmd = TAILQ_LAST(&ptgt->m_active_cmdq, mptsas_active_cmdq);
+		if (cmd != NULL) {
+			if (cmd->cmd_active_expiration <= timestamp) {
+				/*
+				 * Earliest command timeout expired.
+				 * Drain throttle.
+				 */
+				mptsas_set_throttle(mpt, ptgt, DRAIN_THROTTLE);
 
-			ptgt->m_timeout -= mptsas_scsi_watchdog_tick;
+				/*
+				 * Check for remaining commands.
+				 */
+				cmd = TAILQ_FIRST(&ptgt->m_active_cmdq);
+				if (cmd->cmd_active_expiration > timestamp) {
+					/*
+					 * Wait for remaining commands to
+					 * complete or time out.
+					 */
+					NDBG23(("command timed out, "
+					    "pending drain"));
+				} else {
+					mutex_exit(&ptgt->m_t_mutex);
 
-			if (ptgt->m_timeout < 0) {
-				mptsas_cmd_timeout(mpt, ptgt->m_devhdl);
-				continue;
-			}
+					/*
+					 * All command timeouts expired.
+					 */
+					mptsas_log(mpt, CE_NOTE,
+					    "Timeout of %d seconds "
+					    "expired with %d commands on "
+					    "target %d lun %d.",
+					    cmd->cmd_pkt->pkt_time,
+					    ptgt->m_t_ncmds,
+					    ptgt->m_devhdl, Lun(cmd));
 
-			if ((ptgt->m_timeout) <=
-			    mptsas_scsi_watchdog_tick) {
+					mptsas_cmd_timeout(mpt, ptgt);
+					continue;
+				}
+			} else if (cmd->cmd_active_expiration <= timestamp +
+			    (hrtime_t)mptsas_scsi_watchdog_tick * NANOSEC) {
 				NDBG23(("pending timeout"));
-				mptsas_set_throttle(mpt, ptgt,
-				    DRAIN_THROTTLE);
+				mptsas_set_throttle(mpt, ptgt, DRAIN_THROTTLE);
 			}
 		}
+		mutex_exit(&ptgt->m_t_mutex);
+	}
+	if (restart_hba == B_TRUE) {
+		mptsas_restart_hba(mpt);
 	}
 }
 
@@ -9473,16 +10671,29 @@
  * timeout recovery
  */
 static void
-mptsas_cmd_timeout(mptsas_t *mpt, uint16_t devhdl)
+mptsas_cmd_timeout(mptsas_t *mpt, mptsas_target_t *ptgt)
 {
+	uint16_t	devhdl;
+	uint64_t	sas_wwn;
+	uint8_t		phy;
+	char		wwn_str[MPTSAS_WWN_STRLEN];
+
+	devhdl = ptgt->m_devhdl;
+	sas_wwn = ptgt->m_addr.mta_wwn;
+	phy = ptgt->m_phynum;
+	if (sas_wwn == 0) {
+		(void) sprintf(wwn_str, "p%x", phy);
+	} else {
+		(void) sprintf(wwn_str, "w%016"PRIx64, sas_wwn);
+	}
 
 	NDBG29(("mptsas_cmd_timeout: target=%d", devhdl));
 	mptsas_log(mpt, CE_WARN, "Disconnected command timeout for "
-	    "Target %d", devhdl);
+	    "target %d %s,  enclosure %u .", devhdl, wwn_str,
+	    ptgt->m_enclosure);
 
 	/*
-	 * If the current target is not the target passed in,
-	 * try to reset that target.
+	 * Abort all outstanding commands on the device.
 	 */
 	NDBG29(("mptsas_cmd_timeout: device reset"));
 	if (mptsas_do_scsi_reset(mpt, devhdl) != TRUE) {
@@ -9531,7 +10742,7 @@
 	/* Set all the throttles to zero */
 	for (ptgt = refhash_first(mpt->m_targets); ptgt != NULL;
 	    ptgt = refhash_next(mpt->m_targets, ptgt)) {
-		mptsas_set_throttle(mpt, ptgt, HOLD_THROTTLE);
+		mptsas_set_throttle_mtx(mpt, ptgt, HOLD_THROTTLE);
 	}
 
 	/* If there are any outstanding commands in the queue */
@@ -9546,7 +10757,8 @@
 			mpt->m_softstate &= ~MPTSAS_SS_DRAINING;
 			for (ptgt = refhash_first(mpt->m_targets); ptgt != NULL;
 			    ptgt = refhash_next(mpt->m_targets, ptgt)) {
-				mptsas_set_throttle(mpt, ptgt, MAX_THROTTLE);
+				mptsas_set_throttle_mtx(mpt, ptgt,
+				    MAX_THROTTLE);
 			}
 			mptsas_restart_hba(mpt);
 			if (mpt->m_quiesce_timeid != 0) {
@@ -9583,7 +10795,7 @@
 	mpt->m_softstate &= ~MPTSAS_SS_QUIESCED;
 	for (ptgt = refhash_first(mpt->m_targets); ptgt != NULL;
 	    ptgt = refhash_next(mpt->m_targets, ptgt)) {
-		mptsas_set_throttle(mpt, ptgt, MAX_THROTTLE);
+		mptsas_set_throttle_mtx(mpt, ptgt, MAX_THROTTLE);
 	}
 	mptsas_restart_hba(mpt);
 	mutex_exit(&mpt->m_mutex);
@@ -9609,7 +10821,8 @@
 			 */
 			for (ptgt = refhash_first(mpt->m_targets); ptgt != NULL;
 			    ptgt = refhash_next(mpt->m_targets, ptgt)) {
-				mptsas_set_throttle(mpt, ptgt, HOLD_THROTTLE);
+				mptsas_set_throttle_mtx(mpt, ptgt,
+				    HOLD_THROTTLE);
 			}
 
 			mpt->m_quiesce_timeid = timeout(mptsas_ncmds_checkdrain,
@@ -9645,18 +10858,99 @@
 }
 
 static void
+mptsas_passthru_sge(ddi_acc_handle_t acc_hdl, mptsas_pt_request_t *pt,
+    pMpi2SGESimple64_t sgep)
+{
+	uint32_t		sge_flags;
+	uint32_t		data_size, dataout_size;
+	ddi_dma_cookie_t	data_cookie;
+	ddi_dma_cookie_t	dataout_cookie;
+
+	data_size = pt->data_size;
+	dataout_size = pt->dataout_size;
+	data_cookie = pt->data_cookie;
+	dataout_cookie = pt->dataout_cookie;
+
+	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 (pt->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));
+}
+
+static void
+mptsas_passthru_ieee_sge(ddi_acc_handle_t acc_hdl, mptsas_pt_request_t *pt,
+    pMpi2IeeeSgeSimple64_t ieeesgep)
+{
+	uint8_t			sge_flags;
+	uint32_t		data_size, dataout_size;
+	ddi_dma_cookie_t	data_cookie;
+	ddi_dma_cookie_t	dataout_cookie;
+
+	data_size = pt->data_size;
+	dataout_size = pt->dataout_size;
+	data_cookie = pt->data_cookie;
+	dataout_cookie = pt->dataout_cookie;
+
+	sge_flags = (MPI2_IEEE_SGE_FLAGS_SIMPLE_ELEMENT |
+	    MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR);
+	if (dataout_size) {
+		ddi_put32(acc_hdl, &ieeesgep->Length, dataout_size);
+		ddi_put32(acc_hdl, &ieeesgep->Address.Low,
+		    (uint32_t)(dataout_cookie.dmac_laddress &
+		    0xffffffffull));
+		ddi_put32(acc_hdl, &ieeesgep->Address.High,
+		    (uint32_t)(dataout_cookie.dmac_laddress >> 32));
+		ddi_put8(acc_hdl, &ieeesgep->Flags, sge_flags);
+		ieeesgep++;
+	}
+	sge_flags |= MPI25_IEEE_SGE_FLAGS_END_OF_LIST;
+	ddi_put32(acc_hdl, &ieeesgep->Length, data_size);
+	ddi_put32(acc_hdl, &ieeesgep->Address.Low,
+	    (uint32_t)(data_cookie.dmac_laddress & 0xffffffffull));
+	ddi_put32(acc_hdl, &ieeesgep->Address.High,
+	    (uint32_t)(data_cookie.dmac_laddress >> 32));
+	ddi_put8(acc_hdl, &ieeesgep->Flags, sge_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;
+	uint32_t		request_size;
+	uint64_t		request_desc = 0;
+	uint64_t		sense_bufp;
 	uint8_t			desc_type;
 	uint8_t			*request, function;
 	ddi_dma_handle_t	dma_hdl = mpt->m_dma_req_frame_hdl;
@@ -9665,12 +10959,7 @@
 	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
@@ -9680,54 +10969,24 @@
 	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);
-	}
+	bcopy(request, memp, request_size);
 
-	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));
+	NDBG15(("mptsas_start_passthru: Func 0x%x, MsgFlags 0x%x, "
+	    "size=%d, in %d, out %d", request_hdrp->Function,
+	    request_hdrp->MsgFlags, request_size,
+	    pt->data_size, pt->dataout_size));
+
+	/*
+	 * Add an SGE, even if the length is zero.
+	 */
+	if (mpt->m_MPI25 && pt->simple == 0) {
+		mptsas_passthru_ieee_sge(acc_hdl, pt,
+		    (pMpi2IeeeSgeSimple64_t)
+		    ((uint8_t *)request_hdrp + pt->sgl_offset));
+	} else {
+		mptsas_passthru_sge(acc_hdl, pt,
+		    (pMpi2SGESimple64_t)
+		    ((uint8_t *)request_hdrp + pt->sgl_offset));
 	}
 
 	function = request_hdrp->Function;
@@ -9735,6 +10994,7 @@
 	    (function == MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) {
 		pMpi2SCSIIORequest_t	scsi_io_req;
 
+		NDBG15(("mptsas_start_passthru: Is SCSI IO Req"));
 		scsi_io_req = (pMpi2SCSIIORequest_t)request_hdrp;
 		/*
 		 * Put SGE for data and data_out buffer at the end of
@@ -9746,8 +11006,8 @@
 		    &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 = (uint32_t)(mpt->m_req_frame_dma_addr +
+		    (mpt->m_req_frame_size * cmd->cmd_slot) & 0xffffffffull);
 		sense_bufp += 64;
 		ddi_put32(acc_hdl,
 		    &scsi_io_req->SenseBufferLowAddress, sense_bufp);
@@ -9765,8 +11025,8 @@
 		 */
 		if (function == MPI2_FUNCTION_SCSI_IO_REQUEST) {
 			desc_type = MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO;
-			request_desc_high = (ddi_get16(acc_hdl,
-			    &scsi_io_req->DevHandle) << 16);
+			request_desc = (((uint64_t)ddi_get16(acc_hdl,
+			    &scsi_io_req->DevHandle)) << 48);
 		}
 	}
 
@@ -9776,21 +11036,382 @@
 	 * finish.
 	 */
 	(void) ddi_dma_sync(dma_hdl, 0, 0, DDI_DMA_SYNC_FORDEV);
-	request_desc_low = (cmd->cmd_slot << 16) + desc_type;
+	request_desc |= ((cmd->cmd_slot << 16) | desc_type);
 	cmd->cmd_rfm = NULL;
-	MPTSAS_START_CMD(mpt, request_desc_low, request_desc_high);
+	MPTSAS_START_CMD(mpt, request_desc);
 	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);
 	}
 }
 
+typedef void (mps_pre_f)(mptsas_t *, mptsas_pt_request_t *);
+static mps_pre_f	mpi_pre_ioc_facts;
+static mps_pre_f	mpi_pre_port_facts;
+static mps_pre_f	mpi_pre_fw_download;
+static mps_pre_f	mpi_pre_fw_25_download;
+static mps_pre_f	mpi_pre_fw_upload;
+static mps_pre_f	mpi_pre_fw_25_upload;
+static mps_pre_f	mpi_pre_sata_passthrough;
+static mps_pre_f	mpi_pre_smp_passthrough;
+static mps_pre_f	mpi_pre_config;
+static mps_pre_f	mpi_pre_sas_io_unit_control;
+static mps_pre_f	mpi_pre_scsi_io_req;
+
+/*
+ * Prepare the pt for a SAS2 FW_DOWNLOAD request.
+ */
+static void
+mpi_pre_fw_download(mptsas_t *mpt, mptsas_pt_request_t *pt)
+{
+	pMpi2FWDownloadTCSGE_t tcsge;
+	pMpi2FWDownloadRequest req;
+
+	/*
+	 * If SAS3, call separate function.
+	 */
+	if (mpt->m_MPI25) {
+		mpi_pre_fw_25_download(mpt, pt);
+		return;
+	}
+
+	/*
+	 * User requests should come in with the Transaction
+	 * context element where the SGL will go. Putting the
+	 * SGL after that seems to work, but don't really know
+	 * why. Other drivers tend to create an extra SGL and
+	 * refer to the TCE through that.
+	 */
+	req = (pMpi2FWDownloadRequest)pt->request;
+	tcsge = (pMpi2FWDownloadTCSGE_t)&req->SGL;
+	if (tcsge->ContextSize != 0 || tcsge->DetailsLength != 12 ||
+	    tcsge->Flags != MPI2_SGE_FLAGS_TRANSACTION_ELEMENT) {
+		mptsas_log(mpt, CE_WARN, "FW Download tce invalid!");
+	}
+
+	pt->sgl_offset = offsetof(MPI2_FW_DOWNLOAD_REQUEST, SGL) +
+	    sizeof (*tcsge);
+	if (pt->request_size != pt->sgl_offset)
+		NDBG15(("mpi_pre_fw_download(): Incorrect req size, "
+		    "0x%x, should be 0x%x, dataoutsz 0x%x",
+		    (int)pt->request_size, (int)pt->sgl_offset,
+		    (int)pt->dataout_size));
+	if (pt->data_size < sizeof (MPI2_FW_DOWNLOAD_REPLY))
+		NDBG15(("mpi_pre_fw_download(): Incorrect rep size, "
+		    "0x%x, should be 0x%x", pt->data_size,
+		    (int)sizeof (MPI2_FW_DOWNLOAD_REPLY)));
+}
+
+/*
+ * Prepare the pt for a SAS3 FW_DOWNLOAD request.
+ */
+static void
+mpi_pre_fw_25_download(mptsas_t *mpt, mptsas_pt_request_t *pt)
+{
+	pMpi2FWDownloadTCSGE_t tcsge;
+	pMpi2FWDownloadRequest req2;
+	pMpi25FWDownloadRequest req25;
+
+	/*
+	 * User requests should come in with the Transaction
+	 * context element where the SGL will go. The new firmware
+	 * Doesn't use TCE and has space in the main request for
+	 * this information. So move to the right place.
+	 */
+	req2 = (pMpi2FWDownloadRequest)pt->request;
+	req25 = (pMpi25FWDownloadRequest)pt->request;
+	tcsge = (pMpi2FWDownloadTCSGE_t)&req2->SGL;
+	if (tcsge->ContextSize != 0 || tcsge->DetailsLength != 12 ||
+	    tcsge->Flags != MPI2_SGE_FLAGS_TRANSACTION_ELEMENT) {
+		mptsas_log(mpt, CE_WARN, "FW Download tce invalid!");
+	}
+	req25->ImageOffset = tcsge->ImageOffset;
+	req25->ImageSize = tcsge->ImageSize;
+
+	pt->sgl_offset = offsetof(MPI25_FW_DOWNLOAD_REQUEST, SGL);
+	if (pt->request_size != pt->sgl_offset)
+		NDBG15(("mpi_pre_fw_25_download(): Incorrect req size, "
+		    "0x%x, should be 0x%x, dataoutsz 0x%x",
+		    pt->request_size, pt->sgl_offset,
+		    pt->dataout_size));
+	if (pt->data_size < sizeof (MPI2_FW_DOWNLOAD_REPLY))
+		NDBG15(("mpi_pre_fw_25_download(): Incorrect rep size, "
+		    "0x%x, should be 0x%x", pt->data_size,
+		    (int)sizeof (MPI2_FW_UPLOAD_REPLY)));
+}
+
+/*
+ * Prepare the pt for a SAS2 FW_UPLOAD request.
+ */
+static void
+mpi_pre_fw_upload(mptsas_t *mpt, mptsas_pt_request_t *pt)
+{
+	pMpi2FWUploadTCSGE_t tcsge;
+	pMpi2FWUploadRequest_t req;
+
+	/*
+	 * If SAS3, call separate function.
+	 */
+	if (mpt->m_MPI25) {
+		mpi_pre_fw_25_upload(mpt, pt);
+		return;
+	}
+
+	/*
+	 * User requests should come in with the Transaction
+	 * context element where the SGL will go. Putting the
+	 * SGL after that seems to work, but don't really know
+	 * why. Other drivers tend to create an extra SGL and
+	 * refer to the TCE through that.
+	 */
+	req = (pMpi2FWUploadRequest_t)pt->request;
+	tcsge = (pMpi2FWUploadTCSGE_t)&req->SGL;
+	if (tcsge->ContextSize != 0 || tcsge->DetailsLength != 12 ||
+	    tcsge->Flags != MPI2_SGE_FLAGS_TRANSACTION_ELEMENT) {
+		mptsas_log(mpt, CE_WARN, "FW Upload tce invalid!");
+	}
+
+	pt->sgl_offset = offsetof(MPI2_FW_UPLOAD_REQUEST, SGL) +
+	    sizeof (*tcsge);
+	if (pt->request_size != pt->sgl_offset)
+		NDBG15(("mpi_pre_fw_upload(): Incorrect req size, "
+		    "0x%x, should be 0x%x, dataoutsz 0x%x",
+		    pt->request_size, pt->sgl_offset,
+		    pt->dataout_size));
+	if (pt->data_size < sizeof (MPI2_FW_UPLOAD_REPLY))
+		NDBG15(("mpi_pre_fw_upload(): Incorrect rep size, "
+		    "0x%x, should be 0x%x", pt->data_size,
+		    (int)sizeof (MPI2_FW_UPLOAD_REPLY)));
+}
+
+/*
+ * Prepare the pt a SAS3 FW_UPLOAD request.
+ */
+static void
+mpi_pre_fw_25_upload(mptsas_t *mpt, mptsas_pt_request_t *pt)
+{
+	pMpi2FWUploadTCSGE_t tcsge;
+	pMpi2FWUploadRequest_t req2;
+	pMpi25FWUploadRequest_t req25;
+
+	/*
+	 * User requests should come in with the Transaction
+	 * context element where the SGL will go. The new firmware
+	 * Doesn't use TCE and has space in the main request for
+	 * this information. So move to the right place.
+	 */
+	req2 = (pMpi2FWUploadRequest_t)pt->request;
+	req25 = (pMpi25FWUploadRequest_t)pt->request;
+	tcsge = (pMpi2FWUploadTCSGE_t)&req2->SGL;
+	if (tcsge->ContextSize != 0 || tcsge->DetailsLength != 12 ||
+	    tcsge->Flags != MPI2_SGE_FLAGS_TRANSACTION_ELEMENT) {
+		mptsas_log(mpt, CE_WARN, "FW Upload tce invalid!");
+	}
+	req25->ImageOffset = tcsge->ImageOffset;
+	req25->ImageSize = tcsge->ImageSize;
+
+	pt->sgl_offset = offsetof(MPI25_FW_UPLOAD_REQUEST, SGL);
+	if (pt->request_size != pt->sgl_offset)
+		NDBG15(("mpi_pre_fw_25_upload(): Incorrect req size, "
+		    "0x%x, should be 0x%x, dataoutsz 0x%x",
+		    pt->request_size, pt->sgl_offset,
+		    pt->dataout_size));
+	if (pt->data_size < sizeof (MPI2_FW_UPLOAD_REPLY))
+		NDBG15(("mpi_pre_fw_25_upload(): Incorrect rep size, "
+		    "0x%x, should be 0x%x", pt->data_size,
+		    (int)sizeof (MPI2_FW_UPLOAD_REPLY)));
+}
+
+/*
+ * Prepare the pt for an IOC_FACTS request.
+ */
+static void
+mpi_pre_ioc_facts(mptsas_t *mpt, mptsas_pt_request_t *pt)
+{
+#ifndef __lock_lint
+	_NOTE(ARGUNUSED(mpt))
+#endif
+	if (pt->request_size != sizeof (MPI2_IOC_FACTS_REQUEST))
+		NDBG15(("mpi_pre_ioc_facts(): Incorrect req size, "
+		    "0x%x, should be 0x%x, dataoutsz 0x%x",
+		    pt->request_size,
+		    (int)sizeof (MPI2_IOC_FACTS_REQUEST),
+		    pt->dataout_size));
+	if (pt->data_size != sizeof (MPI2_IOC_FACTS_REPLY))
+		NDBG15(("mpi_pre_ioc_facts(): Incorrect rep size, "
+		    "0x%x, should be 0x%x", pt->data_size,
+		    (int)sizeof (MPI2_IOC_FACTS_REPLY)));
+	pt->sgl_offset = (uint16_t)pt->request_size;
+}
+
+/*
+ * Prepare the pt for a PORT_FACTS request.
+ */
+static void
+mpi_pre_port_facts(mptsas_t *mpt, mptsas_pt_request_t *pt)
+{
+#ifndef __lock_lint
+	_NOTE(ARGUNUSED(mpt))
+#endif
+	if (pt->request_size != sizeof (MPI2_PORT_FACTS_REQUEST))
+		NDBG15(("mpi_pre_port_facts(): Incorrect req size, "
+		    "0x%x, should be 0x%x, dataoutsz 0x%x",
+		    pt->request_size,
+		    (int)sizeof (MPI2_PORT_FACTS_REQUEST),
+		    pt->dataout_size));
+	if (pt->data_size != sizeof (MPI2_PORT_FACTS_REPLY))
+		NDBG15(("mpi_pre_port_facts(): Incorrect rep size, "
+		    "0x%x, should be 0x%x", pt->data_size,
+		    (int)sizeof (MPI2_PORT_FACTS_REPLY)));
+	pt->sgl_offset = (uint16_t)pt->request_size;
+}
+
+/*
+ * Prepare pt for a SATA_PASSTHROUGH request.
+ */
+static void
+mpi_pre_sata_passthrough(mptsas_t *mpt, mptsas_pt_request_t *pt)
+{
+#ifndef __lock_lint
+	_NOTE(ARGUNUSED(mpt))
+#endif
+	pt->sgl_offset = offsetof(MPI2_SATA_PASSTHROUGH_REQUEST, SGL);
+	if (pt->request_size != pt->sgl_offset)
+		NDBG15(("mpi_pre_sata_passthrough(): Incorrect req size, "
+		    "0x%x, should be 0x%x, dataoutsz 0x%x",
+		    pt->request_size, pt->sgl_offset,
+		    pt->dataout_size));
+	if (pt->data_size != sizeof (MPI2_SATA_PASSTHROUGH_REPLY))
+		NDBG15(("mpi_pre_sata_passthrough(): Incorrect rep size, "
+		    "0x%x, should be 0x%x", pt->data_size,
+		    (int)sizeof (MPI2_SATA_PASSTHROUGH_REPLY)));
+}
+
+static void
+mpi_pre_smp_passthrough(mptsas_t *mpt, mptsas_pt_request_t *pt)
+{
+#ifndef __lock_lint
+	_NOTE(ARGUNUSED(mpt))
+#endif
+	pt->sgl_offset = offsetof(MPI2_SMP_PASSTHROUGH_REQUEST, SGL);
+	if (pt->request_size != pt->sgl_offset)
+		NDBG15(("mpi_pre_smp_passthrough(): Incorrect req size, "
+		    "0x%x, should be 0x%x, dataoutsz 0x%x",
+		    pt->request_size, pt->sgl_offset,
+		    pt->dataout_size));
+	if (pt->data_size != sizeof (MPI2_SMP_PASSTHROUGH_REPLY))
+		NDBG15(("mpi_pre_smp_passthrough(): Incorrect rep size, "
+		    "0x%x, should be 0x%x", pt->data_size,
+		    (int)sizeof (MPI2_SMP_PASSTHROUGH_REPLY)));
+}
+
+/*
+ * Prepare pt for a CONFIG request.
+ */
+static void
+mpi_pre_config(mptsas_t *mpt, mptsas_pt_request_t *pt)
+{
+#ifndef __lock_lint
+	_NOTE(ARGUNUSED(mpt))
+#endif
+	pt->sgl_offset = offsetof(MPI2_CONFIG_REQUEST, PageBufferSGE);
+	if (pt->request_size != pt->sgl_offset)
+		NDBG15(("mpi_pre_config(): Incorrect req size, 0x%x, "
+		    "should be 0x%x, dataoutsz 0x%x", pt->request_size,
+		    pt->sgl_offset, pt->dataout_size));
+	if (pt->data_size != sizeof (MPI2_CONFIG_REPLY))
+		NDBG15(("mpi_pre_config(): Incorrect rep size, 0x%x, "
+		    "should be 0x%x", pt->data_size,
+		    (int)sizeof (MPI2_CONFIG_REPLY)));
+	pt->simple = 1;
+}
+
+/*
+ * Prepare pt for a SCSI_IO_REQ request.
+ */
+static void
+mpi_pre_scsi_io_req(mptsas_t *mpt, mptsas_pt_request_t *pt)
+{
+#ifndef __lock_lint
+	_NOTE(ARGUNUSED(mpt))
+#endif
+	pt->sgl_offset = offsetof(MPI2_SCSI_IO_REQUEST, SGL);
+	if (pt->request_size != pt->sgl_offset)
+		NDBG15(("mpi_pre_config(): Incorrect req size, 0x%x, "
+		    "should be 0x%x, dataoutsz 0x%x", pt->request_size,
+		    pt->sgl_offset,
+		    pt->dataout_size));
+	if (pt->data_size != sizeof (MPI2_SCSI_IO_REPLY))
+		NDBG15(("mpi_pre_config(): Incorrect rep size, 0x%x, "
+		    "should be 0x%x", pt->data_size,
+		    (int)sizeof (MPI2_SCSI_IO_REPLY)));
+}
+
+/*
+ * Prepare the mps_command for a SAS_IO_UNIT_CONTROL request.
+ */
+static void
+mpi_pre_sas_io_unit_control(mptsas_t *mpt, mptsas_pt_request_t *pt)
+{
+#ifndef __lock_lint
+	_NOTE(ARGUNUSED(mpt))
+#endif
+	pt->sgl_offset = (uint16_t)pt->request_size;
+}
+
+/*
+ * A set of functions to prepare an mps_command for the various
+ * supported requests.
+ */
+struct mps_func {
+	U8		Function;
+	char		*Name;
+	mps_pre_f	*f_pre;
+} mps_func_list[] = {
+	{ MPI2_FUNCTION_IOC_FACTS, "IOC_FACTS",		mpi_pre_ioc_facts },
+	{ MPI2_FUNCTION_PORT_FACTS, "PORT_FACTS",	mpi_pre_port_facts },
+	{ MPI2_FUNCTION_FW_DOWNLOAD, "FW_DOWNLOAD",	mpi_pre_fw_download },
+	{ MPI2_FUNCTION_FW_UPLOAD, "FW_UPLOAD",		mpi_pre_fw_upload },
+	{ MPI2_FUNCTION_SATA_PASSTHROUGH, "SATA_PASSTHROUGH",
+	    mpi_pre_sata_passthrough },
+	{ MPI2_FUNCTION_SMP_PASSTHROUGH, "SMP_PASSTHROUGH",
+	    mpi_pre_smp_passthrough},
+	{ MPI2_FUNCTION_SCSI_IO_REQUEST, "SCSI_IO_REQUEST",
+	    mpi_pre_scsi_io_req},
+	{ MPI2_FUNCTION_CONFIG, "CONFIG",		mpi_pre_config},
+	{ MPI2_FUNCTION_SAS_IO_UNIT_CONTROL, "SAS_IO_UNIT_CONTROL",
+	    mpi_pre_sas_io_unit_control },
+	{ 0xFF, NULL,				NULL } /* list end */
+};
+
+static void
+mptsas_prep_sgl_offset(mptsas_t *mpt, mptsas_pt_request_t *pt)
+{
+	pMPI2RequestHeader_t	hdr;
+	struct mps_func		*f;
+
+	hdr = (pMPI2RequestHeader_t)pt->request;
+
+	for (f = mps_func_list; f->f_pre != NULL; f++) {
+		if (hdr->Function == f->Function) {
+			f->f_pre(mpt, pt);
+			NDBG15(("mptsas_prep_sgl_offset: Function %s,"
+			    " sgl_offset 0x%x", f->Name,
+			    pt->sgl_offset));
+			return;
+		}
+	}
+	NDBG15(("mptsas_prep_sgl_offset: Unknown Function 0x%02x,"
+	    " returning req_size 0x%x for sgl_offset",
+	    hdr->Function, pt->request_size));
+	pt->sgl_offset = (uint16_t)pt->request_size;
+}
 
 
 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 data_size, uint8_t direction, uint8_t *dataout,
     uint32_t dataout_size, short timeout, int mode)
 {
 	mptsas_pt_request_t		pt;
@@ -9867,6 +11488,8 @@
 			mutex_enter(&mpt->m_mutex);
 		}
 	}
+	else
+		bzero(&data_dma_state, sizeof (data_dma_state));
 
 	if (dataout_size != 0) {
 		dataout_dma_state.size = dataout_size;
@@ -9890,6 +11513,8 @@
 		}
 		mutex_enter(&mpt->m_mutex);
 	}
+	else
+		bzero(&dataout_dma_state, sizeof (dataout_dma_state));
 
 	if ((rvalue = (mptsas_request_from_pool(mpt, &cmd, &pkt))) == -1) {
 		status = EAGAIN;
@@ -9906,11 +11531,13 @@
 
 	pt.request = (uint8_t *)request_msg;
 	pt.direction = direction;
+	pt.simple = 0;
 	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;
+	mptsas_prep_sgl_offset(mpt, &pt);
 
 	/*
 	 * Form a blank cmd/pkt to store the acknowledgement message
@@ -9967,7 +11594,7 @@
 		    DDI_DMA_SYNC_FORCPU);
 		reply_msg = (pMPI2DefaultReply_t)
 		    (mpt->m_reply_frame + (cmd->cmd_rfm -
-		    mpt->m_reply_frame_dma_addr));
+		    (mpt->m_reply_frame_dma_addr&0xfffffffful)));
 	}
 
 	mptsas_fma_check(mpt, cmd);
@@ -10123,7 +11750,7 @@
 		    (uint8_t *)((uintptr_t)data->PtrReply),
 		    (uint8_t *)((uintptr_t)data->PtrData),
 		    data->RequestSize, data->ReplySize,
-		    data->DataSize, data->DataDirection,
+		    data->DataSize, (uint8_t)data->DataDirection,
 		    (uint8_t *)((uintptr_t)data->PtrDataOut),
 		    data->DataOutSize, data->Timeout, mode));
 	} else {
@@ -10152,7 +11779,8 @@
 	pMpi2DiagReleaseRequest_t	pDiag_release_msg;
 	struct scsi_pkt			*pkt = cmd->cmd_pkt;
 	mptsas_diag_request_t		*diag = pkt->pkt_ha_private;
-	uint32_t			request_desc_low, i;
+	uint32_t			i;
+	uint64_t			request_desc;
 
 	ASSERT(mutex_owned(&mpt->m_mutex));
 
@@ -10205,10 +11833,10 @@
 	 */
 	(void) ddi_dma_sync(mpt->m_dma_req_frame_hdl, 0, 0,
 	    DDI_DMA_SYNC_FORDEV);
-	request_desc_low = (cmd->cmd_slot << 16) +
+	request_desc = (cmd->cmd_slot << 16) |
 	    MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
 	cmd->cmd_rfm = NULL;
-	MPTSAS_START_CMD(mpt, request_desc_low, 0);
+	MPTSAS_START_CMD(mpt, request_desc);
 	if ((mptsas_check_dma_handle(mpt->m_dma_req_frame_hdl) !=
 	    DDI_SUCCESS) ||
 	    (mptsas_check_acc_handle(mpt->m_acc_req_frame_hdl) !=
@@ -10306,7 +11934,8 @@
 		(void) ddi_dma_sync(mpt->m_dma_reply_frame_hdl, 0, 0,
 		    DDI_DMA_SYNC_FORCPU);
 		reply = (pMpi2DiagBufferPostReply_t)(mpt->m_reply_frame +
-		    (cmd->cmd_rfm - mpt->m_reply_frame_dma_addr));
+		    (cmd->cmd_rfm -
+		    (mpt->m_reply_frame_dma_addr&0xfffffffful)));
 
 		/*
 		 * Get the reply message data
@@ -10460,7 +12089,8 @@
 		(void) ddi_dma_sync(mpt->m_dma_reply_frame_hdl, 0, 0,
 		    DDI_DMA_SYNC_FORCPU);
 		reply = (pMpi2DiagReleaseReply_t)(mpt->m_reply_frame +
-		    (cmd->cmd_rfm - mpt->m_reply_frame_dma_addr));
+		    (cmd->cmd_rfm -
+		    (mpt->m_reply_frame_dma_addr&0xfffffffful)));
 
 		/*
 		 * Get the reply message data
@@ -11208,7 +12838,7 @@
 	char	*driver_verstr = MPTSAS_MOD_STRING;
 
 	mptsas_lookup_pci_data(mpt, adapter_data);
-	adapter_data->AdapterType = MPTIOCTL_ADAPTER_TYPE_SAS2;
+	adapter_data->AdapterType = MPTIOCTL_ADAPTER_TYPE_SAS3;
 	adapter_data->PCIDeviceHwId = (uint32_t)mpt->m_devid;
 	adapter_data->PCIDeviceHwRev = (uint32_t)mpt->m_revid;
 	adapter_data->SubSystemId = (uint32_t)mpt->m_ssid;
@@ -11482,7 +13112,7 @@
 		return (EPERM);
 	}
 
-	mpt = ddi_get_soft_state(mptsas_state, MINOR2INST(getminor(dev)));
+	mpt = ddi_get_soft_state(mptsas3_state, MINOR2INST(getminor(dev)));
 	if (mpt == NULL) {
 		/*
 		 * Called from iport node, get the states
@@ -11503,7 +13133,7 @@
 			if (pm_raise_power(mpt->m_dip, 0, PM_LEVEL_D0) !=
 			    DDI_SUCCESS) {
 				mptsas_log(mpt, CE_WARN,
-				    "mptsas%d: mptsas_ioctl: Raise power "
+				    "mptsas3%d: mptsas_ioctl: Raise power "
 				    "request failed.", mpt->m_instance);
 				(void) pm_idle_component(mpt->m_dip, 0);
 				return (ENXIO);
@@ -11743,7 +13373,7 @@
 	 */
 	for (ptgt = refhash_first(mpt->m_targets); ptgt != NULL;
 	    ptgt = refhash_next(mpt->m_targets, ptgt)) {
-		mptsas_set_throttle(mpt, ptgt, HOLD_THROTTLE);
+		mptsas_set_throttle_mtx(mpt, ptgt, HOLD_THROTTLE);
 	}
 
 	/*
@@ -11781,7 +13411,7 @@
 	 */
 	for (ptgt = refhash_first(mpt->m_targets); ptgt != NULL;
 	    ptgt = refhash_next(mpt->m_targets, ptgt)) {
-		mptsas_set_throttle(mpt, ptgt, MAX_THROTTLE);
+		mptsas_set_throttle_mtx(mpt, ptgt, MAX_THROTTLE);
 	}
 
 	mptsas_doneq_empty(mpt);
@@ -11804,7 +13434,8 @@
 mptsas_init_chip(mptsas_t *mpt, int first_time)
 {
 	ddi_dma_cookie_t	cookie;
-	uint32_t		i;
+	mptsas_reply_pqueue_t	*rpqp;
+	uint32_t		i, j;
 	int			rval;
 
 	/*
@@ -11847,6 +13478,16 @@
 		goto fail;
 	}
 
+	/*
+	 * Now we know chip MSIX capabilitites and it's not been done
+	 * previously register interrupts accordingly. Need to know this
+	 * information before allocating the reply frames below.
+	 */
+	if (mpt->m_intr_cnt == 0) {
+		if (mptsas_register_intrs(mpt) == FALSE)
+			goto fail;
+	}
+
 	mpt->m_targets = refhash_create(MPTSAS_TARGET_BUCKET_COUNT,
 	    mptsas_target_addr_hash, mptsas_target_addr_cmp,
 	    mptsas_target_free, sizeof (mptsas_target_t),
@@ -11864,6 +13505,10 @@
 		mptsas_log(mpt, CE_WARN, "mptsas_alloc_request_frames failed");
 		goto fail;
 	}
+	if (mptsas_alloc_sense_bufs(mpt) == DDI_FAILURE) {
+		mptsas_log(mpt, CE_WARN, "mptsas_alloc_sense_bufs failed");
+		goto fail;
+	}
 	if (mptsas_alloc_free_queue(mpt) == DDI_FAILURE) {
 		mptsas_log(mpt, CE_WARN, "mptsas_alloc_free_queue failed!");
 		goto fail;
@@ -11889,16 +13534,10 @@
 	mptsas_alloc_reply_args(mpt);
 
 	/*
-	 * Initialize reply post index.  Reply free index is initialized after
-	 * the next loop.
-	 */
-	mpt->m_post_index = 0;
-
-	/*
 	 * Initialize the Reply Free Queue with the physical addresses of our
 	 * reply frames.
 	 */
-	cookie.dmac_address = mpt->m_reply_frame_dma_addr;
+	cookie.dmac_address = mpt->m_reply_frame_dma_addr&0xfffffffful;
 	for (i = 0; i < mpt->m_max_replies; i++) {
 		ddi_put32(mpt->m_acc_free_queue_hdl,
 		    &((uint32_t *)(void *)mpt->m_free_queue)[i],
@@ -11916,17 +13555,31 @@
 	ddi_put32(mpt->m_datap, &mpt->m_reg->ReplyFreeHostIndex, i);
 
 	/*
-	 * Initialize the reply post queue to 0xFFFFFFFF,0xFFFFFFFF's.
+	 * Initialize the reply post queue to 0xFFFFFFFF,0xFFFFFFFF's
+	 * and the indexes to 0.
 	 */
-	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);
+	rpqp = mpt->m_rep_post_queues;
+	for (j = 0; j < mpt->m_post_reply_qcount; j++) {
+		for (i = 0; i < mpt->m_post_queue_depth; i++) {
+			ddi_put64(mpt->m_acc_post_queue_hdl,
+			    &((uint64_t *)(void *)rpqp->rpq_queue)[i],
+			    0xFFFFFFFFFFFFFFFF);
+		}
+		rpqp->rpq_index = 0;
+		rpqp++;
 	}
 	(void) ddi_dma_sync(mpt->m_dma_post_queue_hdl, 0, 0,
 	    DDI_DMA_SYNC_FORDEV);
 
 	/*
+	 * Initialise all the reply post queue indexes.
+	 */
+	for (j = 0; j < mpt->m_post_reply_qcount; j++) {
+		ddi_put32(mpt->m_datap, &mpt->m_reg->ReplyPostHostIndex,
+		    j << MPI2_RPHI_MSIX_INDEX_SHIFT);
+	}
+
+	/*
 	 * Enable ports
 	 */
 	if (mptsas_ioc_enable_port(mpt) == DDI_FAILURE) {
@@ -11938,6 +13591,8 @@
 	 * enable events
 	 */
 	if (mptsas_ioc_enable_event_notification(mpt)) {
+		mptsas_log(mpt, CE_WARN,
+		    "mptsas_ioc_enable_event_notification failed");
 		goto fail;
 	}
 
@@ -11948,6 +13603,8 @@
 
 	if ((mptsas_check_dma_handle(mpt->m_dma_req_frame_hdl) !=
 	    DDI_SUCCESS) ||
+	    (mptsas_check_dma_handle(mpt->m_dma_req_sense_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) !=
@@ -11964,6 +13621,8 @@
 	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_req_sense_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) !=
@@ -12032,26 +13691,36 @@
 		switch (cap) {
 			case PCI_CAP_ID_PM:
 				mptsas_log(mpt, CE_NOTE,
-				    "?mptsas%d supports power management.\n",
+				    "?mptsas3%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;
+			case PCI_CAP_ID_MSI:
+				mptsas_log(mpt, CE_NOTE,
+				    "?mptsas3%d supports MSI.\n",
+				    mpt->m_instance);
+				mpt->m_options |= MPTSAS_OPT_MSI;
+				break;
+			case PCI_CAP_ID_MSI_X:
+				mptsas_log(mpt, CE_NOTE,
+				    "?mptsas3%d supports MSI-X.\n",
+				    mpt->m_instance);
+				mpt->m_options |= MPTSAS_OPT_MSI_X;
+				break;
 			/*
 			 * The following capabilities are valid.  Any others
 			 * will cause a message to be logged.
 			 */
 			case PCI_CAP_ID_VPD:
-			case PCI_CAP_ID_MSI:
 			case PCI_CAP_ID_PCIX:
 			case PCI_CAP_ID_PCI_E:
-			case PCI_CAP_ID_MSI_X:
 				break;
 			default:
 				mptsas_log(mpt, CE_NOTE,
-				    "?mptsas%d unrecognized capability "
+				    "?mptsas3%d unrecognized capability "
 				    "0x%x.\n", mpt->m_instance, cap);
 				break;
 		}
@@ -12077,9 +13746,6 @@
 			};
 	uint16_t	pmcsr_stat;
 
-	if (mptsas_get_pci_cap(mpt) == FALSE) {
-		return (DDI_FAILURE);
-	}
 	/*
 	 * If PCI's capability does not support PM, then don't need
 	 * to registe the pm-components
@@ -12090,13 +13756,13 @@
 	 * 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);
+	(void) sprintf(pmc_name, "NAME=mptsas3%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.",
+		    "mptsas3%d: pm-component property creation failed.",
 		    mpt->m_instance);
 		return (DDI_FAILURE);
 	}
@@ -12108,7 +13774,7 @@
 	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",
+		mptsas_log(mpt, CE_WARN, "mptsas3%d: Power up the device",
 		    mpt->m_instance);
 		pci_config_put16(mpt->m_config_handle, mpt->m_pmcsr_offset,
 		    PCI_PMCSR_D0);
@@ -12145,22 +13811,33 @@
 	NDBG6(("ddi_intr_get_supported_types() returned: 0x%x", intr_types));
 
 	/*
+	 * Try MSIX first.
+	 */
+	if (mptsas_enable_msix && (intr_types & DDI_INTR_TYPE_MSIX)) {
+		if (mptsas_add_intrs(mpt, DDI_INTR_TYPE_MSIX) == DDI_SUCCESS) {
+			NDBG6(("Using MSI-X interrupt type"));
+			mpt->m_intr_type = DDI_INTR_TYPE_MSIX;
+			return (TRUE);
+		}
+	}
+
+	/*
 	 * Try MSI, but fall back to FIXED
 	 */
 	if (mptsas_enable_msi && (intr_types & DDI_INTR_TYPE_MSI)) {
 		if (mptsas_add_intrs(mpt, DDI_INTR_TYPE_MSI) == DDI_SUCCESS) {
-			NDBG0(("Using MSI interrupt type"));
+			NDBG6(("Using MSI interrupt type"));
 			mpt->m_intr_type = DDI_INTR_TYPE_MSI;
 			return (TRUE);
 		}
 	}
 	if (intr_types & DDI_INTR_TYPE_FIXED) {
 		if (mptsas_add_intrs(mpt, DDI_INTR_TYPE_FIXED) == DDI_SUCCESS) {
-			NDBG0(("Using FIXED interrupt type"));
+			NDBG6(("Using FIXED interrupt type"));
 			mpt->m_intr_type = DDI_INTR_TYPE_FIXED;
 			return (TRUE);
 		} else {
-			NDBG0(("FIXED interrupt registration failed"));
+			NDBG6(("FIXED interrupt registration failed"));
 			return (FALSE);
 		}
 	}
@@ -12197,7 +13874,7 @@
 		return (DDI_FAILURE);
 	}
 
-	/* Get number of available interrupts */
+	/* Get number of interrupts available to this device */
 	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, "
@@ -12206,25 +13883,47 @@
 		return (DDI_FAILURE);
 	}
 
-	if (avail < count) {
+	if (count < avail) {
 		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;
+	NDBG6(("mptsas_add_intrs:count %d, avail %d", count, avail));
+
+	if (intr_type == DDI_INTR_TYPE_MSIX) {
+		if (!mptsas3_max_msix_intrs) {
+			return (DDI_FAILURE);
+		}
+
+		/*
+		 * Restrict the number of interrupts, firstly by
+		 * the number returned from the IOCInfo, then by
+		 * overall restriction.
+		 */
+		if (avail > mpt->m_max_msix_vectors) {
+			avail = mpt->m_max_msix_vectors?
+			    mpt->m_max_msix_vectors:1;
+			NDBG6(("mptsas_add_intrs: mmmv avail %d", avail));
+		}
+		if (avail > mptsas3_max_msix_intrs) {
+			avail = mptsas3_max_msix_intrs;
+			NDBG6(("mptsas_add_intrs: m3mmi avail %d", avail));
+		}
+	}
+	if (intr_type == DDI_INTR_TYPE_MSI) {
+		NDBG6(("mptsas_add_intrs: MSI avail %d", avail));
+		avail = 1;
 	}
 
 	/* Allocate an array of interrupt handles */
-	mpt->m_intr_size = count * sizeof (ddi_intr_handle_t);
+	mpt->m_intr_size = avail * 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);
+	    avail, &actual, flag);
 
 	if ((ret != DDI_SUCCESS) || (actual == 0)) {
 		mptsas_log(mpt, CE_WARN, "ddi_intr_alloc() failed, ret %d\n",
@@ -12233,14 +13932,14 @@
 		return (DDI_FAILURE);
 	}
 
+	NDBG6(("mptsas_add_intrs: actual %d, avail %d", actual, avail));
 	/* use interrupt count returned or abort? */
-	if (actual < count) {
-		mptsas_log(mpt, CE_NOTE, "Requested: %d, Received: %d\n",
-		    count, actual);
+	if (actual < avail) {
+		mptsas_log(mpt, CE_NOTE,
+		    "Interrupts requested: %d, received: %d\n",
+		    avail, actual);
 	}
 
-	mpt->m_intr_cnt = actual;
-
 	/*
 	 * Get priority for first msi, assume remaining are all the same
 	 */
@@ -12301,6 +14000,8 @@
 		return (DDI_FAILURE);
 	}
 
+	mpt->m_intr_cnt = actual;
+
 	/*
 	 * Enable interrupts
 	 */
@@ -12313,6 +14014,22 @@
 			(void) ddi_intr_enable(mpt->m_htable[i]);
 		}
 	}
+
+	switch (intr_type) {
+	case DDI_INTR_TYPE_MSIX:
+		mptsas_log(mpt, CE_NOTE, "?Using %d MSI-X interrupt(s) "
+		    "(Available sys %d, mpt %d, Requested %d)\n",
+		    actual, count, mpt->m_max_msix_vectors, avail);
+		break;
+	case DDI_INTR_TYPE_MSI:
+		mptsas_log(mpt, CE_NOTE, "Using single MSI interrupt\n");
+		break;
+	case DDI_INTR_TYPE_FIXED:
+	default:
+		mptsas_log(mpt, CE_NOTE, "Using single fixed interrupt\n");
+		break;
+	}
+
 	return (DDI_SUCCESS);
 }
 
@@ -12343,8 +14060,8 @@
 		(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);
+	mpt->m_intr_cnt = 0;
 }
 
 /*
@@ -12494,13 +14211,13 @@
 	uint64_t	devicename;
 	uint16_t	pdev_hdl;
 	mptsas_target_t	*tmp_tgt = NULL;
-	uint16_t	bay_num, enclosure;
+	uint16_t	bay_num, enclosure, io_flags;
 
 	ASSERT(*pptgt == NULL);
 
 	rval = mptsas_get_sas_device_page0(mpt, page_address, dev_handle,
 	    &sas_wwn, &dev_info, &physport, &phynum, &pdev_hdl,
-	    &bay_num, &enclosure);
+	    &bay_num, &enclosure, &io_flags);
 	if (rval != DDI_SUCCESS) {
 		rval = DEV_INFO_FAIL_PAGE0;
 		return (rval);
@@ -12545,7 +14262,9 @@
 		tmp_tgt->m_qfull_retry_interval =
 		    drv_usectohz(QFULL_RETRY_INTERVAL * 1000);
 		tmp_tgt->m_t_throttle = MAX_THROTTLE;
+		mutex_init(&tmp_tgt->m_t_mutex, NULL, MUTEX_DRIVER, NULL);
 		devicename = mptsas_get_sata_guid(mpt, tmp_tgt, 0);
+		mutex_destroy(&tmp_tgt->m_t_mutex);
 		kmem_free(tmp_tgt, sizeof (struct mptsas_target));
 		mutex_enter(&mpt->m_mutex);
 		if (devicename != 0 && (((devicename >> 56) & 0xf0) == 0x50)) {
@@ -12564,6 +14283,7 @@
 		rval = DEV_INFO_FAIL_ALLOC;
 		return (rval);
 	}
+	(*pptgt)->m_io_flags = io_flags;
 	(*pptgt)->m_enclosure = enclosure;
 	(*pptgt)->m_slot_num = bay_num;
 	return (DEV_INFO_SUCCESS);
@@ -12701,6 +14421,7 @@
 	}
 	bcopy(cdb, pktp->pkt_cdbp, cdblen);
 	pktp->pkt_flags = FLAG_NOPARITY;
+	pktp->pkt_time = mptsas_scsi_pkt_time;
 	if (scsi_poll(pktp) < 0) {
 		goto out;
 	}
@@ -13549,7 +15270,7 @@
  * because we didn't call mdi_pi_free for path
  */
 static int
-mptsas_offline_target(dev_info_t *pdip, char *name)
+mptsas_offline_targetdev(dev_info_t *pdip, char *name)
 {
 	dev_info_t		*child = NULL, *prechild = NULL;
 	mdi_pathinfo_t		*pip = NULL, *savepip = NULL;
@@ -13584,7 +15305,7 @@
 			if (ndi_prop_create_boolean(DDI_DEV_T_NONE,
 			    prechild, MPTSAS_DEV_GONE) !=
 			    DDI_PROP_SUCCESS) {
-				mptsas_log(mpt, CE_WARN, "mptsas driver "
+				mptsas_log(mpt, CE_WARN,
 				    "unable to create property for "
 				    "SAS %s (MPTSAS_DEV_GONE)", addr);
 			}
@@ -13961,8 +15682,7 @@
 	char			*old_guid = NULL;
 	mptsas_t		*mpt = DIP2MPT(pdip);
 	char			*lun_addr = NULL;
-	char			*wwn_str = NULL;
-	char			*attached_wwn_str = NULL;
+	char			wwn_str[MPTSAS_WWN_STRLEN];
 	char			*component = NULL;
 	uint8_t			phy = 0xFF;
 	uint64_t		sas_wwn;
@@ -13976,7 +15696,7 @@
 	uint8_t			physport;
 	uint8_t			phy_id;
 	uint32_t		page_address;
-	uint16_t		bay_num, enclosure;
+	uint16_t		bay_num, enclosure, io_flags;
 	char			pdev_wwn_str[MPTSAS_WWN_STRLEN];
 	uint32_t		dev_info;
 
@@ -14070,13 +15790,12 @@
 	 * 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 "
+		mptsas_log(mpt, CE_WARN, "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);
 
@@ -14096,7 +15815,7 @@
 
 		if (mdi_prop_update_string(*pip, MDI_GUID,
 		    guid) != DDI_SUCCESS) {
-			mptsas_log(mpt, CE_WARN, "mptsas driver unable to "
+			mptsas_log(mpt, CE_WARN, "unable to "
 			    "create prop for target %d lun %d (MDI_GUID)",
 			    target, lun);
 			mdi_rtn = MDI_FAILURE;
@@ -14105,7 +15824,7 @@
 
 		if (mdi_prop_update_int(*pip, LUN_PROP,
 		    lun) != DDI_SUCCESS) {
-			mptsas_log(mpt, CE_WARN, "mptsas driver unable to "
+			mptsas_log(mpt, CE_WARN, "unable to "
 			    "create prop for target %d lun %d (LUN_PROP)",
 			    target, lun);
 			mdi_rtn = MDI_FAILURE;
@@ -14114,7 +15833,7 @@
 		lun64 = (int64_t)lun;
 		if (mdi_prop_update_int64(*pip, LUN64_PROP,
 		    lun64) != DDI_SUCCESS) {
-			mptsas_log(mpt, CE_WARN, "mptsas driver unable to "
+			mptsas_log(mpt, CE_WARN, "unable to "
 			    "create prop for target %d (LUN64_PROP)",
 			    target);
 			mdi_rtn = MDI_FAILURE;
@@ -14123,7 +15842,7 @@
 		if (mdi_prop_update_string_array(*pip, "compatible",
 		    compatible, ncompatible) !=
 		    DDI_PROP_SUCCESS) {
-			mptsas_log(mpt, CE_WARN, "mptsas driver unable to "
+			mptsas_log(mpt, CE_WARN, "unable to "
 			    "create prop for target %d lun %d (COMPATIBLE)",
 			    target, lun);
 			mdi_rtn = MDI_FAILURE;
@@ -14131,7 +15850,7 @@
 		}
 		if (sas_wwn && (mdi_prop_update_string(*pip,
 		    SCSI_ADDR_PROP_TARGET_PORT, wwn_str) != DDI_PROP_SUCCESS)) {
-			mptsas_log(mpt, CE_WARN, "mptsas driver unable to "
+			mptsas_log(mpt, CE_WARN, "unable to "
 			    "create prop for target %d lun %d "
 			    "(target-port)", target, lun);
 			mdi_rtn = MDI_FAILURE;
@@ -14141,7 +15860,7 @@
 			/*
 			 * Direct attached SATA device without DeviceName
 			 */
-			mptsas_log(mpt, CE_WARN, "mptsas driver unable to "
+			mptsas_log(mpt, CE_WARN, "unable to "
 			    "create prop for SAS target %d lun %d "
 			    "(sata-phy)", target, lun);
 			mdi_rtn = MDI_FAILURE;
@@ -14154,7 +15873,7 @@
 		    (uint32_t)ptgt->m_devhdl;
 		rval = mptsas_get_sas_device_page0(mpt, page_address,
 		    &dev_hdl, &dev_sas_wwn, &dev_info, &physport,
-		    &phy_id, &pdev_hdl, &bay_num, &enclosure);
+		    &phy_id, &pdev_hdl, &bay_num, &enclosure, &io_flags);
 		if (rval != DDI_SUCCESS) {
 			mutex_exit(&mpt->m_mutex);
 			mptsas_log(mpt, CE_WARN, "mptsas unable to get "
@@ -14167,7 +15886,7 @@
 		    MPI2_SAS_DEVICE_PGAD_FORM_MASK) | (uint32_t)pdev_hdl;
 		rval = mptsas_get_sas_device_page0(mpt, page_address,
 		    &dev_hdl, &pdev_sas_wwn, &pdev_info, &physport,
-		    &phy_id, &pdev_hdl, &bay_num, &enclosure);
+		    &phy_id, &pdev_hdl, &bay_num, &enclosure, &io_flags);
 		if (rval != DDI_SUCCESS) {
 			mutex_exit(&mpt->m_mutex);
 			mptsas_log(mpt, CE_WARN, "mptsas unable to get"
@@ -14214,9 +15933,9 @@
 		if (mdi_prop_update_string(*pip,
 		    SCSI_ADDR_PROP_ATTACHED_PORT, pdev_wwn_str) !=
 		    DDI_PROP_SUCCESS) {
-			mptsas_log(mpt, CE_WARN, "mptsas unable to create "
+			mptsas_log(mpt, CE_WARN, "unable to create "
 			    "property for iport attached-port %s (sas_wwn)",
-			    attached_wwn_str);
+			    pdev_wwn_str);
 			mdi_rtn = MDI_FAILURE;
 			goto virt_create_done;
 		}
@@ -14232,7 +15951,7 @@
 
 			if (mdi_pi_pathname_obp_set(*pip, component) !=
 			    DDI_SUCCESS) {
-				mptsas_log(mpt, CE_WARN, "mpt_sas driver "
+				mptsas_log(mpt, CE_WARN,
 				    "unable to set obp-path for object %s",
 				    component);
 				mdi_rtn = MDI_FAILURE;
@@ -14246,7 +15965,7 @@
 			if ((ndi_prop_update_int(DDI_DEV_T_NONE, *lun_dip,
 			    "pm-capable", 1)) !=
 			    DDI_PROP_SUCCESS) {
-				mptsas_log(mpt, CE_WARN, "mptsas driver"
+				mptsas_log(mpt, CE_WARN,
 				    "failed to create pm-capable "
 				    "property, target %d", target);
 				mdi_rtn = MDI_FAILURE;
@@ -14258,7 +15977,7 @@
 		 */
 		if (mdi_prop_update_int(*pip, "phy-num",
 		    ptgt->m_phynum) != DDI_SUCCESS) {
-			mptsas_log(mpt, CE_WARN, "mptsas driver unable to "
+			mptsas_log(mpt, CE_WARN, "unable to "
 			    "create phy-num property for target %d lun %d",
 			    target, lun);
 			mdi_rtn = MDI_FAILURE;
@@ -14287,9 +16006,6 @@
 	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);
 	}
@@ -14310,9 +16026,8 @@
 	int			ncompatible = 0;
 	int			instance = 0;
 	mptsas_t		*mpt = DIP2MPT(pdip);
-	char			*wwn_str = NULL;
-	char			*component = NULL;
-	char			*attached_wwn_str = NULL;
+	char			wwn_str[MPTSAS_WWN_STRLEN];
+	char			component[MAXPATHLEN];
 	uint8_t			phy = 0xFF;
 	uint64_t		sas_wwn;
 	uint32_t		devinfo;
@@ -14324,7 +16039,7 @@
 	uint8_t			physport;
 	uint8_t			phy_id;
 	uint32_t		page_address;
-	uint16_t		bay_num, enclosure;
+	uint16_t		bay_num, enclosure, io_flags;
 	char			pdev_wwn_str[MPTSAS_WWN_STRLEN];
 	uint32_t		dev_info;
 	int64_t			lun64 = 0;
@@ -14395,7 +16110,6 @@
 		 * 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, "w%016"PRIx64, sas_wwn);
 		if (sas_wwn && ndi_prop_update_string(DDI_DEV_T_NONE,
 		    *lun_dip, SCSI_ADDR_PROP_TARGET_PORT, wwn_str)
@@ -14461,7 +16175,7 @@
 		rval = mptsas_get_sas_device_page0(mpt, page_address,
 		    &dev_hdl, &dev_sas_wwn, &dev_info,
 		    &physport, &phy_id, &pdev_hdl,
-		    &bay_num, &enclosure);
+		    &bay_num, &enclosure, &io_flags);
 		if (rval != DDI_SUCCESS) {
 			mutex_exit(&mpt->m_mutex);
 			mptsas_log(mpt, CE_WARN, "mptsas unable to get"
@@ -14473,8 +16187,8 @@
 		page_address = (MPI2_SAS_DEVICE_PGAD_FORM_HANDLE &
 		    MPI2_SAS_DEVICE_PGAD_FORM_MASK) | (uint32_t)pdev_hdl;
 		rval = mptsas_get_sas_device_page0(mpt, page_address,
-		    &dev_hdl, &pdev_sas_wwn, &pdev_info,
-		    &physport, &phy_id, &pdev_hdl, &bay_num, &enclosure);
+		    &dev_hdl, &pdev_sas_wwn, &pdev_info, &physport,
+		    &phy_id, &pdev_hdl, &bay_num, &enclosure, &io_flags);
 		if (rval != DDI_SUCCESS) {
 			mutex_exit(&mpt->m_mutex);
 			mptsas_log(mpt, CE_WARN, "mptsas unable to create "
@@ -14524,7 +16238,7 @@
 			mptsas_log(mpt, CE_WARN,
 			    "mptsas unable to create "
 			    "property for iport attached-port %s (sas_wwn)",
-			    attached_wwn_str);
+			    pdev_wwn_str);
 			ndi_rtn = NDI_FAILURE;
 			goto phys_create_done;
 		}
@@ -14563,7 +16277,7 @@
 		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, "
+			NDBG2(("mptsas3%d: creating pm-capable property, "
 			    "target %d", instance, target));
 
 			if ((ndi_prop_update_int(DDI_DEV_T_NONE,
@@ -14584,7 +16298,6 @@
 			 */
 			bzero(wwn_str, sizeof (wwn_str));
 			(void) sprintf(wwn_str, "%016"PRIx64, sas_wwn);
-			component = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
 			if (guid) {
 				(void) snprintf(component, MAXPATHLEN,
 				    "disk@w%s,%x", wwn_str, lun);
@@ -14608,7 +16321,7 @@
 			if (ndi_prop_update_int(DDI_DEV_T_NONE,
 			    *lun_dip, "phy-num", ptgt->m_phynum) !=
 			    DDI_PROP_SUCCESS) {
-				mptsas_log(mpt, CE_WARN, "mptsas driver "
+				mptsas_log(mpt, CE_WARN,
 				    "failed to create phy-num property for "
 				    "target %d", target);
 				ndi_rtn = NDI_FAILURE;
@@ -14636,7 +16349,7 @@
 		 * If success set rtn flag, else unwire alloc'd lun
 		 */
 		if (ndi_rtn != NDI_SUCCESS) {
-			NDBG12(("mptsas driver unable to online "
+			NDBG12(("unable to online "
 			    "target %d lun %d", target, lun));
 			ndi_prop_remove_all(*lun_dip);
 			(void) ndi_devi_free(*lun_dip);
@@ -14646,14 +16359,6 @@
 
 	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);
 }
 
@@ -14724,7 +16429,7 @@
 	char		*iport = NULL;
 	mptsas_phymask_t	phy_mask = 0;
 	uint16_t	attached_devhdl;
-	uint16_t	bay_num, enclosure;
+	uint16_t	bay_num, enclosure, io_flags;
 
 	(void) sprintf(wwn_str, "%"PRIx64, smp_node->m_addr.mta_wwn);
 
@@ -14791,8 +16496,8 @@
 		    MPI2_SAS_DEVICE_PGAD_FORM_MASK) |
 		    (uint32_t)dev_info.m_pdevhdl;
 		rval = mptsas_get_sas_device_page0(mpt, page_address,
-		    &dev_hdl, &sas_wwn, &smp_node->m_pdevinfo,
-		    &physport, &phy_id, &pdev_hdl, &bay_num, &enclosure);
+		    &dev_hdl, &sas_wwn, &smp_node->m_pdevinfo, &physport,
+		    &phy_id, &pdev_hdl, &bay_num, &enclosure, &io_flags);
 		if (rval != DDI_SUCCESS) {
 			mutex_exit(&mpt->m_mutex);
 			mptsas_log(mpt, CE_WARN, "mptsas unable to get "
@@ -14806,7 +16511,8 @@
 		    (uint32_t)dev_info.m_devhdl;
 		rval = mptsas_get_sas_device_page0(mpt, page_address,
 		    &dev_hdl, &smp_sas_wwn, &smp_node->m_deviceinfo,
-		    &physport, &phy_id, &pdev_hdl, &bay_num, &enclosure);
+		    &physport, &phy_id, &pdev_hdl, &bay_num, &enclosure,
+		    &io_flags);
 		if (rval != DDI_SUCCESS) {
 			mutex_exit(&mpt->m_mutex);
 			mptsas_log(mpt, CE_WARN, "mptsas unable to get "
@@ -14960,7 +16666,7 @@
 	uint64_t			wwn;
 	Mpi2SmpPassthroughRequest_t	req;
 	Mpi2SmpPassthroughReply_t	rep;
-	uint32_t			direction = 0;
+	uint8_t				direction = 0;
 	mptsas_t			*mpt;
 	int				ret;
 	uint64_t			tmp64;
@@ -15264,12 +16970,23 @@
 	tmp_tgt->m_qfull_retry_interval =
 	    drv_usectohz(QFULL_RETRY_INTERVAL * 1000);
 	tmp_tgt->m_t_throttle = MAX_THROTTLE;
+	mutex_init(&tmp_tgt->m_t_mutex, NULL, MUTEX_DRIVER, NULL);
+	TAILQ_INIT(&tmp_tgt->m_active_cmdq);
 
 	refhash_insert(mpt->m_targets, tmp_tgt);
 
 	return (tmp_tgt);
 }
 
+static void
+mptsas_smp_target_copy(mptsas_smp_t *src, mptsas_smp_t *dst)
+{
+	dst->m_devhdl = src->m_devhdl;
+	dst->m_deviceinfo = src->m_deviceinfo;
+	dst->m_pdevhdl = src->m_pdevhdl;
+	dst->m_pdevinfo = src->m_pdevinfo;
+}
+
 static mptsas_smp_t *
 mptsas_smp_alloc(mptsas_t *mpt, mptsas_smp_t *data)
 {
@@ -15279,8 +16996,14 @@
 	addr.mta_wwn = data->m_addr.mta_wwn;
 	addr.mta_phymask = data->m_addr.mta_phymask;
 	ret_data = refhash_lookup(mpt->m_smp_targets, &addr);
+	/*
+	 * If there's already a matching SMP target, update its fields
+	 * in place.  Since the address is not changing, it's safe to do
+	 * this.  We cannot just bcopy() here because the structure we've
+	 * been given has invalid hash links.
+	 */
 	if (ret_data != NULL) {
-		bcopy(data, ret_data, sizeof (mptsas_smp_t)); /* XXX - dupl */
+		mptsas_smp_target_copy(data, ret_data);
 		return (ret_data);
 	}
 
@@ -15444,7 +17167,6 @@
 
 	if (ddi_dma_alloc_handle(mpt->m_dip, &dma_attr, DDI_DMA_SLEEP,
 	    NULL, dma_hdp) != DDI_SUCCESS) {
-		dma_hdp = NULL;
 		return (FALSE);
 	}
 
@@ -15452,7 +17174,6 @@
 	    DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, dma_memp, &alloc_len,
 	    acc_hdp) != DDI_SUCCESS) {
 		ddi_dma_free_handle(dma_hdp);
-		dma_hdp = NULL;
 		return (FALSE);
 	}
 
@@ -15461,7 +17182,6 @@
 	    cookiep, &ncookie) != DDI_DMA_MAPPED) {
 		(void) ddi_dma_mem_free(acc_hdp);
 		ddi_dma_free_handle(dma_hdp);
-		dma_hdp = NULL;
 		return (FALSE);
 	}
 
@@ -15477,5 +17197,4 @@
 	(void) ddi_dma_unbind_handle(*dma_hdp);
 	(void) ddi_dma_mem_free(acc_hdp);
 	ddi_dma_free_handle(dma_hdp);
-	dma_hdp = NULL;
 }
--- old/usr/src/uts/common/io/scsi/adapters/mpt_sas3/mptsas3_hash.c	2014-06-12 17:42:16.716586855 +0100
+++ new/usr/src/uts/common/io/scsi/adapters/mpt_sas3/mptsas3_hash.c	2014-06-12 17:42:16.722123048 +0100
@@ -11,9 +11,10 @@
 
 /*
  * Copyright 2014 Joyent, Inc.  All rights reserved.
+ * Copyright (c) 2014, Tegile Systems Inc. All rights reserved.
  */
 
-#include <sys/scsi/adapters/mpt_sas/mptsas_hash.h>
+#include <sys/scsi/adapters/mpt_sas3/mptsas3_hash.h>
 #include <sys/sysmacros.h>
 #include <sys/types.h>
 #include <sys/kmem.h>
--- old/usr/src/uts/common/io/scsi/adapters/mpt_sas3/mptsas3_impl.c	2014-06-12 17:42:16.878312556 +0100
+++ new/usr/src/uts/common/io/scsi/adapters/mpt_sas3/mptsas3_impl.c	2014-06-12 17:42:16.884650279 +0100
@@ -22,6 +22,8 @@
 /*
  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
  * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 2014, Tegile Systems Inc. All rights reserved.
+ * Copyright 2014 OmniTI Computer Consulting, Inc. All rights reserved.
  */
 
 /*
@@ -68,20 +70,20 @@
 #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>
-#include <sys/scsi/adapters/mpt_sas/mpi/mpi2_tool.h>
+#include <sys/scsi/adapters/mpt_sas3/mpi/mpi2_type.h>
+#include <sys/scsi/adapters/mpt_sas3/mpi/mpi2.h>
+#include <sys/scsi/adapters/mpt_sas3/mpi/mpi2_cnfg.h>
+#include <sys/scsi/adapters/mpt_sas3/mpi/mpi2_init.h>
+#include <sys/scsi/adapters/mpt_sas3/mpi/mpi2_ioc.h>
+#include <sys/scsi/adapters/mpt_sas3/mpi/mpi2_sas.h>
+#include <sys/scsi/adapters/mpt_sas3/mpi/mpi2_tool.h>
 #pragma pack()
 
 /*
  * private header files.
  */
-#include <sys/scsi/adapters/mpt_sas/mptsas_var.h>
-#include <sys/scsi/adapters/mpt_sas/mptsas_smhba.h>
+#include <sys/scsi/adapters/mpt_sas3/mptsas3_var.h>
+#include <sys/scsi/adapters/mpt_sas3/mptsas3_smhba.h>
 
 /*
  * FMA header files.
@@ -90,6 +92,7 @@
 
 #if defined(MPTSAS_DEBUG)
 extern uint32_t mptsas_debug_flags;
+extern uint32_t mptsas_dbglog_imask;
 #endif
 
 /*
@@ -205,7 +208,8 @@
 	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;
+	uint32_t		length, flagslength;
+	uint64_t		request_desc;
 
 	ASSERT(mutex_owned(&mpt->m_mutex));
 
@@ -259,7 +263,7 @@
 			direction = MPI2_SGE_FLAGS_HOST_TO_IOC;
 		}
 		ddi_put32(mpt->m_acc_req_frame_hdl, &sge->Address.Low,
-		    (uint32_t)cmd->cmd_dma_addr);
+		    (uint32_t)(cmd->cmd_dma_addr&0xfffffffful));
 		ddi_put32(mpt->m_acc_req_frame_hdl, &sge->Address.High,
 		    (uint32_t)(cmd->cmd_dma_addr >> 32));
 	}
@@ -279,10 +283,10 @@
 
 	(void) ddi_dma_sync(mpt->m_dma_req_frame_hdl, 0, 0,
 	    DDI_DMA_SYNC_FORDEV);
-	request_desc_low = (cmd->cmd_slot << 16) +
+	request_desc = (cmd->cmd_slot << 16) +
 	    MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
 	cmd->cmd_rfm = NULL;
-	MPTSAS_START_CMD(mpt, request_desc_low, 0);
+	MPTSAS_START_CMD(mpt, request_desc);
 	if ((mptsas_check_dma_handle(mpt->m_dma_req_frame_hdl) !=
 	    DDI_SUCCESS) ||
 	    (mptsas_check_acc_handle(mpt->m_acc_req_frame_hdl) !=
@@ -309,6 +313,7 @@
 	uint16_t		iocstatus = 0;
 	uint32_t		iocloginfo;
 	caddr_t			page_memp;
+	boolean_t		free_dma = B_FALSE;
 
 	va_start(ap, callback);
 	ASSERT(mutex_owned(&mpt->m_mutex));
@@ -391,7 +396,7 @@
 		(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));
+		    - (mpt->m_reply_frame_dma_addr&0xfffffffful)));
 		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,
@@ -465,8 +470,14 @@
 	if (mptsas_dma_addr_create(mpt, attrs,
 	    &cmd->cmd_dmahandle, &accessp, &page_memp,
 	    len, &cookie) == FALSE) {
+		mptsas_log(mpt, CE_WARN,
+		    "mptsas_dma_addr_create(len=0x%x) failed", (int)len);
+		rval = DDI_FAILURE;
 		goto page_done;
 	}
+	/* NOW we can safely call mptsas_dma_addr_destroy(). */
+	free_dma = B_TRUE;
+
 	cmd->cmd_dma_addr = cookie.dmac_laddress;
 	bzero(page_memp, len);
 
@@ -530,7 +541,7 @@
 		(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));
+		    - (mpt->m_reply_frame_dma_addr&0xfffffffful)));
 		iocstatus = ddi_get16(mpt->m_acc_reply_frame_hdl,
 		    &reply->IOCStatus);
 		iocstatus = MPTSAS_IOCSTATUS(iocstatus);
@@ -584,7 +595,8 @@
 		    mpt->m_free_index);
 	}
 
-	mptsas_dma_addr_destroy(&cmd->cmd_dmahandle, &accessp);
+	if (free_dma)
+		mptsas_dma_addr_destroy(&cmd->cmd_dmahandle, &accessp);
 
 	if (cmd && (cmd->cmd_flags & CFLAG_PREPARED)) {
 		mptsas_remove_cmd(mpt, cmd);
@@ -606,7 +618,7 @@
 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)
+	uint8_t pagelength, uint32_t SGEflagslength, uint64_t SGEaddress)
 {
 	pMpi2ConfigRequest_t	config;
 	int			send_numbytes;
@@ -623,7 +635,11 @@
 	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);
+	    &config->PageBufferSGE.MpiSimple.u.Address64.Low,
+	    SGEaddress&0xfffffffful);
+	ddi_put32(mpt->m_hshk_acc_hdl,
+	    &config->PageBufferSGE.MpiSimple.u.Address64.High,
+	    SGEaddress >> 32);
 	send_numbytes = sizeof (MPI2_CONFIG_REQUEST);
 
 	/*
@@ -640,7 +656,7 @@
 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)
+	uint32_t SGEflagslength, uint64_t SGEaddress)
 {
 	pMpi2ConfigRequest_t	config;
 	int			send_numbytes;
@@ -659,7 +675,11 @@
 	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);
+	    &config->PageBufferSGE.MpiSimple.u.Address64.Low,
+	    SGEaddress&0xfffffffful);
+	ddi_put32(mpt->m_hshk_acc_hdl,
+	    &config->PageBufferSGE.MpiSimple.u.Address64.High,
+	    SGEaddress >> 32);
 	send_numbytes = sizeof (MPI2_CONFIG_REQUEST);
 
 	/*
@@ -1087,7 +1107,8 @@
 	mptsas_cmd_t				*cmd;
 	struct scsi_pkt				*pkt;
 	mptsas_slots_t				*slots = mpt->m_active;
-	uint32_t				request_desc_low, i;
+	uint32_t				i;
+	uint64_t				request_desc;
 	pMPI2DefaultReply_t			reply_msg;
 
 	/*
@@ -1143,9 +1164,9 @@
 	 */
 	(void) ddi_dma_sync(mpt->m_dma_req_frame_hdl, 0, 0,
 	    DDI_DMA_SYNC_FORDEV);
-	request_desc_low = (cmd->cmd_slot << 16) +
+	request_desc = (cmd->cmd_slot << 16) +
 	    MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY;
-	MPTSAS_START_CMD(mpt, request_desc_low, 0);
+	MPTSAS_START_CMD(mpt, request_desc);
 	rval = mptsas_poll(mpt, cmd, MPTSAS_POLL_TIME);
 
 	if (pkt->pkt_reason == CMD_INCOMPLETE)
@@ -1161,7 +1182,7 @@
 		    DDI_DMA_SYNC_FORCPU);
 		reply_msg = (pMPI2DefaultReply_t)
 		    (mpt->m_reply_frame + (cmd->cmd_rfm -
-		    mpt->m_reply_frame_dma_addr));
+		    (mpt->m_reply_frame_dma_addr&0xfffffffful)));
 		if (reply_size > sizeof (MPI2_SCSI_TASK_MANAGE_REPLY)) {
 			reply_size = sizeof (MPI2_SCSI_TASK_MANAGE_REPLY);
 		}
@@ -1199,6 +1220,83 @@
 	return (rval);
 }
 
+/*
+ * Complete firmware download frame for v2.0 cards.
+ */
+static void
+mptsas_uflash2(pMpi2FWDownloadRequest fwdownload,
+    ddi_acc_handle_t acc_hdl, uint32_t size, uint8_t type,
+    ddi_dma_cookie_t flsh_cookie)
+{
+	pMpi2FWDownloadTCSGE_t	tcsge;
+	pMpi2SGESimple64_t	sge;
+	uint32_t		flagslength;
+
+	ddi_put8(acc_hdl, &fwdownload->Function,
+	    MPI2_FUNCTION_FW_DOWNLOAD);
+	ddi_put8(acc_hdl, &fwdownload->ImageType, type);
+	ddi_put8(acc_hdl, &fwdownload->MsgFlags,
+	    MPI2_FW_DOWNLOAD_MSGFLGS_LAST_SEGMENT);
+	ddi_put32(acc_hdl, &fwdownload->TotalImageSize, size);
+
+	tcsge = (pMpi2FWDownloadTCSGE_t)&fwdownload->SGL;
+	ddi_put8(acc_hdl, &tcsge->ContextSize, 0);
+	ddi_put8(acc_hdl, &tcsge->DetailsLength, 12);
+	ddi_put8(acc_hdl, &tcsge->Flags, 0);
+	ddi_put32(acc_hdl, &tcsge->ImageOffset, 0);
+	ddi_put32(acc_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(acc_hdl, &sge->FlagsLength, flagslength);
+	ddi_put32(acc_hdl, &sge->Address.Low,
+	    flsh_cookie.dmac_address);
+	ddi_put32(acc_hdl, &sge->Address.High,
+	    (uint32_t)(flsh_cookie.dmac_laddress >> 32));
+}
+
+/*
+ * Complete firmware download frame for v2.5 cards.
+ */
+static void
+mptsas_uflash25(pMpi25FWDownloadRequest fwdownload,
+    ddi_acc_handle_t acc_hdl, uint32_t size, uint8_t type,
+    ddi_dma_cookie_t flsh_cookie)
+{
+	pMpi2IeeeSgeSimple64_t	sge;
+	uint8_t			flags;
+
+	ddi_put8(acc_hdl, &fwdownload->Function,
+	    MPI2_FUNCTION_FW_DOWNLOAD);
+	ddi_put8(acc_hdl, &fwdownload->ImageType, type);
+	ddi_put8(acc_hdl, &fwdownload->MsgFlags,
+	    MPI2_FW_DOWNLOAD_MSGFLGS_LAST_SEGMENT);
+	ddi_put32(acc_hdl, &fwdownload->TotalImageSize, size);
+
+	ddi_put32(acc_hdl, &fwdownload->ImageOffset, 0);
+	ddi_put32(acc_hdl, &fwdownload->ImageSize, size);
+
+	sge = (pMpi2IeeeSgeSimple64_t)&fwdownload->SGL;
+	flags = MPI2_IEEE_SGE_FLAGS_SIMPLE_ELEMENT |
+	    MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR |
+	    MPI25_IEEE_SGE_FLAGS_END_OF_LIST;
+	ddi_put8(acc_hdl, &sge->Flags, flags);
+	ddi_put32(acc_hdl, &sge->Length, size);
+	ddi_put32(acc_hdl, &sge->Address.Low,
+	    flsh_cookie.dmac_address);
+	ddi_put32(acc_hdl, &sge->Address.High,
+	    (uint32_t)(flsh_cookie.dmac_laddress >> 32));
+}
+
+static int mptsas_enable_mpi25_flashupdate = 0;
+
 int
 mptsas_update_flash(mptsas_t *mpt, caddr_t ptrbuffer, uint32_t size,
     uint8_t type, int mode)
@@ -1216,15 +1314,24 @@
 	ddi_dma_handle_t	flsh_dma_handle;
 	ddi_acc_handle_t	flsh_accessp;
 	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;
+	uint64_t		request_desc;
+
+	if (mpt->m_MPI25) {
+		/*
+		 * The code is there but not tested yet.
+		 * User has to know there are risks here.
+		 */
+		mptsas_log(mpt, CE_WARN, "mptsas_update_flash(): "
+		    "Updating firmware through MPI 2.5 has not been "
+		    "tested yet!\n"
+		    "To enable set mptsas_enable_mpi25_flashupdate to 1\n");
+		if (!mptsas_enable_mpi25_flashupdate)
+			return (-1);
+	}
 
 	if ((rvalue = (mptsas_request_from_pool(mpt, &cmd, &pkt))) == -1) {
 		mptsas_log(mpt, CE_WARN, "mptsas_update_flash(): allocation "
@@ -1285,45 +1392,23 @@
 	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));
+	if (mpt->m_MPI25)
+		mptsas_uflash25((pMpi25FWDownloadRequest)memp,
+		    mpt->m_acc_req_frame_hdl, size, type, flsh_cookie);
+	else
+		mptsas_uflash2((pMpi2FWDownloadRequest)memp,
+		    mpt->m_acc_req_frame_hdl, size, type, flsh_cookie);
 
 	/*
 	 * 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) +
+	request_desc = (cmd->cmd_slot << 16) +
 	    MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
 	cmd->cmd_rfm = NULL;
-	MPTSAS_START_CMD(mpt, request_desc_low, 0);
+	MPTSAS_START_CMD(mpt, request_desc);
 
 	rvalue = 0;
 	(void) cv_reltimedwait(&mpt->m_fw_cv, &mpt->m_mutex,
@@ -1357,7 +1442,7 @@
 	uint64_t		*sas_wwn;
 	uint32_t		*dev_info;
 	uint8_t			*physport, *phynum;
-	uint16_t		*pdevhdl;
+	uint16_t		*pdevhdl, *io_flags;
 	uint32_t		page_address;
 
 	if ((iocstatus != MPI2_IOCSTATUS_SUCCESS) &&
@@ -1391,7 +1476,7 @@
 	pdevhdl = va_arg(ap, uint16_t *);
 	bay_num = va_arg(ap, uint16_t *);
 	enclosure = va_arg(ap, uint16_t *);
-
+	io_flags = va_arg(ap, uint16_t *);
 
 	sasdevpage = (pMpi2SasDevicePage0_t)page_memp;
 
@@ -1408,6 +1493,19 @@
 	*pdevhdl = ddi_get16(accessp, &sasdevpage->ParentDevHandle);
 	*bay_num = ddi_get16(accessp, &sasdevpage->Slot);
 	*enclosure = ddi_get16(accessp, &sasdevpage->EnclosureHandle);
+	*io_flags = ddi_get16(accessp, &sasdevpage->Flags);
+
+	if (*io_flags & MPI25_SAS_DEVICE0_FLAGS_FAST_PATH_CAPABLE) {
+		/*
+		 * Leave a messages about FP cabability in the log.
+		 */
+		mptsas_log(mpt, CE_CONT,
+		    "!w%016"PRIx64" FastPath Capable%s", *sas_wwn,
+		    (*io_flags &
+		    MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH)?
+		    " and Enabled":" but Disabled");
+	}
+
 	return (rval);
 }
 
@@ -1419,7 +1517,7 @@
 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, uint16_t *pdev_handle,
-    uint16_t *bay_num, uint16_t *enclosure)
+    uint16_t *bay_num, uint16_t *enclosure, uint16_t *io_flags)
 {
 	int rval = DDI_SUCCESS;
 
@@ -1434,7 +1532,7 @@
 	    MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE, 0, page_address,
 	    mptsas_sasdevpage_0_cb, page_address, dev_handle, sas_wwn,
 	    dev_info, physport, phynum, pdev_handle,
-	    bay_num, enclosure);
+	    bay_num, enclosure, io_flags);
 
 	return (rval);
 }
@@ -1857,6 +1955,7 @@
 	uint32_t		reply_size = 256; /* Big enough for any page */
 	uint_t			state;
 	int			rval = DDI_FAILURE;
+	boolean_t		free_recv = B_FALSE, free_page = B_FALSE;
 
 	/*
 	 * Initialize our "state machine".  This is a bit convoluted,
@@ -1883,6 +1982,8 @@
 		    "mptsas_get_sas_io_unit_page_hndshk: recv dma failed");
 		goto cleanup;
 	}
+	/* Now safe to call mptsas_dma_addr_destroy(recv_dma_handle). */
+	free_recv = B_TRUE;
 
 	page_dma_attrs = mpt->m_msg_dma_attr;
 	page_dma_attrs.dma_attr_sgllen = 1;
@@ -1895,6 +1996,8 @@
 		    "mptsas_get_sas_io_unit_page_hndshk: page dma failed");
 		goto cleanup;
 	}
+	/* Now safe to call mptsas_dma_addr_destroy(page_dma_handle). */
+	free_page = B_TRUE;
 
 	/*
 	 * Now we cycle through the state machine.  Here's what happens:
@@ -1917,7 +2020,7 @@
 			    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_64_BIT_ADDRESSING |
 			    MPI2_SGE_FLAGS_IOC_TO_HOST |
 			    MPI2_SGE_FLAGS_END_OF_LIST) <<
 			    MPI2_SGE_FLAGS_SHIFT);
@@ -1933,7 +2036,7 @@
 			    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_64_BIT_ADDRESSING |
 			    MPI2_SGE_FLAGS_IOC_TO_HOST |
 			    MPI2_SGE_FLAGS_END_OF_LIST) <<
 			    MPI2_SGE_FLAGS_SHIFT);
@@ -1977,7 +2080,7 @@
 		    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)) {
+		    flags_length, page_cookie.dmac_laddress)) {
 			goto cleanup;
 		}
 
@@ -2130,8 +2233,10 @@
 	}
 
 cleanup:
-	mptsas_dma_addr_destroy(&recv_dma_handle, &recv_accessp);
-	mptsas_dma_addr_destroy(&page_dma_handle, &page_accessp);
+	if (free_recv)
+		mptsas_dma_addr_destroy(&recv_dma_handle, &recv_accessp);
+	if (free_page)
+		mptsas_dma_addr_destroy(&page_dma_handle, &page_accessp);
 	if (rval != DDI_SUCCESS) {
 		mptsas_fm_ereport(mpt, DDI_FM_DEVICE_NO_RESPONSE);
 		ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_LOST);
@@ -2159,6 +2264,7 @@
 	uint32_t			flagslength;
 	int				rval = DDI_SUCCESS;
 	uint_t				iocstatus;
+	boolean_t		free_recv = B_FALSE, free_page = B_FALSE;
 
 	MPTSAS_DISABLE_INTR(mpt);
 
@@ -2179,8 +2285,11 @@
 	if (mptsas_dma_addr_create(mpt, recv_dma_attrs,
 	    &recv_dma_handle, &recv_accessp, &recv_memp,
 	    (sizeof (MPI2_CONFIG_REPLY)), NULL) == FALSE) {
+		rval = DDI_FAILURE;
 		goto done;
 	}
+	/* Now safe to call mptsas_dma_addr_destroy(recv_dma_handle). */
+	free_recv = B_TRUE;
 
 	bzero(recv_memp, sizeof (MPI2_CONFIG_REPLY));
 	configreply = (pMpi2ConfigReply_t)recv_memp;
@@ -2213,10 +2322,17 @@
 	if (mptsas_dma_addr_create(mpt, page_dma_attrs, &page_dma_handle,
 	    &page_accessp, &page_memp, (sizeof (MPI2_CONFIG_PAGE_MAN_5)),
 	    &page_cookie) == FALSE) {
+		rval = DDI_FAILURE;
 		goto done;
 	}
+	/* Now safe to call mptsas_dma_addr_destroy(page_dma_handle). */
+	free_page = B_TRUE;
+
 	bzero(page_memp, sizeof (MPI2_CONFIG_PAGE_MAN_5));
 	m5 = (pMpi2ManufacturingPage5_t)page_memp;
+	NDBG20(("mptsas_get_manufacture_page5: paddr 0x%x%08x",
+	    (uint32_t)(page_cookie.dmac_laddress>>32),
+	    (uint32_t)(page_cookie.dmac_laddress&0xfffffffful)));
 
 	/*
 	 * Give reply address to IOC to store config page in and send
@@ -2226,7 +2342,7 @@
 	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_SYSTEM_ADDRESS | MPI2_SGE_FLAGS_64_BIT_ADDRESSING |
 	    MPI2_SGE_FLAGS_IOC_TO_HOST |
 	    MPI2_SGE_FLAGS_END_OF_LIST) << MPI2_SGE_FLAGS_SHIFT);
 
@@ -2235,7 +2351,7 @@
 	    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)) {
+	    flagslength, page_cookie.dmac_laddress)) {
 		rval = DDI_FAILURE;
 		goto done;
 	}
@@ -2303,8 +2419,10 @@
 	/*
 	 * free up memory
 	 */
-	mptsas_dma_addr_destroy(&recv_dma_handle, &recv_accessp);
-	mptsas_dma_addr_destroy(&page_dma_handle, &page_accessp);
+	if (free_recv)
+		mptsas_dma_addr_destroy(&recv_dma_handle, &recv_accessp);
+	if (free_page)
+		mptsas_dma_addr_destroy(&page_dma_handle, &page_accessp);
 	MPTSAS_ENABLE_INTR(mpt);
 
 	return (rval);
@@ -2525,6 +2643,7 @@
 	int				rval = DDI_SUCCESS;
 	uint_t				iocstatus;
 	uint8_t				i = 0;
+	boolean_t		free_recv = B_FALSE, free_page = B_FALSE;
 
 	MPTSAS_DISABLE_INTR(mpt);
 
@@ -2545,8 +2664,12 @@
 	if (mptsas_dma_addr_create(mpt, recv_dma_attrs, &recv_dma_handle,
 	    &recv_accessp, &recv_memp, (sizeof (MPI2_CONFIG_REPLY)),
 	    NULL) == FALSE) {
+		rval = DDI_FAILURE;
 		goto done;
 	}
+	/* Now safe to call mptsas_dma_addr_destroy(recv_dma_handle). */
+	free_recv = B_TRUE;
+
 	bzero(recv_memp, sizeof (MPI2_CONFIG_REPLY));
 	configreply = (pMpi2ConfigReply_t)recv_memp;
 	recv_numbytes = sizeof (MPI2_CONFIG_REPLY);
@@ -2578,8 +2701,12 @@
 	if (mptsas_dma_addr_create(mpt, page_dma_attrs, &page_dma_handle,
 	    &page_accessp, &page_memp, (sizeof (MPI2_CONFIG_PAGE_MAN_0)),
 	    &page_cookie) == FALSE) {
+		rval = DDI_FAILURE;
 		goto done;
 	}
+	/* Now safe to call mptsas_dma_addr_destroy(page_dma_handle). */
+	free_page = B_TRUE;
+
 	bzero(page_memp, sizeof (MPI2_CONFIG_PAGE_MAN_0));
 	m0 = (pMpi2ManufacturingPage0_t)page_memp;
 
@@ -2591,7 +2718,7 @@
 	flagslength = sizeof (MPI2_CONFIG_PAGE_MAN_0);
 	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_SYSTEM_ADDRESS | MPI2_SGE_FLAGS_64_BIT_ADDRESSING |
 	    MPI2_SGE_FLAGS_IOC_TO_HOST |
 	    MPI2_SGE_FLAGS_END_OF_LIST) << MPI2_SGE_FLAGS_SHIFT);
 
@@ -2600,7 +2727,7 @@
 	    MPI2_CONFIG_PAGETYPE_MANUFACTURING, 0, 0,
 	    ddi_get8(recv_accessp, &configreply->Header.PageVersion),
 	    ddi_get8(recv_accessp, &configreply->Header.PageLength),
-	    flagslength, page_cookie.dmac_address)) {
+	    flagslength, page_cookie.dmac_laddress)) {
 		rval = DDI_FAILURE;
 		goto done;
 	}
@@ -2673,8 +2800,10 @@
 	/*
 	 * free up memory
 	 */
-	mptsas_dma_addr_destroy(&recv_dma_handle, &recv_accessp);
-	mptsas_dma_addr_destroy(&page_dma_handle, &page_accessp);
+	if (free_recv)
+		mptsas_dma_addr_destroy(&recv_dma_handle, &recv_accessp);
+	if (free_page)
+		mptsas_dma_addr_destroy(&page_dma_handle, &page_accessp);
 	MPTSAS_ENABLE_INTR(mpt);
 
 	return (rval);
--- old/usr/src/uts/common/io/scsi/adapters/mpt_sas3/mptsas3_init.c	2014-06-12 17:42:17.118522197 +0100
+++ new/usr/src/uts/common/io/scsi/adapters/mpt_sas3/mptsas3_init.c	2014-06-12 17:42:17.124301808 +0100
@@ -22,6 +22,7 @@
 /*
  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
+ * Copyright (c) 2014, Tegile Systems Inc. All rights reserved.
  */
 
 /*
@@ -67,17 +68,17 @@
 #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_tool.h>
+#include <sys/scsi/adapters/mpt_sas3/mpi/mpi2_type.h>
+#include <sys/scsi/adapters/mpt_sas3/mpi/mpi2.h>
+#include <sys/scsi/adapters/mpt_sas3/mpi/mpi2_cnfg.h>
+#include <sys/scsi/adapters/mpt_sas3/mpi/mpi2_init.h>
+#include <sys/scsi/adapters/mpt_sas3/mpi/mpi2_ioc.h>
+#include <sys/scsi/adapters/mpt_sas3/mpi/mpi2_tool.h>
 #pragma pack()
 /*
  * private header files.
  */
-#include <sys/scsi/adapters/mpt_sas/mptsas_var.h>
+#include <sys/scsi/adapters/mpt_sas3/mptsas3_var.h>
 
 static int mptsas_ioc_do_get_facts(mptsas_t *mpt, caddr_t memp, int var,
 	ddi_acc_handle_t accessp);
@@ -101,12 +102,47 @@
 	ddi_acc_handle_t accessp);
 
 static const char *
-mptsas_product_type_string(mptsas_t *mpt)
+mptsas_devid_type_string(mptsas_t *mpt)
 {
-	switch (mpt->m_productid & MPI2_FW_HEADER_PID_PROD_MASK) {
-
-	case MPI2_FW_HEADER_PID_PROD_A:
-		return ("A");
+	switch (mpt->m_devid) {
+	case MPI2_MFGPAGE_DEVID_SAS2008:
+		return ("SAS2008");
+	case MPI2_MFGPAGE_DEVID_SAS2004:
+		return ("SAS2004");
+	case MPI2_MFGPAGE_DEVID_SAS2108_1:
+	case MPI2_MFGPAGE_DEVID_SAS2108_2:
+	case MPI2_MFGPAGE_DEVID_SAS2108_3:
+		return ("SAS2108");
+	case MPI2_MFGPAGE_DEVID_SAS2116_1:
+	case MPI2_MFGPAGE_DEVID_SAS2116_2:
+		return ("SAS2116");
+	case MPI2_MFGPAGE_DEVID_SAS2208_1:
+	case MPI2_MFGPAGE_DEVID_SAS2208_2:
+	case MPI2_MFGPAGE_DEVID_SAS2208_3:
+	case MPI2_MFGPAGE_DEVID_SAS2208_4:
+	case MPI2_MFGPAGE_DEVID_SAS2208_5:
+	case MPI2_MFGPAGE_DEVID_SAS2208_6:
+#if 0
+	/* These are the same as the next 2?? */
+	case MPI2_MFGPAGE_DEVID_SAS2208_7:
+	case MPI2_MFGPAGE_DEVID_SAS2208_8:
+#endif
+		return ("SAS2208");
+	case MPI2_MFGPAGE_DEVID_SAS2308_1:
+	case MPI2_MFGPAGE_DEVID_SAS2308_2:
+	case MPI2_MFGPAGE_DEVID_SAS2308_3:
+		return ("SAS2308");
+	case MPI25_MFGPAGE_DEVID_SAS3004:
+		return ("SAS3004");
+	case MPI25_MFGPAGE_DEVID_SAS3008:
+		return ("SAS3008");
+	case MPI25_MFGPAGE_DEVID_SAS3108_1:
+	case MPI25_MFGPAGE_DEVID_SAS3108_2:
+	case MPI25_MFGPAGE_DEVID_SAS3108_3:
+	case MPI25_MFGPAGE_DEVID_SAS3108_4:
+	case MPI25_MFGPAGE_DEVID_SAS3108_5:
+	case MPI25_MFGPAGE_DEVID_SAS3108_6:
+		return ("SAS3108");
 	default:
 		return ("?");
 	}
@@ -176,6 +212,7 @@
 	int			simple_sge_main;
 	int			simple_sge_next;
 	uint32_t		capabilities;
+	uint16_t		msgversion;
 
 	bzero(memp, sizeof (*factsreply));
 	factsreply = (void *)memp;
@@ -207,8 +244,8 @@
 	    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));
+	mptsas_log(mpt, CE_NOTE, "?MPT Firmware version v%s (%s)\n",
+	    buf, mptsas_devid_type_string(mpt));
 	(void) ddi_prop_update_string(DDI_DEV_T_NONE, mpt->m_dip,
 	    "firmware-version", buf);
 
@@ -245,6 +282,9 @@
 	 * calculated queue size is larger than allowed, subtract a
 	 * multiple of 16 from m_max_requests, m_max_replies, and
 	 * m_reply_free_depth.
+	 *
+	 * There is no indication in the spec that you can reduce the
+	 * queue size if you have many.
 	 */
 	queueSize = mpt->m_max_requests + numReplyFrames + 1;
 	if (queueSize % 16) {
@@ -271,13 +311,31 @@
 	    &factsreply->MaxChainDepth);
 	mpt->m_ioc_capabilities = ddi_get32(accessp,
 	    &factsreply->IOCCapabilities);
+	if (mpt->m_ioc_capabilities & MPI2_IOCFACTS_CAPABILITY_MSI_X_INDEX) {
+		mpt->m_max_msix_vectors = ddi_get8(accessp,
+		    &factsreply->MaxMSIxVectors);
+	}
+
+	/*
+	 * Set flag to check for SAS3 support.
+	 */
+	msgversion = ddi_get16(accessp, &factsreply->MsgVersion);
+	if (msgversion == MPI2_VERSION_02_05) {
+		mptsas_log(mpt, CE_NOTE, "?mpt_sas3%d SAS 3 Supported\n",
+		    mpt->m_instance);
+		mpt->m_MPI25 = TRUE;
+	} else {
+		mptsas_log(mpt, CE_NOTE, "?mpt_sas3%d MPI Version 0x%x\n",
+		    mpt->m_instance, msgversion);
+	}
 
 	/*
 	 * 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_MPI25 ? sizeof (MPI2_IEEE_SGE_SIMPLE64) :
+	    sizeof (MPI2_SGE_SIMPLE64)) - 1;
 
 	mpt->m_max_request_frames = (MPTSAS_MAX_DMA_SEGS -
 	    simple_sge_main) / simple_sge_next + 1;
@@ -290,7 +348,7 @@
 	 * Check if controller supports FW diag buffers and set flag to enable
 	 * each type.
 	 */
-	capabilities = ddi_get32(accessp, &factsreply->IOCCapabilities);
+	capabilities = mpt->m_ioc_capabilities;
 	if (capabilities & MPI2_IOCFACTS_CAPABILITY_DIAG_TRACE_BUFFER) {
 		mpt->m_fw_diag_buffer_list[MPI2_DIAG_BUF_TYPE_TRACE].enabled =
 		    TRUE;
@@ -603,6 +661,9 @@
 	ddi_put8(accessp, &init->WhoInit, MPI2_WHOINIT_HOST_DRIVER);
 	ddi_put16(accessp, &init->MsgVersion, MPI2_VERSION);
 	ddi_put16(accessp, &init->HeaderVersion, MPI2_HEADER_VERSION);
+	if (mpt->m_intr_type == DDI_INTR_TYPE_MSIX) {
+		ddi_put8(accessp, &init->HostMSIxVectors, mpt->m_intr_cnt);
+	}
 	ddi_put16(accessp, &init->SystemRequestFrameSize,
 	    mpt->m_req_frame_size / 4);
 	ddi_put16(accessp, &init->ReplyDescriptorPostQueueDepth,
@@ -614,7 +675,8 @@
 	 * 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->SenseBufferAddressHigh,
+	    (uint32_t)(mpt->m_req_sense_dma_addr >> 32));
 	ddi_put32(accessp, &init->SystemReplyAddressHigh,
 	    (uint32_t)(mpt->m_reply_frame_dma_addr >> 32));
 	ddi_put32(accessp, &init->SystemRequestFrameBaseAddress.High,
--- old/usr/src/uts/common/io/scsi/adapters/mpt_sas3/mptsas3_raid.c	2014-06-12 17:42:17.300395219 +0100
+++ new/usr/src/uts/common/io/scsi/adapters/mpt_sas3/mptsas3_raid.c	2014-06-12 17:42:17.306030121 +0100
@@ -22,6 +22,7 @@
 /*
  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
+ * Copyright (c) 2014, Tegile Systems Inc. All rights reserved.
  */
 
 /*
@@ -72,20 +73,20 @@
 
 #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_raid.h>
-#include <sys/scsi/adapters/mpt_sas/mpi/mpi2_tool.h>
+#include <sys/scsi/adapters/mpt_sas3/mpi/mpi2_type.h>
+#include <sys/scsi/adapters/mpt_sas3/mpi/mpi2.h>
+#include <sys/scsi/adapters/mpt_sas3/mpi/mpi2_cnfg.h>
+#include <sys/scsi/adapters/mpt_sas3/mpi/mpi2_init.h>
+#include <sys/scsi/adapters/mpt_sas3/mpi/mpi2_ioc.h>
+#include <sys/scsi/adapters/mpt_sas3/mpi/mpi2_raid.h>
+#include <sys/scsi/adapters/mpt_sas3/mpi/mpi2_tool.h>
 
 #pragma pack()
 
 /*
  * private header files.
  */
-#include <sys/scsi/adapters/mpt_sas/mptsas_var.h>
+#include <sys/scsi/adapters/mpt_sas3/mptsas3_var.h>
 
 static int mptsas_get_raid_wwid(mptsas_t *mpt, mptsas_raidvol_t *raidvol);
 
@@ -566,6 +567,7 @@
 void
 mptsas_raid_action_system_shutdown(mptsas_t *mpt)
 {
+	mptsas_reply_pqueue_t		*rpqp;
 	pMpi2RaidActionRequest_t	action;
 	uint8_t				ir_active = FALSE, reply_type;
 	uint8_t				function, found_reply = FALSE;
@@ -573,7 +575,8 @@
 	mptsas_slots_t			*slots = mpt->m_active;
 	int				config, vol;
 	mptsas_cmd_t			*cmd;
-	uint32_t			request_desc_low, reply_addr;
+	uint32_t			reply_addr;
+	uint64_t			request_desc;
 	int				cnt;
 	pMpi2ReplyDescriptorsUnion_t	reply_desc_union;
 	pMPI2DefaultReply_t		reply;
@@ -629,12 +632,13 @@
 
 	/*
 	 * Send RAID Action.
+	 * Defaults to MSIxIndex of 0, so check reply q 0 below.
 	 */
 	(void) ddi_dma_sync(mpt->m_dma_req_frame_hdl, 0, 0,
 	    DDI_DMA_SYNC_FORDEV);
-	request_desc_low = (cmd->cmd_slot << 16) +
+	request_desc = (cmd->cmd_slot << 16) +
 	    MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
-	MPTSAS_START_CMD(mpt, request_desc_low, 0);
+	MPTSAS_START_CMD(mpt, request_desc);
 
 	/*
 	 * Even though reply does not matter because the system is shutting
@@ -642,6 +646,7 @@
 	 * we don't want to leave it hanging if it's coming.  Poll because
 	 * interrupts are disabled when this function is called.
 	 */
+	rpqp = mpt->m_rep_post_queues;
 	for (cnt = 0; cnt < 5000; cnt++) {
 		/*
 		 * Check for a reply.
@@ -650,7 +655,7 @@
 		    DDI_DMA_SYNC_FORCPU);
 
 		reply_desc_union = (pMpi2ReplyDescriptorsUnion_t)
-		    MPTSAS_GET_NEXT_REPLY(mpt, mpt->m_post_index);
+		    MPTSAS_GET_NEXT_REPLY(rpqp, rpqp->rpq_index);
 
 		if (ddi_get32(mpt->m_acc_post_queue_hdl,
 		    &reply_desc_union->Words.Low) == 0xFFFFFFFF ||
@@ -725,20 +730,21 @@
 		 * 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],
+		    &((uint64_t *)(void *)rpqp->rpq_queue)[rpqp->rpq_index],
 		    0xFFFFFFFFFFFFFFFF);
 		(void) ddi_dma_sync(mpt->m_dma_post_queue_hdl, 0, 0,
 		    DDI_DMA_SYNC_FORDEV);
 
 		/*
-		 * Update the global reply index and keep looking for the
+		 * Update the reply index and keep looking for the
 		 * reply if not found yet.
 		 */
-		if (++mpt->m_post_index == mpt->m_post_queue_depth) {
-			mpt->m_post_index = 0;
+		if (++rpqp->rpq_index == mpt->m_post_queue_depth) {
+			rpqp->rpq_index = 0;
 		}
+
 		ddi_put32(mpt->m_datap, &mpt->m_reg->ReplyPostHostIndex,
-		    mpt->m_post_index);
+		    rpqp->rpq_index);
 		if (!found_reply) {
 			continue;
 		}
--- old/usr/src/uts/common/io/scsi/adapters/mpt_sas3/mptsas3_smhba.c	2014-06-12 17:42:17.480194710 +0100
+++ new/usr/src/uts/common/io/scsi/adapters/mpt_sas3/mptsas3_smhba.c	2014-06-12 17:42:17.486244539 +0100
@@ -22,9 +22,10 @@
 /*
  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
  * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 2014, Tegile Systems Inc. All rights reserved.
  */
 /*
- * This file contains SM-HBA support for MPT SAS driver
+ * This file contains SM-HBA support for MPT SAS3 driver
  */
 
 #if defined(lint) || defined(DEBUG)
@@ -41,19 +42,19 @@
 #include <sys/scsi/impl/scsi_sas.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>
+#include <sys/scsi/adapters/mpt_sas3/mpi/mpi2_type.h>
+#include <sys/scsi/adapters/mpt_sas3/mpi/mpi2.h>
+#include <sys/scsi/adapters/mpt_sas3/mpi/mpi2_cnfg.h>
+#include <sys/scsi/adapters/mpt_sas3/mpi/mpi2_init.h>
+#include <sys/scsi/adapters/mpt_sas3/mpi/mpi2_ioc.h>
+#include <sys/scsi/adapters/mpt_sas3/mpi/mpi2_sas.h>
 #pragma pack()
 
 /*
  * private header files.
  */
-#include <sys/scsi/adapters/mpt_sas/mptsas_var.h>
-#include <sys/scsi/adapters/mpt_sas/mptsas_smhba.h>
+#include <sys/scsi/adapters/mpt_sas3/mptsas3_var.h>
+#include <sys/scsi/adapters/mpt_sas3/mptsas3_smhba.h>
 
 /*
  * SM - HBA statics
@@ -331,7 +332,7 @@
 			    (longlong_t)mpt->un.m_base_wwid,
 			    ddi_get_instance(dip), i);
 
-			phyp->phy_stats = kstat_create("mptsas",
+			phyp->phy_stats = kstat_create("mptsas3",
 			    ddi_get_instance(dip), ks_name, KSTAT_SAS_PHY_CLASS,
 			    KSTAT_TYPE_NAMED, ndata, 0);
 
--- old/usr/src/uts/common/sys/scsi/adapters/mpt_sas3/mpi/mpi2.h	2014-06-12 17:42:17.641437660 +0100
+++ new/usr/src/uts/common/sys/scsi/adapters/mpt_sas3/mpi/mpi2.h	2014-06-12 17:42:17.647535558 +0100
@@ -20,8 +20,7 @@
  */
 
 /*
- * Copyright (c) 2000 to 2009, LSI Corporation.
- * All rights reserved.
+ *  Copyright (c) 2000-2012 LSI Corporation.
  *
  * Redistribution and use in source and binary forms of all code within
  * this file that is exclusively owned by LSI, with or without
@@ -53,7 +52,12 @@
  *                  scatter/gather formats.
  *  Creation Date:  June 21, 2006
  *
- *  mpi2.h Version:  02.00.13
+ *  mpi2.h Version:  02.00.xx
+ *
+ *  NOTE: Names (typedefs, defines, etc.) beginning with an MPI25 or Mpi25
+ *        prefix are for use only on MPI v2.5 products, and must not be used
+ *        with MPI v2.0 products. Unless otherwise noted, names beginning with
+ *        MPI2 or Mpi2 are for use with both MPI v2.0 and MPI v2.5 products.
  *
  *  Version History
  *  ---------------
@@ -111,19 +115,30 @@
 *
 *****************************************************************************/
 
-#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)
+
+/* major version for all MPI v2.x */
+#define MPI2_VERSION_MAJOR                  (0x02)
+
+/* minor version for MPI v2.0 compatible products */
+#define MPI2_VERSION_MINOR                  (0x00)
 #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            (0x0D)
+
+/* minor version for MPI v2.5 compatible products */
+#define MPI25_VERSION_MINOR                 (0x05)
+#define MPI25_VERSION ((MPI2_VERSION_MAJOR << MPI2_VERSION_MAJOR_SHIFT) |   \
+                                      MPI25_VERSION_MINOR)
+#define MPI2_VERSION_02_05                  (0x0205)
+
+
+/* Unit and Dev versioning for this MPI header set */
+#define MPI2_HEADER_VERSION_UNIT            (0x12)
 #define MPI2_HEADER_VERSION_DEV             (0x00)
 #define MPI2_HEADER_VERSION_UNIT_MASK       (0xFF00)
 #define MPI2_HEADER_VERSION_UNIT_SHIFT      (8)
@@ -183,6 +198,9 @@
     U32         RequestDescriptorPostLow;   /* 0xC0 */
     U32         RequestDescriptorPostHigh;  /* 0xC4 */
     U32         Reserved7[14];              /* 0xC8 */
+    U32		Reserved8[128];             /* 0x100 */
+    U32		Reserved10[3];              /* 0x300 */
+    U32		SuppReplyPostHostIndex[32]; /* 0x30C */
 } MPI2_SYSTEM_INTERFACE_REGS, MPI2_POINTER PTR_MPI2_SYSTEM_INTERFACE_REGS,
   Mpi2SystemInterfaceRegs_t, MPI2_POINTER pMpi2SystemInterfaceRegs_t;
 
@@ -280,6 +298,9 @@
  * Offset for the Reply Descriptor Post Queue
  */
 #define MPI2_REPLY_POST_HOST_INDEX_OFFSET       (0x0000006C)
+#define MPI2_REPLY_POST_HOST_INDEX_MASK         (0x00FFFFFF)
+#define MPI2_RPHI_MSIX_INDEX_MASK               (0xFF000000)
+#define MPI2_RPHI_MSIX_INDEX_SHIFT              (24)
 
 /*
  * Defines for the HCBSize and address
@@ -297,6 +318,12 @@
 #define MPI2_REQUEST_DESCRIPTOR_POST_LOW_OFFSET     (0x000000C0)
 #define MPI2_REQUEST_DESCRIPTOR_POST_HIGH_OFFSET    (0x000000C4)
 
+/*
+ * Offset for the Supplimentary Host Index Base
+ * For use with more than 8 MSI-X interrupts.
+ */
+#define MPI2_SUP_REPLY_POST_HOST_INDEX_OFFSET	(0x0000030C)
+
 
 /*****************************************************************************
 *
@@ -325,6 +352,7 @@
 #define MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY           (0x06)
 #define MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE            (0x08)
 #define MPI2_REQ_DESCRIPT_FLAGS_RAID_ACCELERATOR        (0x0A)
+#define MPI25_REQ_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO      (0x0C)
 
 #define MPI2_REQ_DESCRIPT_FLAGS_IOC_FIFO_MARKER (0x01)
 
@@ -384,6 +412,14 @@
   MPI2_POINTER pMpi2RAIDAcceleratorRequestDescriptor_t;
 
 
+/* Fast Path SCSI IO Request Descriptor */
+typedef MPI2_SCSI_IO_REQUEST_DESCRIPTOR
+    MPI25_FP_SCSI_IO_REQUEST_DESCRIPTOR,
+    MPI2_POINTER PTR_MPI25_FP_SCSI_IO_REQUEST_DESCRIPTOR,
+    Mpi25FastPathSCSIIORequestDescriptor_t,
+    MPI2_POINTER pMpi25FastPathSCSIIORequestDescriptor_t;
+
+
 /* union of Request Descriptors */
 typedef union _MPI2_REQUEST_DESCRIPTOR_UNION
 {
@@ -392,6 +428,7 @@
     MPI2_SCSI_IO_REQUEST_DESCRIPTOR             SCSIIO;
     MPI2_SCSI_TARGET_REQUEST_DESCRIPTOR         SCSITarget;
     MPI2_RAID_ACCEL_REQUEST_DESCRIPTOR          RAIDAccelerator;
+    MPI25_FP_SCSI_IO_REQUEST_DESCRIPTOR         FastPathSCSIIO;
     U64                                         Words;
 } MPI2_REQUEST_DESCRIPTOR_UNION, MPI2_POINTER PTR_MPI2_REQUEST_DESCRIPTOR_UNION,
   Mpi2RequestDescriptorUnion_t, MPI2_POINTER pMpi2RequestDescriptorUnion_t;
@@ -416,6 +453,7 @@
 #define MPI2_RPY_DESCRIPT_FLAGS_TARGETASSIST_SUCCESS        (0x02)
 #define MPI2_RPY_DESCRIPT_FLAGS_TARGET_COMMAND_BUFFER       (0x03)
 #define MPI2_RPY_DESCRIPT_FLAGS_RAID_ACCELERATOR_SUCCESS    (0x05)
+#define MPI25_RPY_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO_SUCCESS  (0x06)
 #define MPI2_RPY_DESCRIPT_FLAGS_UNUSED                      (0x0F)
 
 /* values for marking a reply descriptor as unused */
@@ -495,6 +533,14 @@
   MPI2_POINTER pMpi2RAIDAcceleratorSuccessReplyDescriptor_t;
 
 
+/* Fast Path SCSI IO Success Reply Descriptor */
+typedef MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR
+    MPI25_FP_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR,
+    MPI2_POINTER PTR_MPI25_FP_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR,
+    Mpi25FastPathSCSIIOSuccessReplyDescriptor_t,
+    MPI2_POINTER pMpi25FastPathSCSIIOSuccessReplyDescriptor_t;
+
+
 /* union of Reply Descriptors */
 typedef union _MPI2_REPLY_DESCRIPTORS_UNION
 {
@@ -504,6 +550,7 @@
     MPI2_TARGETASSIST_SUCCESS_REPLY_DESCRIPTOR      TargetAssistSuccess;
     MPI2_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR     TargetCommandBuffer;
     MPI2_RAID_ACCELERATOR_SUCCESS_REPLY_DESCRIPTOR  RAIDAcceleratorSuccess;
+    MPI25_FP_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR       FastPathSCSIIOSuccess;
     U64                                             Words;
 } MPI2_REPLY_DESCRIPTORS_UNION, MPI2_POINTER PTR_MPI2_REPLY_DESCRIPTORS_UNION,
   Mpi2ReplyDescriptorsUnion_t, MPI2_POINTER pMpi2ReplyDescriptorsUnion_t;
@@ -544,12 +591,15 @@
 #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 */
 #define MPI2_FUNCTION_RAID_ACCELERATOR              (0x2C) /* RAID Accelerator */
+#define MPI2_FUNCTION_HOST_BASED_DISCOVERY_ACTION   (0x2F) /* Host Based Discovery Action */
+#define MPI2_FUNCTION_PWR_MGMT_CONTROL              (0x30) /* Power Management Control */
+#define MPI2_FUNCTION_MIN_PRODUCT_SPECIFIC          (0xF0) /* beginning of product-specific range */
+#define MPI2_FUNCTION_MAX_PRODUCT_SPECIFIC          (0xFF) /* end of product-specific range */
 
 
 
 /* Doorbell functions */
 #define MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET        (0x40)
-/* #define MPI2_FUNCTION_IO_UNIT_RESET                 (0x41) */
 #define MPI2_FUNCTION_HANDSHAKE                     (0x42)
 
 
@@ -777,7 +827,7 @@
 
 
 /****************************************************************************
-*  MPI Chain Element structures
+*  MPI Chain Element structures - for MPI v2.0 products only
 ****************************************************************************/
 
 typedef struct _MPI2_SGE_CHAIN32
@@ -813,7 +863,7 @@
 
 
 /****************************************************************************
-*  MPI Transaction Context Element structures
+*  MPI Transaction Context Element structures - for MPI v2.0 products only
 ****************************************************************************/
 
 typedef struct _MPI2_SGE_TRANSACTION32
@@ -879,7 +929,7 @@
 
 
 /****************************************************************************
-*  MPI SGE union for IO SGL's
+*  MPI SGE union for IO SGL's - for MPI v2.0 products only
 ****************************************************************************/
 
 typedef struct _MPI2_MPI_SGE_IO_UNION
@@ -894,7 +944,7 @@
 
 
 /****************************************************************************
-*  MPI SGE union for SGL's with Simple and Transaction elements
+*  MPI SGE union for SGL's with Simple and Transaction elements - for MPI v2.0 products only
 ****************************************************************************/
 
 typedef struct _MPI2_SGE_TRANS_SIMPLE_UNION
@@ -945,9 +995,9 @@
 
 /* Element Type */
 
-#define MPI2_SGE_FLAGS_TRANSACTION_ELEMENT      (0x00)
+#define MPI2_SGE_FLAGS_TRANSACTION_ELEMENT      (0x00) /* for MPI v2.0 products only */
 #define MPI2_SGE_FLAGS_SIMPLE_ELEMENT           (0x10)
-#define MPI2_SGE_FLAGS_CHAIN_ELEMENT            (0x30)
+#define MPI2_SGE_FLAGS_CHAIN_ELEMENT            (0x30) /* for MPI v2.0 products only */
 #define MPI2_SGE_FLAGS_ELEMENT_MASK             (0x30)
 
 /* Address location */
@@ -959,6 +1009,9 @@
 #define MPI2_SGE_FLAGS_IOC_TO_HOST              (0x00)
 #define MPI2_SGE_FLAGS_HOST_TO_IOC              (0x04)
 
+#define MPI2_SGE_FLAGS_DEST                     (MPI2_SGE_FLAGS_IOC_TO_HOST)
+#define MPI2_SGE_FLAGS_SOURCE                   (MPI2_SGE_FLAGS_HOST_TO_IOC)
+
 /* Address Size */
 
 #define MPI2_SGE_FLAGS_32_BIT_ADDRESSING        (0x00)
@@ -1007,6 +1060,7 @@
 *  IEEE Simple Element structures
 ****************************************************************************/
 
+/* MPI2_IEEE_SGE_SIMPLE32 is for MPI v2.0 products only */
 typedef struct _MPI2_IEEE_SGE_SIMPLE32
 {
     U32                     Address;
@@ -1036,8 +1090,10 @@
 *  IEEE Chain Element structures
 ****************************************************************************/
 
+/* MPI2_IEEE_SGE_CHAIN32 is for MPI v2.0 products only */
 typedef MPI2_IEEE_SGE_SIMPLE32  MPI2_IEEE_SGE_CHAIN32;
 
+/* MPI2_IEEE_SGE_CHAIN64 is for MPI v2.0 products only */
 typedef MPI2_IEEE_SGE_SIMPLE64  MPI2_IEEE_SGE_CHAIN64;
 
 typedef union _MPI2_IEEE_SGE_CHAIN_UNION
@@ -1047,11 +1103,23 @@
 } MPI2_IEEE_SGE_CHAIN_UNION, MPI2_POINTER PTR_MPI2_IEEE_SGE_CHAIN_UNION,
   Mpi2IeeeSgeChainUnion_t, MPI2_POINTER pMpi2IeeeSgeChainUnion_t;
 
+/* MPI25_IEEE_SGE_CHAIN64 is for MPI v2.5 products only */
+typedef struct _MPI25_IEEE_SGE_CHAIN64
+{
+    U64                     Address;
+    U32                     Length;
+    U16                     Reserved1;
+    U8                      NextChainOffset;
+    U8                      Flags;
+} MPI25_IEEE_SGE_CHAIN64, MPI2_POINTER PTR_MPI25_IEEE_SGE_CHAIN64,
+  Mpi25IeeeSgeChain64_t, MPI2_POINTER pMpi25IeeeSgeChain64_t;
+
 
 /****************************************************************************
 *  All IEEE SGE types union
 ****************************************************************************/
 
+/* MPI2_IEEE_SGE_UNION is for MPI v2.0 products only */
 typedef struct _MPI2_IEEE_SGE_UNION
 {
     union
@@ -1064,12 +1132,25 @@
 
 
 /****************************************************************************
+*  IEEE SGE union for IO SGL's
+****************************************************************************/
+
+typedef union _MPI25_SGE_IO_UNION
+{
+    MPI2_IEEE_SGE_SIMPLE64      IeeeSimple;
+    MPI25_IEEE_SGE_CHAIN64      IeeeChain;
+} MPI25_SGE_IO_UNION, MPI2_POINTER PTR_MPI25_SGE_IO_UNION,
+  Mpi25SGEIOUnion_t, MPI2_POINTER pMpi25SGEIOUnion_t;
+
+
+/****************************************************************************
 *  IEEE SGE field definitions and masks
 ****************************************************************************/
 
 /* Flags field bit definitions */
 
 #define MPI2_IEEE_SGE_FLAGS_ELEMENT_TYPE_MASK   (0x80)
+#define MPI25_IEEE_SGE_FLAGS_END_OF_LIST        (0x40)
 
 #define MPI2_IEEE32_SGE_FLAGS_SHIFT             (24)
 
@@ -1083,10 +1164,11 @@
 /* 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_SYSTEM_ADDR         (0x00) /* IEEE Simple Element only */
+#define MPI2_IEEE_SGE_FLAGS_IOCDDR_ADDR         (0x01) /* IEEE Simple Element only */
 #define MPI2_IEEE_SGE_FLAGS_IOCPLB_ADDR         (0x02)
-#define MPI2_IEEE_SGE_FLAGS_IOCPLBNTA_ADDR      (0x03)
+#define MPI2_IEEE_SGE_FLAGS_IOCPLBNTA_ADDR      (0x03) /* IEEE Simple Element only */
+#define MPI2_IEEE_SGE_FLAGS_SYSTEMPLBCPI_ADDR   (0x03) /* IEEE Chain Element only */
 
 
 /****************************************************************************
--- old/usr/src/uts/common/sys/scsi/adapters/mpt_sas3/mpi/mpi2_cnfg.h	2014-06-12 17:42:17.831489616 +0100
+++ new/usr/src/uts/common/sys/scsi/adapters/mpt_sas3/mpi/mpi2_cnfg.h	2014-06-12 17:42:17.837884300 +0100
@@ -20,8 +20,7 @@
  */
 
 /*
- * Copyright (c) 2000 to 2009, LSI Corporation.
- * All rights reserved.
+ *  Copyright (c) 2000-2012 LSI Corporation.
  *
  * Redistribution and use in source and binary forms of all code within
  * this file that is exclusively owned by LSI, with or without
@@ -51,7 +50,12 @@
  *          Title:  MPI Configuration messages and pages
  *  Creation Date:  November 10, 2006
  *
- *    mpi2_cnfg.h Version:  02.00.12
+ *  mpi2_cnfg.h Version:  02.00.xx
+ *
+ *  NOTE: Names (typedefs, defines, etc.) beginning with an MPI25 or Mpi25
+ *        prefix are for use only on MPI v2.5 products, and must not be used
+ *        with MPI v2.0 products. Unless otherwise noted, names beginning with
+ *        MPI2 or Mpi2 are for use with both MPI v2.0 and MPI v2.5 products.
  *
  *  Version History
  *  ---------------
@@ -152,6 +156,33 @@
  *                      to SAS Device Page 0 Flags field.
  *                      Added PhyInfo defines for power condition.
  *                      Added Ethernet configuration pages.
+ *  10-28-09  02.00.13  Added MPI2_IOUNITPAGE1_ENABLE_HOST_BASED_DISCOVERY.
+ *                      Added SAS PHY Page 4 structure and defines.
+ *  02-10-10  02.00.14  Modified the comments for the configuration page
+ *                      structures that contain an array of data. The host
+ *                      should use the "count" field in the page data (e.g. the
+ *                      NumPhys field) to determine the number of valid elements
+ *                      in the array.
+ *                      Added/modified some MPI2_MFGPAGE_DEVID_SAS defines.
+ *                      Added PowerManagementCapabilities to IO Unit Page 7.
+ *                      Added PortWidthModGroup field to
+ *                      MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS.
+ *                      Added MPI2_CONFIG_PAGE_SASIOUNIT_6 and related defines.
+ *                      Added MPI2_CONFIG_PAGE_SASIOUNIT_7 and related defines.
+ *                      Added MPI2_CONFIG_PAGE_SASIOUNIT_8 and related defines.
+ *  05-12-10  02.00.15  Added MPI2_RAIDVOL0_STATUS_FLAG_VOL_NOT_CONSISTENT
+ *                      define.
+ *                      Added MPI2_PHYSDISK0_INCOMPATIBLE_MEDIA_TYPE define.
+ *                      Added MPI2_SAS_NEG_LINK_RATE_UNSUPPORTED_PHY define.
+ *  08-11-10  02.00.16  Removed IO Unit Page 1 device path (multi-pathing)
+ *                      defines.
+ *  11-10-10  02.00.17  Added ReceptacleID field (replacing Reserved1) to
+ *                      MPI2_MANPAGE7_CONNECTOR_INFO and reworked defines for
+ *                      the Pinout field.
+ *                      Added BoardTemperature and BoardTemperatureUnits fields
+ *                      to MPI2_CONFIG_PAGE_IO_UNIT_7.
+ *                      Added MPI2_CONFIG_EXTPAGETYPE_EXT_MANUFACTURING define
+ *                      and MPI2_CONFIG_PAGE_EXT_MAN_PS structure.
  *  --------------------------------------------------------------------------
  */
 
@@ -235,6 +266,7 @@
 #define MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING      (0x17)
 #define MPI2_CONFIG_EXTPAGETYPE_SAS_PORT            (0x18)
 #define MPI2_CONFIG_EXTPAGETYPE_ETHERNET            (0x19)
+#define MPI2_CONFIG_EXTPAGETYPE_EXT_MANUFACTURING   (0x1A)
 
 
 /*****************************************************************************
@@ -401,7 +433,7 @@
 
 #define MPI2_MFGPAGE_VENDORID_LSI                   (0x1000)
 
-/* SAS */
+/* MPI v2.0 SAS products */
 #define MPI2_MFGPAGE_DEVID_SAS2004                  (0x0070)
 #define MPI2_MFGPAGE_DEVID_SAS2008                  (0x0072)
 #define MPI2_MFGPAGE_DEVID_SAS2108_1                (0x0074)
@@ -410,6 +442,8 @@
 #define MPI2_MFGPAGE_DEVID_SAS2116_1                (0x0064)
 #define MPI2_MFGPAGE_DEVID_SAS2116_2                (0x0065)
 
+#define MPI2_MFGPAGE_DEVID_SSS6200                  (0x007E)
+
 #define MPI2_MFGPAGE_DEVID_SAS2208_1                (0x0080)
 #define MPI2_MFGPAGE_DEVID_SAS2208_2                (0x0081)
 #define MPI2_MFGPAGE_DEVID_SAS2208_3                (0x0082)
@@ -418,7 +452,19 @@
 #define MPI2_MFGPAGE_DEVID_SAS2208_6                (0x0085)
 #define MPI2_MFGPAGE_DEVID_SAS2208_7                (0x0086)
 #define MPI2_MFGPAGE_DEVID_SAS2208_8                (0x0087)
-
+#define MPI2_MFGPAGE_DEVID_SAS2308_1                (0x0086)
+#define MPI2_MFGPAGE_DEVID_SAS2308_2                (0x0087)
+#define MPI2_MFGPAGE_DEVID_SAS2308_3                (0x006E)
+
+/* MPI v2.5 SAS products */
+#define MPI25_MFGPAGE_DEVID_SAS3004                 (0x0096)
+#define MPI25_MFGPAGE_DEVID_SAS3008                 (0x0097)
+#define MPI25_MFGPAGE_DEVID_SAS3108_1               (0x0090)
+#define MPI25_MFGPAGE_DEVID_SAS3108_2               (0x0091)
+#define MPI25_MFGPAGE_DEVID_SAS3108_3               (0x0092)
+#define MPI25_MFGPAGE_DEVID_SAS3108_4               (0x0093)
+#define MPI25_MFGPAGE_DEVID_SAS3108_5               (0x0094)
+#define MPI25_MFGPAGE_DEVID_SAS3108_6               (0x0095)
 
 /* Manufacturing Page 0 */
 
@@ -632,7 +678,7 @@
     U32                         Pinout;                 /* 0x00 */
     U8                          Connector[16];          /* 0x04 */
     U8                          Location;               /* 0x14 */
-    U8                          Reserved1;              /* 0x15 */
+    U8                          ReceptacleID;           /* 0x15 */
     U16                         Slot;                   /* 0x16 */
     U32                         Reserved2;              /* 0x18 */
 } MPI2_MANPAGE7_CONNECTOR_INFO, MPI2_POINTER PTR_MPI2_MANPAGE7_CONNECTOR_INFO,
@@ -682,7 +728,7 @@
   MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_7,
   Mpi2ManufacturingPage7_t, MPI2_POINTER pMpi2ManufacturingPage7_t;
 
-#define MPI2_MANUFACTURING7_PAGEVERSION                 (0x00)
+#define MPI2_MANUFACTURING7_PAGEVERSION                 (0x01)
 
 /* defines for the Flags field */
 #define MPI2_MANPAGE7_FLAG_USE_SLOT_INFO                (0x00000001)
@@ -757,7 +803,11 @@
 #define MPI2_IOUNITPAGE1_PAGEVERSION                    (0x04)
 
 /* IO Unit Page 1 Flags defines */
+#define MPI25_IOUNITPAGE1_NEW_DEVICE_FAST_PATH_DISABLE  (0x00002000)
+#define MPI25_IOUNITPAGE1_DISABLE_FAST_PATH             (0x00001000)
+#define MPI2_IOUNITPAGE1_ENABLE_HOST_BASED_DISCOVERY    (0x00000800)
 #define MPI2_IOUNITPAGE1_MASK_SATA_WRITE_CACHE          (0x00000600)
+#define MPI2_IOUNITPAGE1_SATA_WRITE_CACHE_SHIFT         (9)
 #define MPI2_IOUNITPAGE1_ENABLE_SATA_WRITE_CACHE        (0x00000000)
 #define MPI2_IOUNITPAGE1_DISABLE_SATA_WRITE_CACHE       (0x00000200)
 #define MPI2_IOUNITPAGE1_UNCHANGED_SATA_WRITE_CACHE     (0x00000400)
@@ -867,15 +917,17 @@
     U8                      PCIeWidth;                              /* 0x06 */
     U8                      PCIeSpeed;                              /* 0x07 */
     U32                     ProcessorState;                         /* 0x08 */
-    U32                     Reserved2;                              /* 0x0C */
+    U32                     PowerManagementCapabilities;            /* 0x0C */
     U16                     IOCTemperature;                         /* 0x10 */
     U8                      IOCTemperatureUnits;                    /* 0x12 */
     U8                      IOCSpeed;                               /* 0x13 */
-    U32                     Reserved3;                              /* 0x14 */
+    U16                     BoardTemperature;                       /* 0x14 */
+    U8                      BoardTemperatureUnits;                  /* 0x16 */
+    U8                      Reserved3;                              /* 0x17 */
 } MPI2_CONFIG_PAGE_IO_UNIT_7, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_7,
   Mpi2IOUnitPage7_t, MPI2_POINTER pMpi2IOUnitPage7_t;
 
-#define MPI2_IOUNITPAGE7_PAGEVERSION                    (0x00)
+#define MPI2_IOUNITPAGE7_PAGEVERSION                    (0x02)
 
 /* defines for IO Unit Page 7 PCIeWidth field */
 #define MPI2_IOUNITPAGE7_PCIE_WIDTH_X1              (0x01)
@@ -896,6 +948,13 @@
 #define MPI2_IOUNITPAGE7_PSTATE_DISABLED            (0x01)
 #define MPI2_IOUNITPAGE7_PSTATE_ENABLED             (0x02)
 
+/* defines for IO Unit Page 7 PowerManagementCapabilities field */
+#define MPI2_IOUNITPAGE7_PMCAP_12_5_PCT_IOCSPEED    (0x00000400)
+#define MPI2_IOUNITPAGE7_PMCAP_25_0_PCT_IOCSPEED    (0x00000200)
+#define MPI2_IOUNITPAGE7_PMCAP_50_0_PCT_IOCSPEED    (0x00000100)
+#define MPI2_IOUNITPAGE7_PMCAP_PCIE_WIDTH_CHANGE    (0x00000008)
+#define MPI2_IOUNITPAGE7_PMCAP_PCIE_SPEED_CHANGE    (0x00000004)
+
 /* defines for IO Unit Page 7 IOCTemperatureUnits field */
 #define MPI2_IOUNITPAGE7_IOC_TEMP_NOT_PRESENT       (0x00)
 #define MPI2_IOUNITPAGE7_IOC_TEMP_FAHRENHEIT        (0x01)
@@ -907,6 +966,10 @@
 #define MPI2_IOUNITPAGE7_IOC_SPEED_QUARTER          (0x04)
 #define MPI2_IOUNITPAGE7_IOC_SPEED_EIGHTH           (0x08)
 
+/* defines for IO Unit Page 7 BoardTemperatureUnits field */
+#define MPI2_IOUNITPAGE7_BOARD_TEMP_NOT_PRESENT     (0x00)
+#define MPI2_IOUNITPAGE7_BOARD_TEMP_FAHRENHEIT      (0x01)
+#define MPI2_IOUNITPAGE7_BOARD_TEMP_CELSIUS         (0x02)
 
 
 /****************************************************************************
@@ -1370,6 +1433,7 @@
 #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_VOL_NOT_CONSISTENT        (0x00000080)
 #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)
@@ -1492,11 +1556,14 @@
 #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_MEDIA_TYPE          (0x06)
 #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_PROTOCOL_MASK             (0x03)
 #define MPI2_PHYSDISK0_ATTRIB_SAS_PROTOCOL              (0x02)
 #define MPI2_PHYSDISK0_ATTRIB_SATA_PROTOCOL             (0x01)
 
@@ -1568,9 +1635,11 @@
 #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_UNSUPPORTED_PHY          (0x06)
 #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)
+#define MPI25_SAS_NEG_LINK_RATE_12_0                    (0x0B)
 
 
 /* values for AttachedPhyInfo fields */
@@ -1594,6 +1663,7 @@
 #define MPI2_SAS_PHYINFO_PHY_VACANT                     (0x80000000)
 
 #define MPI2_SAS_PHYINFO_PHY_POWER_CONDITION_MASK       (0x18000000)
+#define MPI2_SAS_PHYINFO_SHIFT_PHY_POWER_CONDITION      (27)
 #define MPI2_SAS_PHYINFO_PHY_POWER_ACTIVE               (0x00000000)
 #define MPI2_SAS_PHYINFO_PHY_POWER_PARTIAL              (0x08000000)
 #define MPI2_SAS_PHYINFO_PHY_POWER_SLUMBER              (0x10000000)
@@ -1641,6 +1711,7 @@
 #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)
+#define MPI25_SAS_PRATE_MIN_RATE_12_0                   (0x0B)
 
 
 /* values for SAS HwLinkRate fields */
@@ -1652,6 +1723,7 @@
 #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)
+#define MPI25_SAS_HWRATE_MIN_RATE_12_0                  (0x0B)
 
 
 
@@ -1819,10 +1891,12 @@
 #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 MPI25_SASIOUNIT1_MAX_RATE_12_0                              (0xB0)
 #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)
+#define MPI25_SASIOUNIT1_MIN_RATE_12_0                              (0x0B)
 
 /* see mpi2_sas.h for values for SAS IO Unit Page 1 ControllerPhyDeviceInfo values */
 
@@ -1878,7 +1952,7 @@
 typedef struct _MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS
 {
     U8          ControlFlags;               /* 0x00 */
-    U8          Reserved1;                  /* 0x01 */
+    U8          PortWidthModGroup;          /* 0x01 */
     U16         InactivityTimerExponent;    /* 0x02 */
     U8          SATAPartialTimeout;         /* 0x04 */
     U8          Reserved2;                  /* 0x05 */
@@ -1898,6 +1972,9 @@
 #define MPI2_SASIOUNIT5_CONTROL_SATA_SLUMBER_ENABLE     (0x02)
 #define MPI2_SASIOUNIT5_CONTROL_SATA_PARTIAL_ENABLE     (0x01)
 
+/* defines for PortWidthModeGroup field */
+#define MPI2_SASIOUNIT5_PWMG_DISABLE                    (0xFF)
+
 /* defines for InactivityTimerExponent field */
 #define MPI2_SASIOUNIT5_ITE_MASK_SAS_SLUMBER            (0x7000)
 #define MPI2_SASIOUNIT5_ITE_SHIFT_SAS_SLUMBER           (12)
@@ -1937,7 +2014,137 @@
   MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_5,
   Mpi2SasIOUnitPage5_t, MPI2_POINTER pMpi2SasIOUnitPage5_t;
 
-#define MPI2_SASIOUNITPAGE5_PAGEVERSION     (0x00)
+#define MPI2_SASIOUNITPAGE5_PAGEVERSION     (0x01)
+
+
+/* SAS IO Unit Page 6 */
+
+typedef struct _MPI2_SAS_IO_UNIT6_PORT_WIDTH_MOD_GROUP_STATUS
+{
+    U8          CurrentStatus;              /* 0x00 */
+    U8          CurrentModulation;          /* 0x01 */
+    U8          CurrentUtilization;         /* 0x02 */
+    U8          Reserved1;                  /* 0x03 */
+    U32         Reserved2;                  /* 0x04 */
+} MPI2_SAS_IO_UNIT6_PORT_WIDTH_MOD_GROUP_STATUS,
+  MPI2_POINTER PTR_MPI2_SAS_IO_UNIT6_PORT_WIDTH_MOD_GROUP_STATUS,
+  Mpi2SasIOUnit6PortWidthModGroupStatus_t,
+  MPI2_POINTER pMpi2SasIOUnit6PortWidthModGroupStatus_t;
+
+/* defines for CurrentStatus field */
+#define MPI2_SASIOUNIT6_STATUS_UNAVAILABLE                      (0x00)
+#define MPI2_SASIOUNIT6_STATUS_UNCONFIGURED                     (0x01)
+#define MPI2_SASIOUNIT6_STATUS_INVALID_CONFIG                   (0x02)
+#define MPI2_SASIOUNIT6_STATUS_LINK_DOWN                        (0x03)
+#define MPI2_SASIOUNIT6_STATUS_OBSERVATION_ONLY                 (0x04)
+#define MPI2_SASIOUNIT6_STATUS_INACTIVE                         (0x05)
+#define MPI2_SASIOUNIT6_STATUS_ACTIVE_IOUNIT                    (0x06)
+#define MPI2_SASIOUNIT6_STATUS_ACTIVE_HOST                      (0x07)
+
+/* defines for CurrentModulation field */
+#define MPI2_SASIOUNIT6_MODULATION_25_PERCENT                   (0x00)
+#define MPI2_SASIOUNIT6_MODULATION_50_PERCENT                   (0x01)
+#define MPI2_SASIOUNIT6_MODULATION_75_PERCENT                   (0x02)
+#define MPI2_SASIOUNIT6_MODULATION_100_PERCENT                  (0x03)
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check the value returned for NumGroups at runtime.
+ */
+#ifndef MPI2_SAS_IOUNIT6_GROUP_MAX
+#define MPI2_SAS_IOUNIT6_GROUP_MAX      (1)
+#endif
+
+typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_6
+{
+    MPI2_CONFIG_EXTENDED_PAGE_HEADER    Header;                     /* 0x00 */
+    U32                                 Reserved1;                  /* 0x08 */
+    U32                                 Reserved2;                  /* 0x0C */
+    U8                                  NumGroups;                  /* 0x10 */
+    U8                                  Reserved3;                  /* 0x11 */
+    U16                                 Reserved4;                  /* 0x12 */
+    MPI2_SAS_IO_UNIT6_PORT_WIDTH_MOD_GROUP_STATUS
+        PortWidthModulationGroupStatus[MPI2_SAS_IOUNIT6_GROUP_MAX]; /* 0x14 */
+} MPI2_CONFIG_PAGE_SASIOUNIT_6,
+  MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_6,
+  Mpi2SasIOUnitPage6_t, MPI2_POINTER pMpi2SasIOUnitPage6_t;
+
+#define MPI2_SASIOUNITPAGE6_PAGEVERSION     (0x00)
+
+
+/* SAS IO Unit Page 7 */
+
+typedef struct _MPI2_SAS_IO_UNIT7_PORT_WIDTH_MOD_GROUP_SETTINGS
+{
+    U8          Flags;                      /* 0x00 */
+    U8          Reserved1;                  /* 0x01 */
+    U16         Reserved2;                  /* 0x02 */
+    U8          Threshold75Pct;             /* 0x04 */
+    U8          Threshold50Pct;             /* 0x05 */
+    U8          Threshold25Pct;             /* 0x06 */
+    U8          Reserved3;                  /* 0x07 */
+} MPI2_SAS_IO_UNIT7_PORT_WIDTH_MOD_GROUP_SETTINGS,
+  MPI2_POINTER PTR_MPI2_SAS_IO_UNIT7_PORT_WIDTH_MOD_GROUP_SETTINGS,
+  Mpi2SasIOUnit7PortWidthModGroupSettings_t,
+  MPI2_POINTER pMpi2SasIOUnit7PortWidthModGroupSettings_t;
+
+/* defines for Flags field */
+#define MPI2_SASIOUNIT7_FLAGS_ENABLE_PORT_WIDTH_MODULATION  (0x01)
+
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check the value returned for NumGroups at runtime.
+ */
+#ifndef MPI2_SAS_IOUNIT7_GROUP_MAX
+#define MPI2_SAS_IOUNIT7_GROUP_MAX      (1)
+#endif
+
+typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_7
+{
+    MPI2_CONFIG_EXTENDED_PAGE_HEADER            Header;             /* 0x00 */
+    U8                                          SamplingInterval;   /* 0x08 */
+    U8                                          WindowLength;       /* 0x09 */
+    U16                                         Reserved1;          /* 0x0A */
+    U32                                         Reserved2;          /* 0x0C */
+    U32                                         Reserved3;          /* 0x10 */
+    U8                                          NumGroups;          /* 0x14 */
+    U8                                          Reserved4;          /* 0x15 */
+    U16                                         Reserved5;          /* 0x16 */
+    MPI2_SAS_IO_UNIT7_PORT_WIDTH_MOD_GROUP_SETTINGS
+        PortWidthModulationGroupSettings[MPI2_SAS_IOUNIT7_GROUP_MAX]; /* 0x18 */
+} MPI2_CONFIG_PAGE_SASIOUNIT_7,
+  MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_7,
+  Mpi2SasIOUnitPage7_t, MPI2_POINTER pMpi2SasIOUnitPage7_t;
+
+#define MPI2_SASIOUNITPAGE7_PAGEVERSION     (0x00)
+
+
+/* SAS IO Unit Page 8 */
+
+typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_8
+{
+    MPI2_CONFIG_EXTENDED_PAGE_HEADER    Header;                             /* 0x00 */
+    U32                                 Reserved1;                          /* 0x08 */
+    U32                                 PowerManagementCapabilities;        /* 0x0C */
+    U32                                 Reserved2;                          /* 0x10 */
+} MPI2_CONFIG_PAGE_SASIOUNIT_8,
+  MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_8,
+  Mpi2SasIOUnitPage8_t, MPI2_POINTER pMpi2SasIOUnitPage8_t;
+
+#define MPI2_SASIOUNITPAGE8_PAGEVERSION     (0x00)
+
+/* defines for PowerManagementCapabilities field */
+#define MPI2_SASIOUNIT8_PM_HOST_PORT_WIDTH_MOD          (0x000001000)
+#define MPI2_SASIOUNIT8_PM_HOST_SAS_SLUMBER_MODE        (0x000000800)
+#define MPI2_SASIOUNIT8_PM_HOST_SAS_PARTIAL_MODE        (0x000000400)
+#define MPI2_SASIOUNIT8_PM_HOST_SATA_SLUMBER_MODE       (0x000000200)
+#define MPI2_SASIOUNIT8_PM_HOST_SATA_PARTIAL_MODE       (0x000000100)
+#define MPI2_SASIOUNIT8_PM_IOUNIT_PORT_WIDTH_MOD        (0x000000010)
+#define MPI2_SASIOUNIT8_PM_IOUNIT_SAS_SLUMBER_MODE      (0x000000008)
+#define MPI2_SASIOUNIT8_PM_IOUNIT_SAS_PARTIAL_MODE      (0x000000004)
+#define MPI2_SASIOUNIT8_PM_IOUNIT_SATA_SLUMBER_MODE     (0x000000002)
+#define MPI2_SASIOUNIT8_PM_IOUNIT_SATA_PARTIAL_MODE     (0x000000001)
 
 
 
@@ -2124,6 +2331,8 @@
 /* see mpi2_sas.h for values for SAS Device Page 0 DeviceInfo values */
 
 /* values for SAS Device Page 0 Flags field */
+#define MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH           (0x4000)
+#define MPI25_SAS_DEVICE0_FLAGS_FAST_PATH_CAPABLE           (0x2000)
 #define MPI2_SAS_DEVICE0_FLAGS_SLUMBER_PM_CAPABLE           (0x1000)
 #define MPI2_SAS_DEVICE0_FLAGS_PARTIAL_PM_CAPABLE           (0x0800)
 #define MPI2_SAS_DEVICE0_FLAGS_SATA_ASYNCHRONOUS_NOTIFY     (0x0400)
@@ -2341,6 +2550,27 @@
 #define MPI2_SASPHY3_PAGEVERSION            (0x00)
 
 
+/* SAS PHY Page 4 */
+
+typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_4
+{
+    MPI2_CONFIG_EXTENDED_PAGE_HEADER    Header;                     /* 0x00 */
+    U16                                 Reserved1;                  /* 0x08 */
+    U8                                  Reserved2;                  /* 0x0A */
+    U8                                  Flags;                      /* 0x0B */
+    U8                                  InitialFrame[28];           /* 0x0C */
+} MPI2_CONFIG_PAGE_SAS_PHY_4, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_PHY_4,
+  Mpi2SasPhyPage4_t, MPI2_POINTER pMpi2SasPhyPage4_t;
+
+#define MPI2_SASPHY4_PAGEVERSION            (0x00)
+
+/* values for the Flags field */
+#define MPI2_SASPHY4_FLAGS_FRAME_VALID        (0x02)
+#define MPI2_SASPHY4_FLAGS_SATA_FRAME         (0x01)
+
+
+
+
 /****************************************************************************
 *   SAS Port Config Pages
 ****************************************************************************/
@@ -2662,5 +2892,25 @@
 #define MPI2_ETHPG1_MS_DATA_RATE_1GBIT              (0x03)
 
 
+/****************************************************************************
+*   Extended Manufacturing Config Pages
+****************************************************************************/
+
+/*
+ * Generic structure to use for product-specific extended manufacturing pages
+ * (currently Extended Manufacturing Page 40 through Extended Manufacturing
+ * Page 60).
+ */
+
+typedef struct _MPI2_CONFIG_PAGE_EXT_MAN_PS
+{
+    MPI2_CONFIG_EXTENDED_PAGE_HEADER    Header;                 /* 0x00 */
+    U32                                 ProductSpecificInfo;    /* 0x08 */
+} MPI2_CONFIG_PAGE_EXT_MAN_PS,
+  MPI2_POINTER PTR_MPI2_CONFIG_PAGE_EXT_MAN_PS,
+  Mpi2ExtManufacturingPagePS_t, MPI2_POINTER pMpi2ExtManufacturingPagePS_t;
+
+/* PageVersion should be provided by product-specific code */
+
 #endif
 
--- old/usr/src/uts/common/sys/scsi/adapters/mpt_sas3/mpi/mpi2_init.h	2014-06-12 17:42:18.075622334 +0100
+++ new/usr/src/uts/common/sys/scsi/adapters/mpt_sas3/mpi/mpi2_init.h	2014-06-12 17:42:18.081444982 +0100
@@ -20,8 +20,7 @@
  */
 
 /*
- * Copyright (c) 2000 to 2009, LSI Corporation.
- * All rights reserved.
+ *  Copyright (c) 2000-2012 LSI Corporation.
  *
  * Redistribution and use in source and binary forms of all code within
  * this file that is exclusively owned by LSI, with or without
@@ -51,7 +50,12 @@
  *          Title:  MPI SCSI initiator mode messages and structures
  *  Creation Date:  June 23, 2006
  *
- *    mpi2_init.h Version:  02.00.07
+ *  mpi2_init.h Version:  02.00.xx
+ *
+ *  NOTE: Names (typedefs, defines, etc.) beginning with an MPI25 or Mpi25
+ *        prefix are for use only on MPI v2.5 products, and must not be used
+ *        with MPI v2.0 products. Unless otherwise noted, names beginning with
+ *        MPI2 or Mpi2 are for use with both MPI v2.0 and MPI v2.5 products.
  *
  *  Version History
  *  ---------------
@@ -72,6 +76,13 @@
  *                      Query Asynchronous Event.
  *                      Defined two new bits in the SlotStatus field of the SCSI
  *                      Enclosure Processor Request and Reply.
+ *  10-28-09  02.00.08  Added defines for decoding the ResponseInfo bytes for
+ *                      both SCSI IO Error Reply and SCSI Task Management Reply.
+ *                      Added ResponseInfo field to MPI2_SCSI_TASK_MANAGE_REPLY.
+ *                      Added MPI2_SCSITASKMGMT_RSP_TM_OVERLAPPED_TAG define.
+ *  02-10-10  02.00.09  Removed unused structure that had "#if 0" around it.
+ *  05-12-10  02.00.10  Added optional vendor-unique region to SCSI IO Request.
+ *  11-10-10  02.00.11  Added MPI2_SCSIIO_NUM_SGLOFFSETS define.
  *  --------------------------------------------------------------------------
  */
 
@@ -98,20 +109,6 @@
 } 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];
@@ -120,7 +117,7 @@
 } MPI2_SCSI_IO_CDB_UNION, MPI2_POINTER PTR_MPI2_SCSI_IO_CDB_UNION,
   Mpi2ScsiIoCdb_t, MPI2_POINTER pMpi2ScsiIoCdb_t;
 
-/* SCSI IO Request Message */
+/* MPI v2.0 SCSI IO Request Message */
 typedef struct _MPI2_SCSI_IO_REQUEST
 {
     U16                     DevHandle;                      /* 0x00 */
@@ -186,6 +183,9 @@
 #define MPI2_SCSIIO_SGLFLAGS_SGL1_SHIFT             (4)
 #define MPI2_SCSIIO_SGLFLAGS_SGL0_SHIFT             (0)
 
+/* number of SGLOffset fields */
+#define MPI2_SCSIIO_NUM_SGLOFFSETS                  (4)
+
 /* SCSI IO IoFlags bits */
 
 /* Large CDB Address Space */
@@ -250,6 +250,120 @@
 #define MPI2_SCSIIO_CONTROL_TLR_OFF             (0x00000080)
 
 
+/* MPI v2.5 CDB field */
+typedef union _MPI25_SCSI_IO_CDB_UNION
+{
+    U8                      CDB32[32];
+    MPI2_SCSI_IO_CDB_EEDP32 EEDP32;
+    MPI2_IEEE_SGE_SIMPLE64  SGE;
+} MPI25_SCSI_IO_CDB_UNION, MPI2_POINTER PTR_MPI25_SCSI_IO_CDB_UNION,
+  Mpi25ScsiIoCdb_t, MPI2_POINTER pMpi25ScsiIoCdb_t;
+
+/* MPI v2.5 SCSI IO Request Message */
+typedef struct _MPI25_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 */
+    U8                      DMAFlags;                       /* 0x10 */
+    U8                      Reserved5;                      /* 0x11 */
+    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 */
+    U16                     EEDPBlockSize;                  /* 0x28 */
+    U16                     Reserved6;                      /* 0x2A */
+    U32                     SecondaryReferenceTag;          /* 0x2C */
+    U16                     SecondaryApplicationTag;        /* 0x30 */
+    U16                     ApplicationTagTranslationMask;  /* 0x32 */
+    U8                      LUN[8];                         /* 0x34 */
+    U32                     Control;                        /* 0x3C */
+    MPI25_SCSI_IO_CDB_UNION CDB;                            /* 0x40 */
+
+#ifdef MPI25_SCSI_IO_VENDOR_UNIQUE_REGION /* typically this is left undefined */
+    MPI25_SCSI_IO_VENDOR_UNIQUE VendorRegion;
+#endif
+
+    MPI25_SGE_IO_UNION      SGL;                            /* 0x60 */
+
+} MPI25_SCSI_IO_REQUEST, MPI2_POINTER PTR_MPI25_SCSI_IO_REQUEST,
+  Mpi25SCSIIORequest_t, MPI2_POINTER pMpi25SCSIIORequest_t;
+
+/* use MPI2_SCSIIO_MSGFLAGS_ defines for the MsgFlags field */
+
+/* Defines for the DMAFlags field
+ *  Each setting affects 4 SGLS, from SGL0 to SGL3.
+ *      D = Data
+ *      C = Cache DIF
+ *      I = Interleaved
+ *      H = Host DIF
+ */
+#define MPI25_SCSIIO_DMAFLAGS_OP_MASK               (0x0F)
+#define MPI25_SCSIIO_DMAFLAGS_OP_D_D_D_D            (0x00)
+#define MPI25_SCSIIO_DMAFLAGS_OP_D_D_D_C            (0x01)
+#define MPI25_SCSIIO_DMAFLAGS_OP_D_D_D_I            (0x02)
+#define MPI25_SCSIIO_DMAFLAGS_OP_D_D_C_C            (0x03)
+#define MPI25_SCSIIO_DMAFLAGS_OP_D_D_C_I            (0x04)
+#define MPI25_SCSIIO_DMAFLAGS_OP_D_D_I_I            (0x05)
+#define MPI25_SCSIIO_DMAFLAGS_OP_D_C_C_C            (0x06)
+#define MPI25_SCSIIO_DMAFLAGS_OP_D_C_C_I            (0x07)
+#define MPI25_SCSIIO_DMAFLAGS_OP_D_C_I_I            (0x08)
+#define MPI25_SCSIIO_DMAFLAGS_OP_D_I_I_I            (0x09)
+#define MPI25_SCSIIO_DMAFLAGS_OP_D_H_D_D            (0x0A)
+#define MPI25_SCSIIO_DMAFLAGS_OP_D_H_D_C            (0x0B)
+#define MPI25_SCSIIO_DMAFLAGS_OP_D_H_D_I            (0x0C)
+#define MPI25_SCSIIO_DMAFLAGS_OP_D_H_C_C            (0x0D)
+#define MPI25_SCSIIO_DMAFLAGS_OP_D_H_C_I            (0x0E)
+#define MPI25_SCSIIO_DMAFLAGS_OP_D_H_I_I            (0x0F)
+
+/* number of SGLOffset fields */
+#define MPI25_SCSIIO_NUM_SGLOFFSETS                 (4)
+
+/* defines for the IoFlags field */
+#define MPI25_SCSIIO_IOFLAGS_IO_PATH_MASK           (0xC000)
+#define MPI25_SCSIIO_IOFLAGS_NORMAL_PATH            (0x0000)
+#define MPI25_SCSIIO_IOFLAGS_FAST_PATH              (0x4000)
+
+#define MPI25_SCSIIO_IOFLAGS_LARGE_CDB                  (0x1000)
+#define MPI25_SCSIIO_IOFLAGS_BIDIRECTIONAL              (0x0800)
+#define MPI25_SCSIIO_IOFLAGS_CMD_DETERMINES_DATA_DIR    (0x0200)
+#define MPI25_SCSIIO_IOFLAGS_CDBLENGTH_MASK             (0x01FF)
+
+/* MPI v2.5 defines for the EEDPFlags bits */
+/* use MPI2_SCSIIO_EEDPFLAGS_ defines for the other EEDPFlags bits */
+#define MPI25_SCSIIO_EEDPFLAGS_ESCAPE_MODE_MASK             (0x00C0)
+#define MPI25_SCSIIO_EEDPFLAGS_COMPATIBLE_MODE              (0x0000)
+#define MPI25_SCSIIO_EEDPFLAGS_DO_NOT_DISABLE_MODE          (0x0040)
+#define MPI25_SCSIIO_EEDPFLAGS_APPTAG_DISABLE_MODE          (0x0080)
+#define MPI25_SCSIIO_EEDPFLAGS_APPTAG_REFTAG_DISABLE_MODE   (0x00C0)
+
+#define MPI25_SCSIIO_EEDPFLAGS_HOST_GUARD_METHOD_MASK       (0x0030)
+#define MPI25_SCSIIO_EEDPFLAGS_T10_CRC_HOST_GUARD           (0x0000)
+#define MPI25_SCSIIO_EEDPFLAGS_IP_CHKSUM_HOST_GUARD         (0x0010)
+
+/* use MPI2_LUN_ defines from mpi2.h for the LUN field */
+
+/* use MPI2_SCSIIO_CONTROL_ defines for the Control field */
+
+
+/* NOTE: The SCSI IO Reply is the same for MPI 2.0 and MPI 2.5, so
+ *       MPI2_SCSI_IO_REPLY is used for both.
+ */
+
 /* SCSI IO Error Reply Message */
 typedef struct _MPI2_SCSI_IO_REPLY
 {
@@ -299,6 +413,11 @@
 #define MPI2_SCSI_STATE_AUTOSENSE_FAILED        (0x02)
 #define MPI2_SCSI_STATE_AUTOSENSE_VALID         (0x01)
 
+/* masks and shifts for the ResponseInfo field */
+
+#define MPI2_SCSI_RI_MASK_REASONCODE            (0x000000FF)
+#define MPI2_SCSI_RI_SHIFT_REASONCODE           (0)
+
 #define MPI2_SCSI_TASKTAG_UNKNOWN               (0xFFFF)
 
 
@@ -371,6 +490,7 @@
     U16                     IOCStatus;                      /* 0x0E */
     U32                     IOCLogInfo;                     /* 0x10 */
     U32                     TerminationCount;               /* 0x14 */
+    U32                     ResponseInfo;                   /* 0x18 */
 } MPI2_SCSI_TASK_MANAGE_REPLY,
   MPI2_POINTER PTR_MPI2_SCSI_TASK_MANAGE_REPLY,
   Mpi2SCSITaskManagementReply_t, MPI2_POINTER pMpi2SCSIManagementReply_t;
@@ -383,8 +503,20 @@
 #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_TM_OVERLAPPED_TAG         (0x0A)
 #define MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC          (0x80)
 
+/* masks and shifts for the ResponseInfo field */
+
+#define MPI2_SCSITASKMGMT_RI_MASK_REASONCODE            (0x000000FF)
+#define MPI2_SCSITASKMGMT_RI_SHIFT_REASONCODE           (0)
+#define MPI2_SCSITASKMGMT_RI_MASK_ARI2                  (0x0000FF00)
+#define MPI2_SCSITASKMGMT_RI_SHIFT_ARI2                 (8)
+#define MPI2_SCSITASKMGMT_RI_MASK_ARI1                  (0x00FF0000)
+#define MPI2_SCSITASKMGMT_RI_SHIFT_ARI1                 (16)
+#define MPI2_SCSITASKMGMT_RI_MASK_ARI0                  (0xFF000000)
+#define MPI2_SCSITASKMGMT_RI_SHIFT_ARI0                 (24)
+
 
 /****************************************************************************
 *  SCSI Enclosure Processor messages
--- old/usr/src/uts/common/sys/scsi/adapters/mpt_sas3/mpi/mpi2_ioc.h	2014-06-12 17:42:18.247680808 +0100
+++ new/usr/src/uts/common/sys/scsi/adapters/mpt_sas3/mpi/mpi2_ioc.h	2014-06-12 17:42:18.253870494 +0100
@@ -20,8 +20,7 @@
  */
 
 /*
- * Copyright (c) 2000 to 2009, LSI Corporation.
- * All rights reserved.
+ *  Copyright (c) 2000-2012 LSI Corporation.
  *
  * Redistribution and use in source and binary forms of all code within
  * this file that is exclusively owned by LSI, with or without
@@ -51,7 +50,12 @@
  *          Title:  MPI IOC, Port, Event, FW Download, and FW Upload messages
  *  Creation Date:  October 11, 2006
  *
- *  mpi2_ioc.h Version:  02.00.12
+ *  mpi2_ioc.h Version:  02.00.xx
+ *
+ *  NOTE: Names (typedefs, defines, etc.) beginning with an MPI25 or Mpi25
+ *        prefix are for use only on MPI v2.5 products, and must not be used
+ *        with MPI v2.0 products. Unless otherwise noted, names beginning with
+ *        MPI2 or Mpi2 are for use with both MPI v2.0 and MPI v2.5 products.
  *
  *  Version History
  *  ---------------
@@ -132,6 +136,23 @@
  *  07-30-09  02.00.12  Added GPIO Interrupt event define and structure.
  *                      Added MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER define.
  *                      Added new product id family for 2208.
+ *  10-28-09  02.00.13  Added HostMSIxVectors field to MPI2_IOC_INIT_REQUEST.
+ *                      Added MaxMSIxVectors field to MPI2_IOC_FACTS_REPLY.
+ *                      Added MinDevHandle field to MPI2_IOC_FACTS_REPLY.
+ *                      Added MPI2_IOCFACTS_CAPABILITY_HOST_BASED_DISCOVERY.
+ *                      Added MPI2_EVENT_HOST_BASED_DISCOVERY_PHY define.
+ *                      Added MPI2_EVENT_SAS_TOPO_ES_NO_EXPANDER define.
+ *                      Added Host Based Discovery Phy Event data.
+ *                      Added defines for ProductID Product field
+ *                      (MPI2_FW_HEADER_PID_).
+ *                      Modified values for SAS ProductID Family
+ *                      (MPI2_FW_HEADER_PID_FAMILY_).
+ *  02-10-10  02.00.14  Added SAS Quiesce Event structure and defines.
+ *                      Added PowerManagementControl Request structures and
+ *                      defines.
+ *  05-12-10  02.00.15  Marked Task Set Full Event as obsolete.
+ *                      Added MPI2_EVENT_SAS_TOPO_LR_UNSUPPORTED_PHY define.
+ *  11-10-10  02.00.16  Added MPI2_FW_DOWNLOAD_ITYPE_MIN_PRODUCT_SPECIFIC.
  *  --------------------------------------------------------------------------
  */
 
@@ -164,8 +185,10 @@
     U16                     MsgVersion;                     /* 0x0C */
     U16                     HeaderVersion;                  /* 0x0E */
     U32                     Reserved5;                      /* 0x10 */
-    U32                     Reserved6;                      /* 0x14 */
-    U16                     Reserved7;                      /* 0x18 */
+    U16                     Reserved6;                      /* 0x14 */
+    U8                      Reserved7;                      /* 0x16 */
+    U8                      HostMSIxVectors;                /* 0x17 */
+    U16                     Reserved8;                      /* 0x18 */
     U16                     SystemRequestFrameSize;         /* 0x1A */
     U16                     ReplyDescriptorPostQueueDepth;  /* 0x1C */
     U16                     ReplyFreeQueueDepth;            /* 0x1E */
@@ -260,7 +283,7 @@
     U8                      MaxChainDepth;                  /* 0x14 */
     U8                      WhoInit;                        /* 0x15 */
     U8                      NumberOfPorts;                  /* 0x16 */
-    U8                      Reserved2;                      /* 0x17 */
+    U8                      MaxMSIxVectors;                 /* 0x17 */
     U16                     RequestCredit;                  /* 0x18 */
     U16                     ProductID;                      /* 0x1A */
     U32                     IOCCapabilities;                /* 0x1C */
@@ -278,7 +301,8 @@
     U8                      MaxVolumes;                     /* 0x37 */
     U16                     MaxDevHandle;                   /* 0x38 */
     U16                     MaxPersistentEntries;           /* 0x3A */
-    U32                     Reserved4;                      /* 0x3C */
+    U16                     MinDevHandle;                   /* 0x3C */
+    U16                     Reserved4;                      /* 0x3E */
 } MPI2_IOC_FACTS_REPLY, MPI2_POINTER PTR_MPI2_IOC_FACTS_REPLY,
   Mpi2IOCFactsReply_t, MPI2_POINTER pMpi2IOCFactsReply_t;
 
@@ -314,6 +338,8 @@
 /* ProductID field uses MPI2_FW_HEADER_PID_ */
 
 /* IOCCapabilities */
+#define MPI25_IOCFACTS_CAPABILITY_FAST_PATH_CAPABLE     (0x00020000)
+#define MPI2_IOCFACTS_CAPABILITY_HOST_BASED_DISCOVERY   (0x00010000)
 #define MPI2_IOCFACTS_CAPABILITY_MSI_X_INDEX            (0x00008000)
 #define MPI2_IOCFACTS_CAPABILITY_RAID_ACCELERATOR       (0x00004000)
 #define MPI2_IOCFACTS_CAPABILITY_EVENT_REPLAY           (0x00002000)
@@ -483,7 +509,7 @@
 #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_TASK_SET_FULL                    (0x000E) /* obsolete */
 #define MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE         (0x000F)
 #define MPI2_EVENT_IR_OPERATION_STATUS              (0x0014)
 #define MPI2_EVENT_SAS_DISCOVERY                    (0x0016)
@@ -498,6 +524,8 @@
 #define MPI2_EVENT_LOG_ENTRY_ADDED                  (0x0021)
 #define MPI2_EVENT_SAS_PHY_COUNTER                  (0x0022)
 #define MPI2_EVENT_GPIO_INTERRUPT                   (0x0023)
+#define MPI2_EVENT_HOST_BASED_DISCOVERY_PHY         (0x0024)
+#define MPI2_EVENT_SAS_QUIESCE                      (0x0025)
 
 
 /* Log Entry Added Event data */
@@ -543,6 +571,7 @@
   MPI2_POINTER pMpi2EventDataHardResetReceived_t;
 
 /* Task Set Full Event data */
+/*   this event is obsolete */
 
 typedef struct _MPI2_EVENT_DATA_TASK_SET_FULL
 {
@@ -839,6 +868,7 @@
   MPI2_POINTER pMpi2EventDataSasTopologyChangeList_t;
 
 /* values for the ExpStatus field */
+#define MPI2_EVENT_SAS_TOPO_ES_NO_EXPANDER                  (0x00)
 #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)
@@ -856,9 +886,11 @@
 #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_UNSUPPORTED_PHY              (0x06)
 #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)
+#define MPI25_EVENT_SAS_TOPO_LR_RATE_12_0                   (0x0B)
 
 /* values for the PhyStatus field */
 #define MPI2_EVENT_SAS_TOPO_PHYSTATUS_VACANT                (0x80)
@@ -923,6 +955,63 @@
 /* use MPI2_SASPHY3_TFLAGS_ values from mpi2_cnfg.h for the ThresholdFlags field */
 
 
+/* SAS Quiesce Event data */
+
+typedef struct _MPI2_EVENT_DATA_SAS_QUIESCE
+{
+    U8                      ReasonCode;                 /* 0x00 */
+    U8                      Reserved1;                  /* 0x01 */
+    U16                     Reserved2;                  /* 0x02 */
+    U32                     Reserved3;                  /* 0x04 */
+} MPI2_EVENT_DATA_SAS_QUIESCE,
+  MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_QUIESCE,
+  Mpi2EventDataSasQuiesce_t, MPI2_POINTER pMpi2EventDataSasQuiesce_t;
+
+/* SAS Quiesce Event data ReasonCode values */
+#define MPI2_EVENT_SAS_QUIESCE_RC_STARTED                   (0x01)
+#define MPI2_EVENT_SAS_QUIESCE_RC_COMPLETED                 (0x02)
+
+
+/* Host Based Discovery Phy Event data */
+
+typedef struct _MPI2_EVENT_HBD_PHY_SAS
+{
+    U8          Flags;                      /* 0x00 */
+    U8          NegotiatedLinkRate;         /* 0x01 */
+    U8          PhyNum;                     /* 0x02 */
+    U8          PhysicalPort;               /* 0x03 */
+    U32         Reserved1;                  /* 0x04 */
+    U8          InitialFrame[28];           /* 0x08 */
+} MPI2_EVENT_HBD_PHY_SAS, MPI2_POINTER PTR_MPI2_EVENT_HBD_PHY_SAS,
+  Mpi2EventHbdPhySas_t, MPI2_POINTER pMpi2EventHbdPhySas_t;
+
+/* values for the Flags field */
+#define MPI2_EVENT_HBD_SAS_FLAGS_FRAME_VALID        (0x02)
+#define MPI2_EVENT_HBD_SAS_FLAGS_SATA_FRAME         (0x01)
+
+/* use MPI2_SAS_NEG_LINK_RATE_ defines from mpi2_cnfg.h for the NegotiatedLinkRate field */
+
+typedef union _MPI2_EVENT_HBD_DESCRIPTOR
+{
+    MPI2_EVENT_HBD_PHY_SAS      Sas;
+} MPI2_EVENT_HBD_DESCRIPTOR, MPI2_POINTER PTR_MPI2_EVENT_HBD_DESCRIPTOR,
+  Mpi2EventHbdDescriptor_t, MPI2_POINTER pMpi2EventHbdDescriptor_t;
+
+typedef struct _MPI2_EVENT_DATA_HBD_PHY
+{
+    U8                          DescriptorType;     /* 0x00 */
+    U8                          Reserved1;          /* 0x01 */
+    U16                         Reserved2;          /* 0x02 */
+    U32                         Reserved3;          /* 0x04 */
+    MPI2_EVENT_HBD_DESCRIPTOR   Descriptor;         /* 0x08 */
+} MPI2_EVENT_DATA_HBD_PHY, MPI2_POINTER PTR_MPI2_EVENT_DATA_HBD_PHY,
+  Mpi2EventDataHbdPhy_t, MPI2_POINTER pMpi2EventDataMpi2EventDataHbdPhy_t;
+
+/* values for the DescriptorType field */
+#define MPI2_EVENT_HBD_DT_SAS               (0x01)
+
+
+
 /****************************************************************************
 *  EventAck message
 ****************************************************************************/
@@ -969,7 +1058,7 @@
 *  FWDownload message
 ****************************************************************************/
 
-/* FWDownload Request message */
+/* MPI v2.0 FWDownload Request message */
 typedef struct _MPI2_FW_DOWNLOAD_REQUEST
 {
     U8                      ImageType;                  /* 0x00 */
@@ -996,9 +1085,11 @@
 #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_COMPLETE             (0x0A)
 #define MPI2_FW_DOWNLOAD_ITYPE_COMMON_BOOT_BLOCK    (0x0B)
+#define MPI2_FW_DOWNLOAD_ITYPE_MIN_PRODUCT_SPECIFIC (0xF0)
 
-/* FWDownload TransactionContext Element */
+/* MPI v2.0 FWDownload TransactionContext Element */
 typedef struct _MPI2_FW_DOWNLOAD_TCSGE
 {
     U8                      Reserved1;                  /* 0x00 */
@@ -1011,6 +1102,30 @@
 } MPI2_FW_DOWNLOAD_TCSGE, MPI2_POINTER PTR_MPI2_FW_DOWNLOAD_TCSGE,
   Mpi2FWDownloadTCSGE_t, MPI2_POINTER pMpi2FWDownloadTCSGE_t;
 
+
+/* MPI v2.5 FWDownload Request message */
+typedef struct _MPI25_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 */
+    U32                     Reserved6;                  /* 0x14 */
+    U32                     ImageOffset;                /* 0x18 */
+    U32                     ImageSize;                  /* 0x1C */
+    MPI25_SGE_IO_UNION      SGL;                        /* 0x20 */
+} MPI25_FW_DOWNLOAD_REQUEST, MPI2_POINTER PTR_MPI25_FW_DOWNLOAD_REQUEST,
+  Mpi25FWDownloadRequest, MPI2_POINTER pMpi25FWDownloadRequest;
+
+
 /* FWDownload Reply message */
 typedef struct _MPI2_FW_DOWNLOAD_REPLY
 {
@@ -1035,7 +1150,7 @@
 *  FWUpload message
 ****************************************************************************/
 
-/* FWUpload Request message */
+/* MPI v2.0 FWUpload Request message */
 typedef struct _MPI2_FW_UPLOAD_REQUEST
 {
     U8                      ImageType;                  /* 0x00 */
@@ -1065,6 +1180,7 @@
 #define MPI2_FW_UPLOAD_ITYPE_COMPLETE           (0x0A)
 #define MPI2_FW_UPLOAD_ITYPE_COMMON_BOOT_BLOCK  (0x0B)
 
+/* MPI v2.0 FWUpload TransactionContext Element */
 typedef struct _MPI2_FW_UPLOAD_TCSGE
 {
     U8                      Reserved1;                  /* 0x00 */
@@ -1077,6 +1193,30 @@
 } MPI2_FW_UPLOAD_TCSGE, MPI2_POINTER PTR_MPI2_FW_UPLOAD_TCSGE,
   Mpi2FWUploadTCSGE_t, MPI2_POINTER pMpi2FWUploadTCSGE_t;
 
+
+/* MPI v2.5 FWUpload Request message */
+typedef struct _MPI25_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 */
+    U32                     Reserved7;                  /* 0x14 */
+    U32                     ImageOffset;                /* 0x18 */
+    U32                     ImageSize;                  /* 0x1C */
+    MPI25_SGE_IO_UNION      SGL;                        /* 0x20 */
+} MPI25_FW_UPLOAD_REQUEST, MPI2_POINTER PTR_MPI25_FW_UPLOAD_REQUEST,
+  Mpi25FWUploadRequest_t, MPI2_POINTER pMpi25FWUploadRequest_t;
+
+
 /* FWUpload Reply message */
 typedef struct _MPI2_FW_UPLOAD_REPLY
 {
@@ -1171,13 +1311,16 @@
 #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_PROD_MASK                    (0x0F00)
+#define MPI2_FW_HEADER_PID_PROD_A                       (0x0000)
+#define MPI2_FW_HEADER_PID_PROD_TARGET_INITIATOR_SCSI   (0x0200)
+#define MPI2_FW_HEADER_PID_PROD_IR_SCSI                 (0x0700)
 
 #define MPI2_FW_HEADER_PID_FAMILY_MASK          (0x00FF)
-/* SAS */
-#define MPI2_FW_HEADER_PID_FAMILY_2108_SAS      (0x0010)
-#define MPI2_FW_HEADER_PID_FAMILY_2208_SAS      (0x0011)
+/* SAS ProductID Family bits */
+#define MPI2_FW_HEADER_PID_FAMILY_2108_SAS      (0x0013)
+#define MPI2_FW_HEADER_PID_FAMILY_2208_SAS      (0x0014)
+#define MPI25_FW_HEADER_PID_FAMILY_3108_SAS     (0x0021)
 
 /* use MPI2_IOCFACTS_PROTOCOL_ defines for ProtocolFlags field */
 
@@ -1393,5 +1536,101 @@
 #define MPI2_INIT_IMAGE_RESETVECTOR_OFFSET      (0x14)
 
 
+/****************************************************************************
+*  PowerManagementControl message
+****************************************************************************/
+
+/* PowerManagementControl Request message */
+typedef struct _MPI2_PWR_MGMT_CONTROL_REQUEST
+{
+    U8                      Feature;                    /* 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 */
+    U8                      Parameter1;                 /* 0x0C */
+    U8                      Parameter2;                 /* 0x0D */
+    U8                      Parameter3;                 /* 0x0E */
+    U8                      Parameter4;                 /* 0x0F */
+    U32                     Reserved5;                  /* 0x10 */
+    U32                     Reserved6;                  /* 0x14 */
+} MPI2_PWR_MGMT_CONTROL_REQUEST, MPI2_POINTER PTR_MPI2_PWR_MGMT_CONTROL_REQUEST,
+  Mpi2PwrMgmtControlRequest_t, MPI2_POINTER pMpi2PwrMgmtControlRequest_t;
+
+/* defines for the Feature field */
+#define MPI2_PM_CONTROL_FEATURE_DA_PHY_POWER_COND       (0x01)
+#define MPI2_PM_CONTROL_FEATURE_PORT_WIDTH_MODULATION   (0x02)
+#define MPI2_PM_CONTROL_FEATURE_PCIE_LINK               (0x03)
+#define MPI2_PM_CONTROL_FEATURE_IOC_SPEED               (0x04)
+#define MPI2_PM_CONTROL_FEATURE_MIN_PRODUCT_SPECIFIC    (0x80)
+#define MPI2_PM_CONTROL_FEATURE_MAX_PRODUCT_SPECIFIC    (0xFF)
+
+/* parameter usage for the MPI2_PM_CONTROL_FEATURE_DA_PHY_POWER_COND Feature */
+/* Parameter1 contains a PHY number */
+/* Parameter2 indicates power condition action using these defines */
+#define MPI2_PM_CONTROL_PARAM2_PARTIAL                  (0x01)
+#define MPI2_PM_CONTROL_PARAM2_SLUMBER                  (0x02)
+#define MPI2_PM_CONTROL_PARAM2_EXIT_PWR_MGMT            (0x03)
+/* Parameter3 and Parameter4 are reserved */
+
+/* parameter usage for the MPI2_PM_CONTROL_FEATURE_PORT_WIDTH_MODULATION Feature */
+/* Parameter1 contains SAS port width modulation group number */
+/* Parameter2 indicates IOC action using these defines */
+#define MPI2_PM_CONTROL_PARAM2_REQUEST_OWNERSHIP        (0x01)
+#define MPI2_PM_CONTROL_PARAM2_CHANGE_MODULATION        (0x02)
+#define MPI2_PM_CONTROL_PARAM2_RELINQUISH_OWNERSHIP     (0x03)
+/* Parameter3 indicates desired modulation level using these defines */
+#define MPI2_PM_CONTROL_PARAM3_25_PERCENT               (0x00)
+#define MPI2_PM_CONTROL_PARAM3_50_PERCENT               (0x01)
+#define MPI2_PM_CONTROL_PARAM3_75_PERCENT               (0x02)
+#define MPI2_PM_CONTROL_PARAM3_100_PERCENT              (0x03)
+/* Parameter4 is reserved */
+
+/* parameter usage for the MPI2_PM_CONTROL_FEATURE_PCIE_LINK Feature */
+/* Parameter1 indicates desired PCIe link speed using these defines */
+#define MPI2_PM_CONTROL_PARAM1_PCIE_2_5_GBPS            (0x00)
+#define MPI2_PM_CONTROL_PARAM1_PCIE_5_0_GBPS            (0x01)
+#define MPI2_PM_CONTROL_PARAM1_PCIE_8_0_GBPS            (0x02)
+/* Parameter2 indicates desired PCIe link width using these defines */
+#define MPI2_PM_CONTROL_PARAM2_WIDTH_X1                 (0x01)
+#define MPI2_PM_CONTROL_PARAM2_WIDTH_X2                 (0x02)
+#define MPI2_PM_CONTROL_PARAM2_WIDTH_X4                 (0x04)
+#define MPI2_PM_CONTROL_PARAM2_WIDTH_X8                 (0x08)
+/* Parameter3 and Parameter4 are reserved */
+
+/* parameter usage for the MPI2_PM_CONTROL_FEATURE_IOC_SPEED Feature */
+/* Parameter1 indicates desired IOC hardware clock speed using these defines */
+#define MPI2_PM_CONTROL_PARAM1_FULL_IOC_SPEED           (0x01)
+#define MPI2_PM_CONTROL_PARAM1_HALF_IOC_SPEED           (0x02)
+#define MPI2_PM_CONTROL_PARAM1_QUARTER_IOC_SPEED        (0x04)
+#define MPI2_PM_CONTROL_PARAM1_EIGHTH_IOC_SPEED         (0x08)
+/* Parameter2, Parameter3, and Parameter4 are reserved */
+
+
+/* PowerManagementControl Reply message */
+typedef struct _MPI2_PWR_MGMT_CONTROL_REPLY
+{
+    U8                      Feature;                    /* 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_PWR_MGMT_CONTROL_REPLY, MPI2_POINTER PTR_MPI2_PWR_MGMT_CONTROL_REPLY,
+  Mpi2PwrMgmtControlReply_t, MPI2_POINTER pMpi2PwrMgmtControlReply_t;
+
+
 #endif
 
--- old/usr/src/uts/common/sys/scsi/adapters/mpt_sas3/mpi/mpi2_raid.h	2014-06-12 17:42:18.450082065 +0100
+++ new/usr/src/uts/common/sys/scsi/adapters/mpt_sas3/mpi/mpi2_raid.h	2014-06-12 17:42:18.456227421 +0100
@@ -20,8 +20,7 @@
  */
 
 /*
- * Copyright (c) 2000 to 2009, LSI Corporation.
- * All rights reserved.
+ *  Copyright (c) 2000-2012 LSI Corporation.
  *
  * Redistribution and use in source and binary forms of all code within
  * this file that is exclusively owned by LSI, with or without
@@ -51,7 +50,7 @@
  *          Title:  MPI Integrated RAID messages and structures
  *  Creation Date:  April 26, 2007
  *
- *    mpi2_raid.h Version:  02.00.04
+ *    mpi2_raid.h Version:  02.00.05
  *
  *  Version History
  *  ---------------
@@ -67,6 +66,7 @@
  *                      can be sized by the build environment.
  *  07-30-09  02.00.04  Added proper define for the Use Default Settings bit of
  *                      VolumeCreationFlags and marked the old one as obsolete.
+ *  05-12-10  02.00.05  Added MPI2_RAID_VOL_FLAGS_OP_MDC define.
  *  --------------------------------------------------------------------------
  */
 
@@ -220,7 +220,7 @@
 #define MPI2_RAID_ACTION_SYSTEM_SHUTDOWN_INITIATED  (0x20)
 #define MPI2_RAID_ACTION_START_RAID_FUNCTION        (0x21)
 #define MPI2_RAID_ACTION_STOP_RAID_FUNCTION         (0x22)
-
+#define MPI2_RAID_ACTION_FAST_PATH_PERMITTED        (0x24)
 
 /* RAID Volume Creation Structure */
 
@@ -305,6 +305,7 @@
 #define MPI2_RAID_VOL_FLAGS_OP_ONLINE_CAP_EXPANSION (0x00000001)
 #define MPI2_RAID_VOL_FLAGS_OP_CONSISTENCY_CHECK    (0x00000002)
 #define MPI2_RAID_VOL_FLAGS_OP_RESYNC               (0x00000003)
+#define MPI2_RAID_VOL_FLAGS_OP_MDC                  (0x00000004)
 
 
 /* RAID Action Reply ActionData union */
--- old/usr/src/uts/common/sys/scsi/adapters/mpt_sas3/mpi/mpi2_sas.h	2014-06-12 17:42:18.612545678 +0100
+++ new/usr/src/uts/common/sys/scsi/adapters/mpt_sas3/mpi/mpi2_sas.h	2014-06-12 17:42:18.618601573 +0100
@@ -20,8 +20,7 @@
  */
 
 /*
- * Copyright (c) 2000 to 2009, LSI Corporation.
- * All rights reserved.
+ *  Copyright (c) 2000-2012 LSI Corporation.
  *
  * Redistribution and use in source and binary forms of all code within
  * this file that is exclusively owned by LSI, with or without
@@ -51,7 +50,12 @@
  *          Title:  MPI Serial Attached SCSI structures and definitions
  *  Creation Date:  February 9, 2007
  *
- *  mpi2.h Version:  02.00.02
+ *  mpi2_sas.h Version:  02.00.xx
+ *
+ *  NOTE: Names (typedefs, defines, etc.) beginning with an MPI25 or Mpi25
+ *        prefix are for use only on MPI v2.5 products, and must not be used
+ *        with MPI v2.0 products. Unless otherwise noted, names beginning with
+ *        MPI2 or Mpi2 are for use with both MPI v2.0 and MPI v2.5 products.
  *
  *  Version History
  *  ---------------
@@ -63,6 +67,10 @@
  *                      Control Request.
  *  10-02-08  02.00.02  Added Set IOC Parameter Operation to SAS IO Unit Control
  *                      Request.
+ *  10-28-09  02.00.03  Changed the type of SGL in MPI2_SATA_PASSTHROUGH_REQUEST
+ *                      to MPI2_SGE_IO_UNION since it supports chained SGLs.
+ *  05-12-10  02.00.04  Modified some comments.
+ *  08-11-10  02.00.05  Added NCQ operations to SAS IO Unit Control.
  *  --------------------------------------------------------------------------
  */
 
@@ -137,7 +145,7 @@
     U8                      ChainOffset;        /* 0x02 */
     U8                      Function;           /* 0x03 */
     U16                     RequestDataLength;  /* 0x04 */
-    U8                      SGLFlags;           /* 0x06 */
+    U8                      SGLFlags;           /* 0x06 */ /* MPI v2.0 only. Reserved on MPI v2.5. */
     U8                      MsgFlags;           /* 0x07 */
     U8                      VP_ID;              /* 0x08 */
     U8                      VF_ID;              /* 0x09 */
@@ -146,14 +154,14 @@
     U64                     SASAddress;         /* 0x10 */
     U32                     Reserved3;          /* 0x18 */
     U32                     Reserved4;          /* 0x1C */
-    MPI2_SIMPLE_SGE_UNION   SGL;                /* 0x20 */
+    MPI2_SIMPLE_SGE_UNION   SGL;                /* 0x20 */ /* MPI v2.5: IEEE Simple 64 elements only */
 } 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 */
+/* MPI v2.0: use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */
 
 
 /* SMP Passthrough Reply Message */
@@ -195,7 +203,7 @@
     U8                      ChainOffset;        /* 0x02 */
     U8                      Function;           /* 0x03 */
     U16                     PassthroughFlags;   /* 0x04 */
-    U8                      SGLFlags;           /* 0x06 */
+    U8                      SGLFlags;           /* 0x06 */ /* MPI v2.0 only. Reserved on MPI v2.5. */
     U8                      MsgFlags;           /* 0x07 */
     U8                      VP_ID;              /* 0x08 */
     U8                      VF_ID;              /* 0x09 */
@@ -205,7 +213,7 @@
     U32                     Reserved4;          /* 0x14 */
     U32                     DataLength;         /* 0x18 */
     U8                      CommandFIS[20];     /* 0x1C */
-    MPI2_SIMPLE_SGE_UNION   SGL;                /* 0x20 */
+    MPI2_SGE_IO_UNION       SGL;                /* 0x30 */ /* MPI v2.5: IEEE 64 elements only */
 } MPI2_SATA_PASSTHROUGH_REQUEST, MPI2_POINTER PTR_MPI2_SATA_PASSTHROUGH_REQUEST,
   Mpi2SataPassthroughRequest_t, MPI2_POINTER pMpi2SataPassthroughRequest_t;
 
@@ -217,7 +225,7 @@
 #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 */
+/* MPI v2.0: use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */
 
 
 /* SATA Passthrough Reply Message */
@@ -288,6 +296,12 @@
 #define MPI2_SAS_OP_REMOVE_DEVICE               (0x0D)
 #define MPI2_SAS_OP_LOOKUP_MAPPING              (0x0E)
 #define MPI2_SAS_OP_SET_IOC_PARAMETER           (0x0F)
+#define MPI25_SAS_OP_ENABLE_FP_DEVICE           (0x10)
+#define MPI25_SAS_OP_DISABLE_FP_DEVICE          (0x11)
+#define MPI25_SAS_OP_ENABLE_FP_ALL              (0x12)
+#define MPI25_SAS_OP_DISABLE_FP_ALL             (0x13)
+#define MPI2_SAS_OP_DEV_ENABLE_NCQ              (0x14)
+#define MPI2_SAS_OP_DEV_DISABLE_NCQ             (0x15)
 #define MPI2_SAS_OP_PRODUCT_SPECIFIC_MIN        (0x80)
 
 /* values for the PrimFlags field */
--- old/usr/src/uts/common/sys/scsi/adapters/mpt_sas3/mpi/mpi2_tool.h	2014-06-12 17:42:18.777440192 +0100
+++ new/usr/src/uts/common/sys/scsi/adapters/mpt_sas3/mpi/mpi2_tool.h	2014-06-12 17:42:18.782927068 +0100
@@ -20,8 +20,7 @@
  */
 
 /*
- * Copyright (c) 2000 to 2009, LSI Corporation.
- * All rights reserved.
+ *  Copyright (c) 2000-2012 LSI Corporation.
  *
  * Redistribution and use in source and binary forms of all code within
  * this file that is exclusively owned by LSI, with or without
@@ -51,7 +50,7 @@
  *          Title:  MPI diagnostic tool structures and definitions
  *  Creation Date:  March 26, 2007
  *
- *    mpi2_tool.h Version:  02.00.04
+ *    mpi2_tool.h Version:  02.00.06
  *
  *  Version History
  *  ---------------
@@ -67,6 +66,9 @@
  *                      and reply messages.
  *                      Added MPI2_DIAG_BUF_TYPE_EXTENDED.
  *                      Incremented MPI2_DIAG_BUF_TYPE_COUNT.
+ *  05-12-10  02.00.05  Added Diagnostic Data Upload tool.
+ *  08-11-10  02.00.06  Added defines that were missing for Diagnostic Buffer
+ *                      Post Request.
  *  --------------------------------------------------------------------------
  */
 
@@ -82,6 +84,7 @@
 /* defines for the Tools */
 #define MPI2_TOOLBOX_CLEAN_TOOL                     (0x00)
 #define MPI2_TOOLBOX_MEMORY_MOVE_TOOL               (0x01)
+#define MPI2_TOOLBOX_DIAG_DATA_UPLOAD_TOOL          (0x02)
 #define MPI2_TOOLBOX_ISTWI_READ_WRITE_TOOL          (0x03)
 #define MPI2_TOOLBOX_BEACON_TOOL                    (0x05)
 #define MPI2_TOOLBOX_DIAGNOSTIC_CLI_TOOL            (0x06)
@@ -165,6 +168,46 @@
 
 
 /****************************************************************************
+*  Toolbox Diagnostic Data Upload request
+****************************************************************************/
+
+typedef struct _MPI2_TOOLBOX_DIAG_DATA_UPLOAD_REQUEST
+{
+    U8                      Tool;                       /* 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 */
+    U8                      SGLFlags;                   /* 0x0C */
+    U8                      Reserved5;                  /* 0x0D */
+    U16                     Reserved6;                  /* 0x0E */
+    U32                     Flags;                      /* 0x10 */
+    U32                     DataLength;                 /* 0x14 */
+    MPI2_SGE_SIMPLE_UNION   SGL;                        /* 0x18 */
+} MPI2_TOOLBOX_DIAG_DATA_UPLOAD_REQUEST,
+  MPI2_POINTER PTR_MPI2_TOOLBOX_DIAG_DATA_UPLOAD_REQUEST,
+  Mpi2ToolboxDiagDataUploadRequest_t,
+  MPI2_POINTER pMpi2ToolboxDiagDataUploadRequest_t;
+
+/* use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */
+
+
+typedef struct _MPI2_DIAG_DATA_UPLOAD_HEADER
+{
+    U32                     DiagDataLength;             /* 00h */
+    U8                      FormatCode;                 /* 04h */
+    U8                      Reserved1;                  /* 05h */
+    U16                     Reserved2;                  /* 06h */
+} MPI2_DIAG_DATA_UPLOAD_HEADER, MPI2_POINTER PTR_MPI2_DIAG_DATA_UPLOAD_HEADER,
+  Mpi2DiagDataUploadHeader_t, MPI2_POINTER pMpi2DiagDataUploadHeader_t;
+
+
+/****************************************************************************
 *  Toolbox ISTWI Read Write Tool
 ****************************************************************************/
 
@@ -295,7 +338,7 @@
   Mpi2ToolboxDiagnosticCliRequest_t,
   MPI2_POINTER pMpi2ToolboxDiagnosticCliRequest_t;
 
-/* values for SGLFlags field are in the SGL section of mpi2.h */
+/* use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */
 
 
 /* Toolbox Diagnostic CLI Tool reply message */
@@ -363,6 +406,9 @@
 /* count of the number of buffer types */
 #define MPI2_DIAG_BUF_TYPE_COUNT                    (0x03)
 
+/* values for the Flags field */
+#define MPI2_DIAG_BUF_FLAG_RELEASE_ON_FULL          (0x00000002) /* for MPI v2.0 products only */
+#define MPI2_DIAG_BUF_FLAG_IMMEDIATE_RELEASE        (0x00000001)
 
 /****************************************************************************
 *  Diagnostic Buffer Post reply
--- old/usr/src/uts/common/sys/scsi/adapters/mpt_sas3/mpi/mpi2_type.h	2014-06-12 17:42:18.948139594 +0100
+++ new/usr/src/uts/common/sys/scsi/adapters/mpt_sas3/mpi/mpi2_type.h	2014-06-12 17:42:18.953883825 +0100
@@ -20,8 +20,7 @@
  */
 
 /*
- * Copyright (c) 2000 to 2009, LSI Corporation.
- * All rights reserved.
+ *  Copyright (c) 2000-2012 LSI Corporation.
  *
  * Redistribution and use in source and binary forms of all code within
  * this file that is exclusively owned by LSI, with or without
--- old/usr/src/uts/common/sys/scsi/adapters/mpt_sas3/mptsas3_hash.h	2014-06-12 17:42:19.119534789 +0100
+++ new/usr/src/uts/common/sys/scsi/adapters/mpt_sas3/mptsas3_hash.h	2014-06-12 17:42:19.125847666 +0100
@@ -11,10 +11,11 @@
 
 /*
  * Copyright 2014 Joyent, Inc.  All rights reserved.
+ * Copyright (c) 2014, Tegile Systems Inc. All rights reserved.
  */
 
-#ifndef	_SYS_SCSI_ADAPTERS_MPTHASH_H
-#define	_SYS_SCSI_ADAPTERS_MPTHASH_H
+#ifndef	_SYS_SCSI_ADAPTERS_MPTSAS3_HASH_H
+#define	_SYS_SCSI_ADAPTERS_MPTSAS3_HASH_H
 
 #include <sys/types.h>
 #include <sys/list.h>
@@ -58,4 +59,4 @@
 extern void *refhash_next(refhash_t *, void *);
 extern boolean_t refhash_obj_valid(refhash_t *hp, const void *);
 
-#endif	/* _SYS_SCSI_ADAPTERS_MPTHASH_H */
+#endif	/* _SYS_SCSI_ADAPTERS_MPTSAS3_HASH_H */
--- old/usr/src/uts/common/sys/scsi/adapters/mpt_sas3/mptsas3_ioctl.h	2014-06-12 17:42:19.276266889 +0100
+++ new/usr/src/uts/common/sys/scsi/adapters/mpt_sas3/mptsas3_ioctl.h	2014-06-12 17:42:19.282358071 +0100
@@ -25,6 +25,7 @@
  */
 /*
  * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2014, Tegile Systems Inc. All rights reserved.
  */
 
 /*
@@ -54,8 +55,8 @@
  * DAMAGE.
  */
 
-#ifndef _MPTSAS_IOCTL_H
-#define	_MPTSAS_IOCTL_H
+#ifndef _MPTSAS3_IOCTL_H
+#define	_MPTSAS3_IOCTL_H
 
 #ifdef  __cplusplus
 extern "C" {
@@ -102,14 +103,14 @@
  *  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
+ *  Adapter Type - Value = 6 = SCSI Protocol through SAS-3 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
+#define	MPTIOCTL_ADAPTER_TYPE_SAS3	6
 typedef struct mptsas_adapter_data
 {
 	uint32_t		StructureLength;
@@ -357,4 +358,4 @@
 }
 #endif
 
-#endif	/* _MPTSAS_IOCTL_H */
+#endif	/* _MPTSAS3_IOCTL_H */
--- old/usr/src/uts/common/sys/scsi/adapters/mpt_sas3/mptsas3_smhba.h	2014-06-12 17:42:19.440735760 +0100
+++ new/usr/src/uts/common/sys/scsi/adapters/mpt_sas3/mptsas3_smhba.h	2014-06-12 17:42:19.446676834 +0100
@@ -22,21 +22,22 @@
 /*
  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
  * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 2014, Tegile Systems Inc. All rights reserved.
  */
 
 /*
  * SM-HBA interfaces/definitions for MPT SAS driver.
  */
 
-#ifndef _MPTSAS_SMHBA_H
-#define	_MPTSAS_SMHBA_H
+#ifndef _MPTSAS3_SMHBA_H
+#define	_MPTSAS3_SMHBA_H
 #ifdef	__cplusplus
 extern "C" {
 #endif
 
 /* Leverage definition of data_type_t in nvpair.h */
 #include <sys/nvpair.h>
-#include <sys/scsi/adapters/mpt_sas/mptsas_var.h>
+#include <sys/scsi/adapters/mpt_sas3/mptsas3_var.h>
 
 #define	MPTSAS_NUM_PHYS		"num-phys"
 #define	MPTSAS_NUM_PHYS_HBA	"num-phys-hba"
@@ -79,4 +80,4 @@
 #ifdef	__cplusplus
 }
 #endif
-#endif	/* _MPTSAS_SMHBA_H */
+#endif	/* _MPTSAS3_SMHBA_H */
--- old/usr/src/uts/common/sys/scsi/adapters/mpt_sas3/mptsas3_var.h	2014-06-12 17:42:19.601364295 +0100
+++ new/usr/src/uts/common/sys/scsi/adapters/mpt_sas3/mptsas3_var.h	2014-06-12 17:42:19.607556677 +0100
@@ -21,8 +21,9 @@
 
 /*
  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
  * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2014, Tegile Systems Inc. All rights reserved.
  */
 
 /*
@@ -52,17 +53,18 @@
  * DAMAGE.
  */
 
-#ifndef _SYS_SCSI_ADAPTERS_MPTVAR_H
-#define	_SYS_SCSI_ADAPTERS_MPTVAR_H
+#ifndef _SYS_SCSI_ADAPTERS_MPTSAS3_VAR_H
+#define	_SYS_SCSI_ADAPTERS_MPTSAS3_VAR_H
 
 #include <sys/byteorder.h>
+#include <sys/queue.h>
 #include <sys/isa_defs.h>
 #include <sys/sunmdi.h>
 #include <sys/mdi_impldefs.h>
-#include <sys/scsi/adapters/mpt_sas/mptsas_hash.h>
-#include <sys/scsi/adapters/mpt_sas/mptsas_ioctl.h>
-#include <sys/scsi/adapters/mpt_sas/mpi/mpi2_tool.h>
-#include <sys/scsi/adapters/mpt_sas/mpi/mpi2_cnfg.h>
+#include <sys/scsi/adapters/mpt_sas3/mptsas3_hash.h>
+#include <sys/scsi/adapters/mpt_sas3/mptsas3_ioctl.h>
+#include <sys/scsi/adapters/mpt_sas3/mpi/mpi2_tool.h>
+#include <sys/scsi/adapters/mpt_sas3/mpi/mpi2_cnfg.h>
 
 #ifdef	__cplusplus
 extern "C" {
@@ -141,14 +143,17 @@
 	(((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
+ * Calculating 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.
+ * size. IEEE 64-bit dma element used for SAS3 controllers is 4 double-words
+ * (16 bytes).
  */
 #define	MPTSAS_MAX_FRAME_SGES64(mpt) \
 	((mpt->m_req_frame_size - \
-	(sizeof (MPI2_SCSI_IO_REQUEST)) + sizeof (MPI2_SGE_IO_UNION)) / 12)
+	sizeof (MPI2_SCSI_IO_REQUEST) + sizeof (MPI2_SGE_IO_UNION)) / \
+	(mpt->m_MPI25 ? sizeof (MPI2_IEEE_SGE_SIMPLE64) : \
+	sizeof (MPI2_SGE_SIMPLE64)))
 
 /*
  * Scatter-gather list structure defined by HBA hardware
@@ -200,30 +205,36 @@
 	mptsas_phymask_t mta_phymask;
 } mptsas_target_addr_t;
 
+TAILQ_HEAD(mptsas_active_cmdq, mptsas_cmd);
+typedef struct mptsas_active_cmdq mptsas_active_cmdq_t;
+
 typedef	struct mptsas_target {
+		kmutex_t		m_t_mutex;
 		mptsas_target_addr_t	m_addr;
 		refhash_link_t		m_link;
-		uint8_t			m_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;
+		uint8_t			m_phynum;
+		mptsas_active_cmdq_t	m_active_cmdq;
 		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;
+		uint16_t		m_io_flags;
 		uint16_t		m_enclosure;
 		uint16_t		m_slot_num;
-		uint32_t		m_tgt_unconfigured;
+		uint16_t		m_qfull_retry_interval;
+		uint8_t			m_qfull_retries;
+		uint8_t			m_tgt_unconfigured;
 		uint8_t			m_led_status;
-
+		uint8_t			m_dr_flag;
 } mptsas_target_t;
 
+/*
+ * If you change this structure, be sure that mptsas_smp_target_copy()
+ * does the right thing.
+ */
 typedef struct mptsas_smp {
 	mptsas_target_addr_t	m_addr;
 	refhash_link_t		m_link;
@@ -237,7 +248,7 @@
 	ddi_dma_handle_t m_dma_hdl;
 	ddi_acc_handle_t m_acc_hdl;
 	caddr_t m_frames_addr;
-	uint32_t m_phys_addr;
+	uint64_t m_phys_addr;
 } mptsas_cache_frames_t;
 
 typedef struct	mptsas_cmd {
@@ -251,24 +262,22 @@
 	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;
+	caddr_t			cmd_arq_buf;
 
 	int			cmd_pkt_flags;
 
-	/* timer for command in active slot */
-	int			cmd_active_timeout;
+	/* pending expiration time for command in active slot */
+	hrtime_t		cmd_active_expiration;
+	TAILQ_ENTRY(mptsas_cmd)	cmd_active_link;
 
 	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;
+	uint16_t		cmd_extrqslen;	/* len of extended rqsense */
+	uint16_t		cmd_extrqschunks; /* len in map chunks */
+	uint16_t		cmd_extrqsidx;	/* Index into map */
 	uint_t			cmd_scblen;
 	uint32_t		cmd_dmacount;
 	uint64_t		cmd_dma_addr;
@@ -281,6 +290,7 @@
 	uint64_t		cmd_pkt_private[PKT_PRIV_LEN];
 	uint32_t		cmd_slot;
 	uint32_t		ioc_cmd_slot;
+	uint8_t			cmd_rpqidx;
 
 	mptsas_cache_frames_t	*cmd_extra_frames;
 
@@ -316,7 +326,6 @@
 #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 */
@@ -325,6 +334,15 @@
 #define	CFLAG_CONFIG		0x40000000 /* cmd is for config header/page */
 #define	CFLAG_FW_DIAG		0x80000000 /* cmd is for FW diag buffers */
 
+#ifdef MPTSAS_DEBUG
+/* Could be used with cmn_err %b */
+#define	CFLAGS_DEBUG_BITS "\\020\\0CmdDisc\\1Watch\\2Finished\\3ChkSeg" \
+	"\\4Cmpltd\\5Prepd\\6InTran\\7RestPtrs\\8ARQIP\\9TM\\10CArq" \
+	"\\11DMAVal\\12DMASnd\\13CIopb\\14CDBExt\\15SCBExt\\16Free" \
+	"\\17PrivExt\\18DMAPrtl\\19QFull\\20Tout\\21PMMRcv\\22Retry" \
+	"\\23CIoc\\25PThru\\26XArq\\27CAck\\28TXq\\29FWCmd\\30Config\\31FWDiag"
+#endif
+
 #define	MPTSAS_SCSI_REPORTLUNS_ADDRESS_SIZE			8
 #define	MPTSAS_SCSI_REPORTLUNS_ADDRESS_MASK			0xC0
 #define	MPTSAS_SCSI_REPORTLUNS_ADDRESS_PERIPHERAL			0x00
@@ -362,7 +380,9 @@
 	uint32_t request_size;
 	uint32_t data_size;
 	uint32_t dataout_size;
-	uint32_t direction;
+	uint8_t direction;
+	uint8_t simple;
+	uint16_t sgl_offset;
 	ddi_dma_cookie_t data_cookie;
 	ddi_dma_cookie_t dataout_cookie;
 } mptsas_pt_request_t;
@@ -548,7 +568,7 @@
  */
 #define	MPTSAS_DR_EVENT_RECONFIG_TARGET	0x01
 #define	MPTSAS_DR_EVENT_OFFLINE_TARGET	0x02
-#define	MPTSAS_TOPO_FLAG_REMOVE_HANDLE	0x04
+#define	MPTSAS_DR_EVENT_REMOVE_HANDLE	0x04
 
 /*
  * SMP target hotplug events
@@ -642,25 +662,58 @@
 } mptsas_phy_info_t;
 
 
-typedef struct mptsas_doneq_thread_arg {
+typedef struct mptsas_thread_arg {
 	void		*mpt;
-	uint64_t	t;
-} mptsas_doneq_thread_arg_t;
+	uint32_t	t;
+} mptsas_thread_arg_t;
+
+typedef struct mptsas_done_list {
+	mptsas_cmd_t		*dl_q;
+	mptsas_cmd_t		**dl_tail;
+	uint32_t		dl_len;
+} mptsas_done_list_t;
 
 #define	MPTSAS_DONEQ_THREAD_ACTIVE	0x1
 typedef struct mptsas_doneq_thread_list {
-	mptsas_cmd_t		*doneq;
-	mptsas_cmd_t		**donetail;
+	mptsas_done_list_t	dlist;
 	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_thread_arg_t	arg;
 } mptsas_doneq_thread_list_t;
 
+typedef struct mptsas_reply_pqueue {
+	kmutex_t		rpq_mutex;
+	uint8_t			rpq_num;
+	caddr_t			rpq_queue; /* Pointer to this queue base */
+	uint32_t		rpq_index; /* Index of next replyq entry */
+	uint32_t		rpq_ncmds; /* Number of outstanding commands */
+	mptsas_done_list_t	rpq_dlist;
+	uint32_t		rpq_intr_count;
+	uint32_t		rpq_intr_unclaimed;
+	uint32_t		rpq_intr_mutexbusy;
+} mptsas_reply_pqueue_t;
+
+
+typedef struct mptsas_tx_waitqueue {
+	kmutex_t	txwq_mutex;
+	kcondvar_t	txwq_cv;
+	kcondvar_t	txwq_drain_cv;
+	kthread_t	*txwq_threadp;
+	mptsas_cmd_t	*txwq_cmdq;	/* TX cmd queue for active request */
+	mptsas_cmd_t	**txwq_qtail;	/* tx_wait queue tail ptr */
+	uint32_t	txwq_len;	/* TX queue length */
+	mptsas_thread_arg_t	arg;
+	uint8_t		txwq_active;	/* Thread active flag */
+	uint8_t		txwq_draining;	/* TX queue draining flag */
+	uint8_t		txwq_wdrain;
+} mptsas_tx_waitqueue_t;
+
+#define	NUM_TX_WAITQ	2
+
 typedef struct mptsas {
 	int		m_instance;
 
@@ -687,32 +740,33 @@
 
 	m_raidconfig_t	m_raidconfig[MPTSAS_MAX_RAIDCONFIGS];
 	uint8_t		m_num_raid_configs;
+	uint8_t		m_pref_tx_waitq;
 
 	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 */
+	mptsas_tx_waitqueue_t	m_tx_waitq[NUM_TX_WAITQ];
+	uint16_t		m_txwq_thread_threshold;
+	uint16_t		m_txwq_thread_n;
+	uint8_t			m_txwq_enabled;
+	uint8_t			m_txwq_allow_q_jumping;
+	mptsas_done_list_t	m_dlist; /* List of completed commands */
 
 	/*
 	 * variables for helper threads (fan-out interrupts)
 	 */
 	mptsas_doneq_thread_list_t	*m_doneq_thread_id;
-	uint32_t		m_doneq_thread_n;
+	uint16_t		m_doneq_thread_n;
+	uint16_t		m_doneq_next_thread;
 	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;
+	kcondvar_t		m_qthread_cv;
+	kmutex_t		m_qthread_mutex;
 
-	int		m_ncmds;	/* number of outstanding commands */
+	uint32_t		m_ncmds; /* number of outstanding commands */
+	uint32_t		m_ncstarted; /* ncmds started per interval */
+	uint32_t		m_lncstarted; /* record of last value */
 	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 */
 
@@ -731,12 +785,15 @@
 
 	ddi_dma_handle_t m_dma_req_frame_hdl;
 	ddi_acc_handle_t m_acc_req_frame_hdl;
+	ddi_dma_handle_t m_dma_req_sense_hdl;
+	ddi_acc_handle_t m_acc_req_sense_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;
+	uint8_t		m_dma_flags;
 
 	/*
 	 * list of reset notification requests
@@ -766,8 +823,6 @@
 	 */
 	uint_t		m_options;
 
-	int		m_in_callback;
-
 	int		m_power_level;	/* current power level */
 
 	int		m_busy;		/* power management busy state */
@@ -786,20 +841,26 @@
 	 */
 	caddr_t		m_req_frame;
 	uint64_t	m_req_frame_dma_addr;
+	caddr_t		m_req_sense;
+	caddr_t		m_extreq_sense;
+	uint64_t	m_req_sense_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;
+	struct map	*m_erqsense_map;
+	mptsas_reply_pqueue_t	*m_rep_post_queues;
 
 	m_replyh_arg_t *m_replyh_args;
 
 	uint16_t	m_max_requests;
 	uint16_t	m_req_frame_size;
+	uint16_t	m_req_sense_size;
 
 	/*
-	 * Max frames per request reprted in IOC Facts
+	 * Max frames per request reported in IOC Facts
 	 */
 	uint8_t		m_max_chain_depth;
 	/*
@@ -808,16 +869,26 @@
 	 * m_max_chain_depth.
 	 */
 	uint8_t		m_max_request_frames;
+	uint8_t		m_max_msix_vectors;
+	uint8_t		m_reply_frame_size;
+	uint8_t		m_post_reply_qcount;
 
 	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;
 	uint32_t	m_ioc_capabilities;
 
 	/*
+	 * Housekeeping.
+	 */
+	uint64_t	m_interrupt_count;
+	uint32_t	m_unclaimed_pm_interrupt_count;
+	uint32_t	m_unclaimed_polled_interrupt_count;
+	uint32_t	m_unclaimed_no_interrupt_count;
+	uint32_t	m_unclaimed_nocmd_interrupt_count;
+
+	/*
 	 * indicates if the firmware was upload by the driver
 	 * at boot time
 	 */
@@ -891,6 +962,9 @@
 	mptsas_fw_diagnostic_buffer_t
 		m_fw_diag_buffer_list[MPI2_DIAG_BUF_TYPE_COUNT];
 
+	/* GEN3 support */
+	uint8_t			m_MPI25;
+
 	/*
 	 * Event Replay flag (MUR support)
 	 */
@@ -935,9 +1009,7 @@
 _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))
 
 /*
@@ -985,6 +1057,8 @@
  * m_options flags
  */
 #define	MPTSAS_OPT_PM		0x01	/* Power Management */
+#define	MPTSAS_OPT_MSI		0x02	/* PCI MSI Interrupts */
+#define	MPTSAS_OPT_MSI_X	0x04	/* PCI MSI-X Interrupts */
 
 /*
  * m_softstate flags
@@ -995,6 +1069,15 @@
 #define	MPTSAS_DID_MSG_UNIT_RESET	0x10
 
 /*
+ * m_dma_flags (allocated).
+ */
+#define	MPTSAS_REQ_FRAME	0x01
+#define	MPTSAS_REQ_SENSE	0x02
+#define	MPTSAS_REPLY_FRAME	0x04
+#define	MPTSAS_FREE_QUEUE	0x08
+#define	MPTSAS_POST_QUEUE	0x10
+
+/*
  * regspec defines.
  */
 #define	CONFIG_SPACE	0	/* regset[0] - configuration space */
@@ -1007,6 +1090,7 @@
  */
 #define	FALSE		0
 #define	TRUE		1
+#define	BLOCKED		2
 #define	UNDEFINED	-1
 #define	FAILED		-2
 
@@ -1105,11 +1189,12 @@
 			(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	MPTSAS_START_CMD(mpt, req_desc) \
+	ddi_put64(mpt->m_datap, \
+	    (uint64_t *)(void *)&mpt->m_reg->RequestDescriptorPostLow, \
+	    req_desc);						       \
+	atomic_inc_32(&mpt->m_ncstarted)
+
 
 #define	INTPENDING(mpt) \
 	(MPTSAS_GET_ISTAT(mpt) & MPI2_HIS_REPLY_DESCRIPTOR_INTERRUPT)
@@ -1128,8 +1213,8 @@
 	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_REPLY(rpqp, index)  \
+	&((uint64_t *)(void *)rpqp->rpq_queue)[index]
 
 #define	MPTSAS_GET_NEXT_FRAME(mpt, SMID) \
 	(mpt->m_req_frame + (mpt->m_req_frame_size * SMID))
@@ -1165,7 +1250,7 @@
  */
 #define	DEFAULT_SCSI_OPTIONS	SCSI_OPTIONS_DR
 #define	DEFAULT_TAG_AGE_LIMIT	2
-#define	DEFAULT_WD_TICK		10
+#define	DEFAULT_WD_TICK		1
 
 /*
  * invalid hostid.
@@ -1252,14 +1337,6 @@
 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,
@@ -1291,11 +1368,11 @@
 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);
+    uint64_t SGEaddress);
 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);
+    uint32_t SGEflagslength, uint64_t SGEaddress);
 
 int mptsas_request_from_pool(mptsas_t *mpt, mptsas_cmd_t **cmd,
     struct scsi_pkt **pkt);
@@ -1311,7 +1388,6 @@
     int mode);
 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);
@@ -1331,7 +1407,7 @@
 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, uint16_t *pdevhandle,
-    uint16_t *slot_num, uint16_t *enclosure);
+    uint16_t *slot_num, uint16_t *enclosure, uint16_t *io_flags);
 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,
@@ -1370,10 +1446,13 @@
 #if defined(MPTSAS_DEBUG)
 
 void mptsas_printf(char *fmt, ...);
+void mptsas_debug_log(char *fmt, ...);
 
 #define	MPTSAS_DBGPR(m, args)	\
 	if (mptsas_debug_flags & (m)) \
-		mptsas_printf args
+		mptsas_printf args;   \
+	if (~mptsas_dbglog_imask & (m)) \
+		mptsas_debug_log args
 #else	/* ! defined(MPTSAS_DEBUG) */
 #define	MPTSAS_DBGPR(m, args)
 #endif	/* defined(MPTSAS_DEBUG) */
@@ -1385,7 +1464,7 @@
 
 #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	NDBG6(args)	MPTSAS_DBGPR(0x40, args)	/* interrupt setup */
 #define	NDBG7(args)	MPTSAS_DBGPR(0x80, args)	/* queue handling */
 
 #define	NDBG8(args)	MPTSAS_DBGPR(0x0100, args)	/* arq */
@@ -1396,11 +1475,11 @@
 #define	NDBG12(args)	MPTSAS_DBGPR(0x1000, args)	/* enumeration */
 #define	NDBG13(args)	MPTSAS_DBGPR(0x2000, args)	/* configuration page */
 #define	NDBG14(args)	MPTSAS_DBGPR(0x4000, args)	/* LED control */
-#define	NDBG15(args)	MPTSAS_DBGPR(0x8000, args)
+#define	NDBG15(args)	MPTSAS_DBGPR(0x8000, args)	/* Passthrough */
 
-#define	NDBG16(args)	MPTSAS_DBGPR(0x010000, args)
+#define	NDBG16(args)	MPTSAS_DBGPR(0x010000, args)	/* SAS Broadcasts */
 #define	NDBG17(args)	MPTSAS_DBGPR(0x020000, args)	/* scatter/gather */
-#define	NDBG18(args)	MPTSAS_DBGPR(0x040000, args)
+#define	NDBG18(args)	MPTSAS_DBGPR(0x040000, args)	/* Interrupts */
 #define	NDBG19(args)	MPTSAS_DBGPR(0x080000, args)	/* handshaking */
 
 #define	NDBG20(args)	MPTSAS_DBGPR(0x100000, args)	/* events */
@@ -1437,4 +1516,4 @@
 }
 #endif
 
-#endif	/* _SYS_SCSI_ADAPTERS_MPTVAR_H */
+#endif	/* _SYS_SCSI_ADAPTERS_MPTSAS3_VAR_H */
--- old/usr/src/uts/intel/mpt_sas3/Makefile	2014-06-12 17:42:19.822446621 +0100
+++ new/usr/src/uts/intel/mpt_sas3/Makefile	2014-06-12 17:42:19.827821574 +0100
@@ -21,7 +21,8 @@
 # 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.
+#	This makefile drives the production of the mpt_sas3 driver
+#	kernel module.
 #
 #	intel architecture dependent
 #
@@ -34,12 +35,12 @@
 #
 #	Define the module and object file sets.
 #
-MODULE		= mpt_sas
-OBJECTS		= $(MPTSAS_OBJS:%=$(OBJS_DIR)/%)
-LINTS		= $(MPTSAS_OBJS:%.o=$(LINTS_DIR)/%.ln)
+MODULE		= mpt_sas3
+OBJECTS		= $(MPTSAS3_OBJS:%=$(OBJS_DIR)/%)
+LINTS		= $(MPTSAS3_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)
+CONF_SRCDIR	= $(UTSBASE)/common/io/scsi/adapters/mpt_sas3/
+WARLOCK_OUT     = $(MPTSAS3_OBJS:%.o=%.ll)
 WARLOCK_OK      = $(MODULE).ok
 WLCMD_DIR       = $(UTSBASE)/common/io/warlock
 
@@ -116,7 +117,7 @@
 	-l $(UTSBASE)/intel/warlock/ddi_dki_impl.ll
 	$(TOUCH) $@
 
-%.ll: $(UTSBASE)/common/io/scsi/adapters/mpt_sas/%.c
+%.ll: $(UTSBASE)/common/io/scsi/adapters/mpt_sas3/%.c
 	$(WLCC) $(CPPFLAGS) -DDEBUG -o $@ $<
 
 warlock_ddi.files:
--- old/usr/src/uts/sparc/mpt_sas3/Makefile	2014-06-12 17:42:20.006562787 +0100
+++ new/usr/src/uts/sparc/mpt_sas3/Makefile	2014-06-12 17:42:20.013742637 +0100
@@ -21,7 +21,8 @@
 # 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.
+#	This makefile drives the production of the mpt_sas3 driver
+#	kernel module.
 #
 #	Sparc architecture dependent
 #
@@ -34,12 +35,12 @@
 #
 #	Define the module and object file sets.
 #
-MODULE		= mpt_sas
-OBJECTS		= $(MPTSAS_OBJS:%=$(OBJS_DIR)/%)
-LINTS		= $(MPTSAS_OBJS:%.o=$(LINTS_DIR)/%.ln)
+MODULE		= mpt_sas3
+OBJECTS		= $(MPTSAS3_OBJS:%=$(OBJS_DIR)/%)
+LINTS		= $(MPTSAS3_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)
+CONF_SRCDIR	= $(UTSBASE)/common/io/scsi/adapters/mpt_sas3
+WARLOCK_OUT     = $(MPTSAS3_OBJS:%.o=%.ll)
 WARLOCK_OK      = $(MODULE).ok
 WLCMD_DIR       = $(UTSBASE)/common/io/warlock
 
@@ -114,14 +115,14 @@
 warlock: $(WARLOCK_OK)
 
 $(WARLOCK_OK): $(WARLOCK_OUT) warlock_ddi.files scsi.files \
-	$(WLCMD_DIR)/mptsas.wlcmd
-	$(WARLOCK) -c $(WLCMD_DIR)/mptsas.wlcmd $(WARLOCK_OUT) \
+	$(WLCMD_DIR)/mptsas3.wlcmd
+	$(WARLOCK) -c $(WLCMD_DIR)/mptsas3.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
+%.ll: $(UTSBASE)/common/io/scsi/adapters/mpt_sas3/%.c
 	$(WLCC) $(CPPFLAGS) -DDEBUG -o $@ $<
 
 warlock_ddi.files:
