--- old/usr/src/cmd/mdb/common/modules/mpt_sas/mpt_sas.c	Wed May  7 17:09:47 2014
+++ new/usr/src/cmd/mdb/common/modules/mpt_sas/mpt_sas.c	Wed May  7 17:09:47 2014
@@ -23,10 +23,15 @@
  * Use is subject to license terms.
  */
 
+/*
+ * Copyright 2014 Joyent, 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)
@@ -41,9 +46,9 @@
 #pragma pack()
 
 #include <sys/scsi/adapters/mpt_sas/mptsas_var.h>
+#include <sys/scsi/adapters/mpt_sas/mptsas_hash.h>
 
 struct {
-
 	int	value;
 	char	*text;
 } devinfo_array[] = {
@@ -61,19 +66,6 @@
 	{ MPI2_SAS_DEVICE_INFO_SATA_HOST,	"SATA host" }
 };
 
-static int
-atoi(const char *p)
-{
-	int n;
-	int c = *p++;
-
-	for (n = 0; c >= '0' && c <= '9'; c = *p++) {
-		n *= 10; /* two steps to avoid unnecessary overflow */
-		n += '0' - c; /* accum neg to avoid surprises at MAX */
-	}
-	return (-n);
-}
-
 int
 construct_path(uintptr_t addr, char *result)
 {
@@ -116,8 +108,8 @@
 		return (DCMD_ERR);
 	}
 	mdb_readstr(string, sizeof (string), (uintptr_t)pi.pi_addr);
-	mdi_target = atoi(string);
-	mdi_lun = atoi(strchr(string, ',')+1);
+	mdi_target = (int)mdb_strtoull(string);
+	mdi_lun = (int)mdb_strtoull(strchr(string, ',') + 1);
 	if (target != mdi_target)
 		return (0);
 
@@ -213,66 +205,103 @@
 
 
 void
-display_ports(struct mptsas m)
+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 (m.m_phy_info[i].attached_devhdl) {
+		if (mp->m_phy_info[i].attached_devhdl) {
 			mdb_printf("phy %x --> port %x, phymask %x,"
-			"attached_devhdl %x\n", i, m.m_phy_info[i].port_num,
-			    m.m_phy_info[i].phy_mask,
-			    m.m_phy_info[i].attached_devhdl);
+			"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 *
-hash_traverse(mptsas_hash_table_t *hashtab, int pos, int alloc_size)
+krefhash_first(uintptr_t khp)
 {
-	mptsas_hash_node_t *this = NULL;
-	mptsas_hash_node_t h;
-	void *ret = NULL;
+	refhash_t mh;
+	uintptr_t klp;
+	uintptr_t kop;
+	void *rp;
 
-	if (pos == MPTSAS_HASH_FIRST) {
-		hashtab->line = 0;
-		hashtab->cur = NULL;
-		this = hashtab->head[0];
-	} else {
-		if (hashtab->cur == NULL) {
-			return (NULL);
-		} else {
-			mdb_vread(&h, sizeof (h), (uintptr_t)hashtab->cur);
-			this = h.next;
-		}
-	}
+	mdb_vread(&mh, sizeof (mh), khp);
+	klp = klist_head(&mh.rh_objs, khp + offsetof(refhash_t, rh_objs));
+	if (klp == 0)
+		return (NULL);
 
-	while (this == NULL) {
-		hashtab->line++;
-		if (hashtab->line >= MPTSAS_HASH_ARRAY_SIZE) {
-			/* the traverse reaches the end */
-			hashtab->cur = NULL;
-			return (NULL);
-		} else {
-			this = hashtab->head[hashtab->line];
-		}
+	kop = klp - mh.rh_link_off;
+	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)
+{
+	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;
 	}
-	hashtab->cur = this;
 
-	if (mdb_vread(&h, sizeof (h), (uintptr_t)this) == -1) {
-		mdb_warn("couldn't read hashtab");
+	if (klp == 0) {
+		mdb_free(prev, mh.rh_obj_size);
 		return (NULL);
 	}
-	ret = mdb_alloc(alloc_size, UM_SLEEP);
-	if (mdb_vread(ret, alloc_size, (uintptr_t)h.data) == -1) {
-		mdb_warn("couldn't read hashdata");
-		return (NULL);
-	}
-	return (ret);
+
+	kop = klp - mh.rh_link_off;
+	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_slots *s)
+display_targets(struct mptsas *mp)
 {
 	mptsas_target_t *ptgt;
 	mptsas_smp_t *psmp;
@@ -279,32 +308,29 @@
 
 	mdb_printf("\n");
 	mdb_printf("The SCSI target information\n");
-	ptgt = (mptsas_target_t *)hash_traverse(&s->m_tgttbl,
-	    MPTSAS_HASH_FIRST, sizeof (mptsas_target_t));
-	while (ptgt != NULL) {
+	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_sas_wwn,
-		    ptgt->m_phymask, ptgt->m_deviceinfo);
-		mdb_printf("throttle %x, dr_flag %x, m_t_ncmds %x\n",
-		    ptgt->m_t_throttle, ptgt->m_dr_flag, ptgt->m_t_ncmds);
-
-		mdb_free(ptgt, sizeof (mptsas_target_t));
-		ptgt = (mptsas_target_t *)hash_traverse(
-		    &s->m_tgttbl, MPTSAS_HASH_NEXT, sizeof (mptsas_target_t));
+		    "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");
-	psmp = (mptsas_smp_t *)hash_traverse(&s->m_smptbl,
-	    MPTSAS_HASH_FIRST, sizeof (mptsas_smp_t));
-	while (psmp != NULL) {
+	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_sasaddr, psmp->m_phymask);
-
-		mdb_free(psmp, sizeof (mptsas_smp_t));
-		psmp = (mptsas_smp_t *)hash_traverse(
-		    &s->m_smptbl, MPTSAS_HASH_NEXT, sizeof (mptsas_smp_t));
+		    psmp->m_devhdl, psmp->m_addr.mta_wwn,
+		    psmp->m_addr.mta_phymask);
 	}
 	mdb_printf("\n");
 #if 0
@@ -313,11 +339,12 @@
 	mdb_printf("-------------------------------"
 	    "--------------------------------\n");
 	for (i = 0; i < MPTSAS_MAX_TARGETS; i++) {
-		if (s->m_target[i].m_sas_wwn || s->m_target[i].m_deviceinfo) {
+		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_sas_wwn)
+			if (s->m_target[i].m_addr.mta_wwn)
 				mdb_printf("%"PRIx64" ",
-				    s->m_target[i].m_sas_wwn);
+				    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) {
 				case QFULL_THROTTLE:
@@ -427,7 +454,7 @@
 	int	ncmds = 0;
 	ulong_t	saved_indent;
 
-	nslots = s->m_n_slots;
+	nslots = s->m_n_normal;
 
 	slots = mdb_alloc(sizeof (mptsas_cmd_t) * nslots, UM_SLEEP);
 
@@ -480,7 +507,7 @@
 	saved_indent = mdb_dec_indent(0);
 	mdb_dec_indent(saved_indent);
 
-	for (i = 0; i < s->m_n_slots; i++)
+	for (i = 0; i < s->m_n_normal; i++)
 		if (s->m_slot[i]) {
 			if (!header_output) {
 				mdb_printf("\n");
@@ -602,12 +629,12 @@
 }
 
 void
-display_deviceinfo(struct mptsas m)
+display_deviceinfo(struct mptsas *mp)
 {
 	char	device_path[PATH_MAX];
 
 	*device_path = 0;
-	if (construct_path((uintptr_t)m.m_dip, device_path) != DCMD_OK) {
+	if (construct_path((uintptr_t)mp->m_dip, device_path) != DCMD_OK) {
 		strcpy(device_path, "couldn't determine device path");
 	}
 
@@ -692,7 +719,7 @@
 mptsas_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
 {
 	struct mptsas		m;
-	struct	mptsas_slots	*s;
+	struct mptsas_slots	*s;
 
 	int			nslots;
 	int			slot_size = 0;
@@ -743,7 +770,7 @@
 		return (DCMD_ERR);
 	}
 
-	nslots = s->m_n_slots;
+	nslots = s->m_n_normal;
 
 	mdb_free(s, sizeof (mptsas_slots_t));
 
@@ -796,13 +823,13 @@
 	mdb_inc_indent(17);
 
 	if (target_info)
-		display_targets(s);
+		display_targets(&m);
 
 	if (port_info)
-		display_ports(m);
+		display_ports(&m);
 
 	if (device_info)
-		display_deviceinfo(m);
+		display_deviceinfo(&m);
 
 	if (slot_info)
 		display_slotinfo();
@@ -813,9 +840,7 @@
 
 	return (rv);
 }
-/*
- * Only -t is implemented now, will add more later when the driver is stable
- */
+
 void
 mptsas_help()
 {
--- old/usr/src/lib/fm/topo/libtopo/common/topo_hc.h	Wed May  7 17:09:47 2014
+++ new/usr/src/lib/fm/topo/libtopo/common/topo_hc.h	Wed May  7 17:09:47 2014
@@ -21,6 +21,7 @@
 
 /*
  * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
  */
 
 #ifndef _TOPO_HC_H
@@ -115,6 +116,10 @@
 
 #define	TOPO_PGROUP_BINDING	"binding"
 #define	TOPO_BINDING_OCCUPANT	"occupant-path"
+#define	TOPO_BINDING_DRIVER	"driver"
+#define	TOPO_BINDING_DEVCTL	"devctl"
+#define	TOPO_BINDING_ENCLOSURE	"enclosure"
+#define	TOPO_BINDING_SLOT	"slot"
 
 #define	TOPO_PGROUP_STORAGE	"storage"
 #define	TOPO_STORAGE_INITIATOR_PORT	"initiator-port"
--- old/usr/src/lib/fm/topo/libtopo/common/topo_xml.c	Wed May  7 17:09:47 2014
+++ new/usr/src/lib/fm/topo/libtopo/common/topo_xml.c	Wed May  7 17:09:47 2014
@@ -21,6 +21,7 @@
 
 /*
  * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
  */
 
 #include <libxml/parser.h>
@@ -1376,16 +1377,10 @@
 
 		if ((fprov = xmlGetProp(cn, (xmlChar *)Provider)) == NULL)
 			goto fenumdone;
-
-		if (xmlStrcmp(fprov, (xmlChar *)"fac_prov_ipmi") != 0) {
-			topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
-			    "Invalid provider specified: %s\n", fprov);
-			goto fenumdone;
-		}
-
 		/*
-		 * Invoke enum entry point in fac provider which will cause the
-		 * facility enumeration node method to be registered.
+		 * Invoke enum entry point in facility provider which will
+		 * cause the facility enumeration node method to be
+		 * registered.
 		 */
 		if (fac_enum_run(mp, ptn, (const char *)fprov) != 0) {
 			topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
@@ -1440,12 +1435,6 @@
 		    xmlStrcmp(ftype, (xmlChar *)Indicator) != 0)
 			goto facdone;
 
-		if (xmlStrcmp(provider, (xmlChar *)"fac_prov_ipmi") != 0) {
-			topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "fac_process: "
-			    "Invalid provider attr value: %s\n", provider);
-			goto facdone;
-		}
-
 		if ((ntn = topo_node_facbind(mp, ptn, (char *)fname,
 		    (char *)ftype)) == NULL)
 			goto facdone;
@@ -1463,8 +1452,9 @@
 			}
 		}
 		/*
-		 * Invoke enum entry point in fac_prov_ipmi module, which will
-		 * cause the provider methods to be registered on this node
+		 * Invoke enum entry point in the facility provider module,
+		 * which will cause the provider methods to be registered on
+		 * this node
 		 */
 		if (fac_enum_run(mp, ntn, (const char *)provider) != 0) {
 			topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, "fac_process: "
--- old/usr/src/lib/fm/topo/modules/common/Makefile	Wed May  7 17:09:48 2014
+++ new/usr/src/lib/fm/topo/modules/common/Makefile	Wed May  7 17:09:48 2014
@@ -23,11 +23,11 @@
 # Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
 
 SUBDIRS =		\
 	disk		\
 	fac_prov_ipmi	\
+	fac_prov_mptsas	\
 	ipmi		\
 	ses		\
 	xfp
--- old/usr/src/lib/fm/topo/modules/common/disk/Makefile	Wed May  7 17:09:48 2014
+++ new/usr/src/lib/fm/topo/modules/common/disk/Makefile	Wed May  7 17:09:48 2014
@@ -22,14 +22,15 @@
 # Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
 
 MODULE = disk
 CLASS = common
 
-MODULESRCS = disk.c disk_common.c
+MODULESRCS = disk.c disk_common.c disk_mptsas.c
 
 include ../../Makefile.plugin
 
+CPPFLAGS += -I$(SRC)/uts/common
+
 LDLIBS += -ldevinfo -ldevid -lcfgadm -ldiskstatus
 
--- old/usr/src/lib/fm/topo/modules/common/disk/disk.c	Wed May  7 17:09:48 2014
+++ new/usr/src/lib/fm/topo/modules/common/disk/disk.c	Wed May  7 17:09:48 2014
@@ -21,6 +21,9 @@
 /*
  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  */
+/*
+ * Copyright (c) 2013, Joyent, Inc.  All rights reserved.
+ */
 
 #include <strings.h>
 #include <devid.h>
@@ -33,6 +36,7 @@
 #include <fm/libdiskstatus.h>
 #include <sys/fm/protocol.h>
 #include "disk.h"
+#include "disk_drivers.h"
 
 static int disk_enum(topo_mod_t *, tnode_t *, const char *,
 	topo_instance_t, topo_instance_t, void *, void *);
@@ -43,6 +47,31 @@
 static const topo_modinfo_t disk_info =
 	{DISK, FM_FMRI_SCHEME_HC, DISK_VERSION, &disk_ops};
 
+static int
+disk_declare_driver(topo_mod_t *mod, tnode_t *baynode, topo_list_t *dlistp,
+    char *driver)
+{
+	int err;
+
+	if (strcmp("mpt_sas", driver) == 0) {
+		char *sas_address = NULL;
+		tnode_t *child = NULL;
+
+		if ((err = disk_mptsas_find_disk(mod, baynode,
+		    &sas_address)) != 0)
+			return (err);
+
+		err = disk_declare_addr(mod, baynode, dlistp,
+		    sas_address, &child);
+		topo_mod_strfree(mod, sas_address);
+
+		return (err);
+	}
+
+	topo_mod_dprintf(mod, "unknown disk driver '%s'\n", driver);
+	return (-1);
+}
+
 /*ARGSUSED*/
 static int
 disk_enum(topo_mod_t *mod, tnode_t *baynode,
@@ -49,7 +78,7 @@
     const char *name, topo_instance_t min, topo_instance_t max,
     void *arg, void *notused)
 {
-	char		*device;
+	char		*device, *driver;
 	int		err;
 	nvlist_t	*fmri;
 	topo_list_t	*dlistp = topo_mod_getspecific(mod);
@@ -75,6 +104,22 @@
 	nvlist_free(fmri);
 
 	/*
+	 * For internal storage, first check to see if we need to
+	 * request more detail from an HBA driver.
+	 */
+	if (topo_prop_get_string(baynode, TOPO_PGROUP_BINDING,
+	    TOPO_BINDING_DRIVER, &driver, &err) == 0) {
+		err = disk_declare_driver(mod, baynode, dlistp, driver);
+
+		topo_mod_strfree(mod, driver);
+		return (err);
+	} else if (err != ETOPO_PROP_NOENT) {
+		topo_mod_dprintf(mod, "disk_enum: "
+		    "binding error %s\n", topo_strerror(err));
+		return (-1);
+	}
+
+	/*
 	 * For internal storage, get the path to the occupant from the
 	 * binding group of the bay node
 	 */
--- old/usr/src/lib/fm/topo/modules/common/disk/disk.h	Wed May  7 17:09:48 2014
+++ new/usr/src/lib/fm/topo/modules/common/disk/disk.h	Wed May  7 17:09:48 2014
@@ -22,6 +22,9 @@
 /*
  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  */
+/*
+ * Copyright (c) 2013, Joyent, Inc.  All rights reserved.
+ */
 
 #ifndef _DISK_H
 #define	_DISK_H
@@ -54,8 +57,17 @@
  */
 #define	TOPO_PGROUP_BINDING		"binding"
 #define	TOPO_BINDING_OCCUPANT		"occupant-path"
+#define	TOPO_BINDING_DRIVER		"driver"
 
 /*
+ * The binding group required in platform specific xml that describes 'bay'
+ * nodes containing disks attached to an HBA using the 'mpt_sas' driver.
+ */
+#define	TOPO_BINDING_DEVCTL		"devctl"
+#define	TOPO_BINDING_ENCLOSURE		"enclosure"
+#define	TOPO_BINDING_SLOT		"slot"
+
+/*
  * device node information.
  */
 typedef struct dev_di_node {
--- /dev/null	Wed May  7 17:09:48 2014
+++ new/usr/src/lib/fm/topo/modules/common/disk/disk_drivers.h	Wed May  7 17:09:48 2014
@@ -0,0 +1,31 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+/*
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ */
+
+#ifndef _DISK_DRIVERS_H
+#define	_DISK_DRIVERS_H
+
+#include <fm/topo_mod.h>
+#include <libdevinfo.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int disk_mptsas_find_disk(topo_mod_t *, tnode_t *, char **);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DISK_DRIVERS_H */
--- /dev/null	Wed May  7 17:09:48 2014
+++ new/usr/src/lib/fm/topo/modules/common/disk/disk_mptsas.c	Wed May  7 17:09:48 2014
@@ -0,0 +1,120 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+/*
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ */
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stropts.h>
+#include <string.h>
+#include <strings.h>
+
+#include <fm/topo_mod.h>
+#include <fm/topo_list.h>
+
+#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_init.h>
+#include <sys/scsi/adapters/mpt_sas/mptsas_ioctl.h>
+
+#include "disk.h"
+#include "disk_drivers.h"
+
+static int
+get_sas_address(topo_mod_t *mod, char *devctl, uint32_t enclosure,
+    uint32_t slot, char **sas_address)
+{
+	int fd, err, i;
+	mptsas_get_disk_info_t gdi;
+	mptsas_disk_info_t *di;
+	size_t disz;
+
+	bzero(&gdi, sizeof (gdi));
+
+	if ((fd = open(devctl, O_RDWR)) == -1) {
+		topo_mod_dprintf(mod, "could not open '%s' for ioctl: %s\n",
+		    devctl, strerror(errno));
+		return (-1);
+	}
+
+	if (ioctl(fd, MPTIOCTL_GET_DISK_INFO, &gdi) == -1) {
+		topo_mod_dprintf(mod, "ioctl 1 on '%s' failed: %s\n", devctl,
+		    strerror(errno));
+		(void) close(fd);
+		return (-1);
+	}
+
+	gdi.DiskInfoArraySize = disz = sizeof (mptsas_disk_info_t) *
+	    gdi.DiskCount;
+	gdi.PtrDiskInfoArray = di = topo_mod_alloc(mod, disz);
+	if (di == NULL) {
+		topo_mod_dprintf(mod, "memory allocation failed\n");
+		(void) close(fd);
+		return (-1);
+	}
+
+	if (ioctl(fd, MPTIOCTL_GET_DISK_INFO, &gdi) == -1) {
+		topo_mod_dprintf(mod, "ioctl 2 on '%s' failed: %s\n", devctl,
+		    strerror(errno));
+		topo_mod_free(mod, di, disz);
+		(void) close(fd);
+		return (-1);
+	}
+
+	err = -1;
+	for (i = 0; i < gdi.DiskCount; i++) {
+		if (di[i].Enclosure == enclosure && di[i].Slot == slot) {
+			char sas[17]; /* 16 hex digits and NUL */
+			(void) snprintf(sas, 17, "%llx", di[i].SasAddress);
+			topo_mod_dprintf(mod, "found mpt_sas disk (%d/%d) "
+			    "with adddress %s\n", enclosure, slot, sas);
+			*sas_address = topo_mod_strdup(mod, sas);
+			err = 0;
+			break;
+		}
+	}
+
+	topo_mod_free(mod, di, disz);
+	(void) close(fd);
+	return (err);
+}
+
+int
+disk_mptsas_find_disk(topo_mod_t *mod, tnode_t *baynode, char **sas_address)
+{
+	char *devctl = NULL;
+	uint32_t enclosure, slot;
+	int err;
+
+	/*
+	 * Get the required properties from the node.  These come from
+	 * the static XML mapping.
+	 */
+	if (topo_prop_get_string(baynode, TOPO_PGROUP_BINDING,
+	    TOPO_BINDING_DEVCTL, &devctl, &err) != 0 ||
+	    topo_prop_get_uint32(baynode, TOPO_PGROUP_BINDING,
+	    TOPO_BINDING_ENCLOSURE, &enclosure, &err) != 0 ||
+	    topo_prop_get_uint32(baynode, TOPO_PGROUP_BINDING,
+	    TOPO_BINDING_SLOT, &slot, &err) != 0) {
+		if (devctl != NULL)
+			topo_mod_strfree(mod, devctl);
+		topo_mod_dprintf(mod, "bay node was missing mpt_sas binding "
+		    "properties\n");
+		return (-1);
+	}
+
+	return (get_sas_address(mod, devctl, enclosure, slot, sas_address));
+
+}
--- /dev/null	Wed May  7 17:09:48 2014
+++ new/usr/src/lib/fm/topo/modules/common/fac_prov_mptsas/Makefile	Wed May  7 17:09:48 2014
@@ -0,0 +1,34 @@
+#
+# 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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+# Copyright (c) 2013, Joyent, Inc. All rights reserved.
+#
+
+MODULE = fac_prov_mptsas
+CLASS = common
+
+MODULESRCS = fac_prov_mptsas.c
+
+include ../../Makefile.plugin
+
+CPPFLAGS += -I$(SRC)/uts/common
--- /dev/null	Wed May  7 17:09:48 2014
+++ new/usr/src/lib/fm/topo/modules/common/fac_prov_mptsas/fac_prov_mptsas.c	Wed May  7 17:09:48 2014
@@ -0,0 +1,244 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <string.h>
+#include <strings.h>
+#include <limits.h>
+#include <alloca.h>
+#include <errno.h>
+#include <libnvpair.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <sys/fm/protocol.h>
+#include <fm/libtopo.h>
+#include <fm/topo_mod.h>
+
+#include "sys/scsi/adapters/mpt_sas/mptsas_ioctl.h"
+
+#define	TOPO_METH_MPTSAS_LED_MODE_VERSION	0
+
+static int fac_prov_mptsas_enum(topo_mod_t *, tnode_t *, const char *,
+    topo_instance_t, topo_instance_t, void *, void *);
+
+/*
+ * mpt_sas facility provider methods
+ */
+static int mptsas_led_mode(topo_mod_t *, tnode_t *, topo_version_t,
+    nvlist_t *, nvlist_t **);
+
+const topo_modops_t mptsas_ops = { fac_prov_mptsas_enum, NULL };
+
+const topo_modinfo_t mptsas_info =
+	{ "mpt_sas facility provider", FM_FMRI_SCHEME_HC, TOPO_VERSION,
+	&mptsas_ops };
+
+static const topo_method_t mptsas_fac_methods[] = {
+	{ "mptsas_led_mode", TOPO_PROP_METH_DESC,
+	    TOPO_METH_MPTSAS_LED_MODE_VERSION,
+	    TOPO_STABILITY_INTERNAL, mptsas_led_mode },
+	{ NULL }
+};
+
+/*ARGSUSED*/
+int
+_topo_init(topo_mod_t *mod, topo_version_t version)
+{
+	if (getenv("TOPOFACMPTSASDEBUG") != NULL)
+		topo_mod_setdebug(mod);
+
+	return (topo_mod_register(mod, &mptsas_info, TOPO_VERSION));
+}
+
+void
+_topo_fini(topo_mod_t *mod)
+{
+	topo_mod_unregister(mod);
+}
+
+static int
+do_led_control(topo_mod_t *mod, char *devctl, uint16_t enclosure,
+    uint16_t slot, uint8_t led, uint32_t *ledmode, boolean_t set)
+{
+	int fd;
+	mptsas_led_control_t lc;
+
+	bzero(&lc, sizeof (lc));
+
+	lc.Command = set ? MPTSAS_LEDCTL_FLAG_SET : MPTSAS_LEDCTL_FLAG_GET;
+	lc.Enclosure = enclosure;
+	lc.Slot = slot;
+	lc.Led = led;
+	lc.LedStatus = *ledmode;
+
+	if ((fd = open(devctl, (set ? O_RDWR : O_RDONLY))) == -1) {
+		topo_mod_dprintf(mod, "devctl open failed: %s",
+		    strerror(errno));
+		return (-1);
+	}
+
+	if (ioctl(fd, MPTIOCTL_LED_CONTROL, &lc) == -1) {
+		if (errno == ENOENT) {
+			/*
+			 * If there is not presently a target attached for
+			 * a particular enclosure/slot pair then the driver
+			 * does not track LED status for this bay.  Assume
+			 * all LEDs are off.
+			 */
+			lc.LedStatus = 0;
+		} else {
+			topo_mod_dprintf(mod, "led control ioctl failed: %s",
+			    strerror(errno));
+			(void) close(fd);
+			return (-1);
+		}
+	}
+
+	*ledmode = lc.LedStatus ? TOPO_LED_STATE_ON : TOPO_LED_STATE_OFF;
+
+	(void) close(fd);
+	return (0);
+}
+
+static int
+mptsas_led_mode(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
+    nvlist_t *in, nvlist_t **nvout)
+{
+	int err, ret = 0;
+	tnode_t *pnode = topo_node_parent(node);
+	uint32_t type, ledmode = 0;
+	nvlist_t *pargs, *nvl;
+	char *driver = NULL, *devctl = NULL;
+	uint32_t enclosure, slot;
+	uint8_t mptsas_led;
+	boolean_t set;
+
+	if (vers > TOPO_METH_MPTSAS_LED_MODE_VERSION)
+		return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
+
+	if (topo_prop_get_string(pnode, TOPO_PGROUP_BINDING,
+	    TOPO_BINDING_DRIVER, &driver, &err) != 0 ||
+	    strcmp("mpt_sas", driver) != 0) {
+		topo_mod_dprintf(mod, "%s: Facility driver was not mpt_sas",
+		    __func__);
+		ret = topo_mod_seterrno(mod, EMOD_NVL_INVAL);
+		goto out;
+	}
+	if (topo_prop_get_uint32(node, TOPO_PGROUP_FACILITY, TOPO_FACILITY_TYPE,
+	    &type, &err) != 0) {
+		topo_mod_dprintf(mod, "%s: Failed to lookup %s property "
+		    "(%s)", __func__, TOPO_FACILITY_TYPE, topo_strerror(err));
+		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
+	}
+	switch (type) {
+	case (TOPO_LED_TYPE_SERVICE):
+		mptsas_led = MPTSAS_LEDCTL_LED_FAIL;
+		break;
+	case (TOPO_LED_TYPE_LOCATE):
+		mptsas_led = MPTSAS_LEDCTL_LED_IDENT;
+		break;
+	case (TOPO_LED_TYPE_OK2RM):
+		mptsas_led = MPTSAS_LEDCTL_LED_OK2RM;
+		break;
+	default:
+		topo_mod_dprintf(mod, "%s: Invalid LED type: 0x%x\n", __func__,
+		    type);
+		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
+	}
+	if (topo_prop_get_string(pnode, TOPO_PGROUP_BINDING,
+	    TOPO_BINDING_DEVCTL, &devctl, &err) != 0 ||
+	    topo_prop_get_uint32(pnode, TOPO_PGROUP_BINDING,
+	    TOPO_BINDING_ENCLOSURE, &enclosure, &err) != 0 ||
+	    topo_prop_get_uint32(pnode, TOPO_PGROUP_BINDING,
+	    TOPO_BINDING_SLOT, &slot, &err) != 0) {
+		topo_mod_dprintf(mod, "%s: Facility was missing mpt_sas binding"
+		    " properties\n", __func__);
+		ret = topo_mod_seterrno(mod, EMOD_NVL_INVAL);
+		goto out;
+	}
+
+	if ((nvlist_lookup_nvlist(in, TOPO_PROP_PARGS, &pargs) == 0) &&
+	    nvlist_exists(pargs, TOPO_PROP_VAL_VAL)) {
+		/*
+		 * Set the LED mode
+		 */
+		set = B_TRUE;
+		if ((ret = nvlist_lookup_uint32(pargs, TOPO_PROP_VAL_VAL,
+		    &ledmode)) != 0) {
+			topo_mod_dprintf(mod, "%s: Failed to lookup %s nvpair "
+			    "(%s)\n", __func__, TOPO_PROP_VAL_VAL,
+			    strerror(ret));
+			ret = topo_mod_seterrno(mod, EMOD_NVL_INVAL);
+			goto out;
+		}
+		topo_mod_dprintf(mod, "%s: Setting LED mode to %s\n", __func__,
+		    ledmode ? "ON" : "OFF");
+	} else {
+		/*
+		 * Get the LED mode
+		 */
+		set = B_FALSE;
+		topo_mod_dprintf(mod, "%s: Getting LED mode\n", __func__);
+	}
+
+	if (do_led_control(mod, devctl, enclosure, slot, mptsas_led, &ledmode,
+	    set) != 0) {
+		topo_mod_dprintf(mod, "%s: do_led_control failed", __func__);
+		ret = topo_mod_seterrno(mod, EMOD_UNKNOWN);
+		goto out;
+	}
+
+	if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) != 0 ||
+	    nvlist_add_string(nvl, TOPO_PROP_VAL_NAME, TOPO_LED_MODE) != 0 ||
+	    nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE, TOPO_TYPE_UINT32) != 0 ||
+	    nvlist_add_uint32(nvl, TOPO_PROP_VAL_VAL, ledmode) != 0) {
+		topo_mod_dprintf(mod, "%s: Failed to allocate 'out' nvlist\n",
+		    __func__);
+		nvlist_free(nvl);
+		ret = topo_mod_seterrno(mod, EMOD_NOMEM);
+		goto out;
+	}
+	*nvout = nvl;
+
+out:
+	if (driver != NULL)
+		topo_mod_strfree(mod, driver);
+	if (devctl != NULL)
+		topo_mod_strfree(mod, devctl);
+	return (ret);
+}
+
+/*ARGSUSED*/
+static int
+fac_prov_mptsas_enum(topo_mod_t *mod, tnode_t *rnode, const char *name,
+    topo_instance_t min, topo_instance_t max, void *arg, void *unused)
+{
+	if (topo_node_flags(rnode) == TOPO_NODE_FACILITY) {
+		if (topo_method_register(mod, rnode, mptsas_fac_methods) != 0) {
+			topo_mod_dprintf(mod, "%s: topo_method_register() "
+			    "failed: %s", __func__, topo_mod_errmsg(mod));
+			return (-1);
+		}
+		return (0);
+	}
+
+	topo_mod_dprintf(mod, "%s: unexpected node flags %x", __func__,
+	    topo_node_flags(rnode));
+	return (-1);
+}
--- old/usr/src/pkg/manifests/service-fault-management.mf	Wed May  7 17:09:48 2014
+++ new/usr/src/pkg/manifests/service-fault-management.mf	Wed May  7 17:09:48 2014
@@ -565,6 +565,7 @@
 file path=usr/lib/fm/topo/maps/xfp-hc-topology.xml mode=0444
 file path=usr/lib/fm/topo/plugins/disk.so mode=0555
 file path=usr/lib/fm/topo/plugins/fac_prov_ipmi.so mode=0555
+file path=usr/lib/fm/topo/plugins/fac_prov_mptsas.so mode=0555
 file path=usr/lib/fm/topo/plugins/ipmi.so mode=0555
 file path=usr/lib/fm/topo/plugins/ses.so mode=0555
 file path=usr/lib/fm/topo/plugins/xfp.so mode=0555
--- old/usr/src/uts/common/Makefile.files	Wed May  7 17:09:48 2014
+++ new/usr/src/uts/common/Makefile.files	Wed May  7 17:09:48 2014
@@ -1840,7 +1840,8 @@
 
 MXFE_OBJS += mxfe.o
 
-MPTSAS_OBJS += mptsas.o mptsas_impl.o mptsas_init.o mptsas_raid.o mptsas_smhba.o
+MPTSAS_OBJS += mptsas.o mptsas_hash.o mptsas_impl.o mptsas_init.o \
+		mptsas_raid.o mptsas_smhba.o
 
 SFE_OBJS += sfe.o sfe_util.o
 
--- old/usr/src/uts/common/io/comstar/lu/stmf_sbd/sbd.c	Wed May  7 17:09:48 2014
+++ new/usr/src/uts/common/io/comstar/lu/stmf_sbd/sbd.c	Wed May  7 17:09:48 2014
@@ -18,10 +18,11 @@
  *
  * CDDL HEADER END
  */
+
 /*
  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
- *
- * Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
+ * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 2013 by Delphix. All rights reserved.
  */
 
 #include <sys/conf.h>
@@ -1719,7 +1720,6 @@
 	char *namebuf;
 	sbd_lu_t *sl;
 	stmf_lu_t *lu;
-	sbd_status_t sret;
 	char *p;
 	int sz;
 	int alloc_sz;
@@ -1835,11 +1835,6 @@
 	if (slu->slu_write_protected) {
 		sl->sl_flags |= SL_WRITE_PROTECTED;
 	}
-	if (slu->slu_writeback_cache_disable) {
-		sl->sl_flags |= SL_WRITEBACK_CACHE_DISABLE |
-		    SL_SAVED_WRITE_CACHE_DISABLE;
-	}
-
 	if (slu->slu_blksize_valid) {
 		if ((slu->slu_blksize & (slu->slu_blksize - 1)) ||
 		    (slu->slu_blksize > (32 * 1024)) ||
@@ -1876,27 +1871,30 @@
 	}
 
 	/*
-	 * set write cache disable on the device
-	 * if it fails, we'll support it using sync/flush
+	 * Check if we were explicitly asked to disable/enable write
+	 * cache on the device, otherwise get current device setting.
 	 */
-	if (slu->slu_writeback_cache_disable) {
-		(void) sbd_wcd_set(1, sl);
-		wcd = 1;
-	/*
-	 * Attempt to set it to enable, if that fails and it was explicitly set
-	 * return an error, otherwise get the current setting and use that
-	 */
-	} else {
-		sret = sbd_wcd_set(0, sl);
-		if (slu->slu_writeback_cache_disable_valid &&
-		    sret != SBD_SUCCESS) {
-			*err_ret = SBD_RET_WRITE_CACHE_SET_FAILED;
-			ret = EFAULT;
-			goto scm_err_out;
+	if (slu->slu_writeback_cache_disable_valid) {
+		if (slu->slu_writeback_cache_disable) {
+			/*
+			 * Set write cache disable on the device. If it fails,
+			 * we'll support it using sync/flush.
+			 */
+			(void) sbd_wcd_set(1, sl);
+			wcd = 1;
+		} else {
+			/*
+			 * Set write cache enable on the device. If it fails,
+			 * return an error.
+			 */
+			if (sbd_wcd_set(0, sl) != SBD_SUCCESS) {
+				*err_ret = SBD_RET_WRITE_CACHE_SET_FAILED;
+				ret = EFAULT;
+				goto scm_err_out;
+			}
 		}
-		if (sret != SBD_SUCCESS) {
-			sbd_wcd_get(&wcd, sl);
-		}
+	} else {
+		sbd_wcd_get(&wcd, sl);
 	}
 
 	if (wcd) {
@@ -3000,7 +2998,6 @@
 {
 	int ret;
 	long resid;
-	hrtime_t xfer_start, xfer_done;
 
 	if ((offset + size) > sl->sl_lu_size) {
 		return (SBD_IO_PAST_EOF);
@@ -3019,8 +3016,6 @@
 		size = store_end;
 	}
 
-	xfer_start = gethrtime();
-	stmf_lu_xfer_start(task);
 	DTRACE_PROBE5(backing__store__read__start, sbd_lu_t *, sl,
 	    uint8_t *, buf, uint64_t, size, uint64_t, offset,
 	    scsi_task_t *, task);
@@ -3041,8 +3036,6 @@
 	    &resid);
 	rw_exit(&sl->sl_access_state_lock);
 
-	xfer_done = gethrtime() - xfer_start;
-	stmf_lu_xfer_done(task, B_TRUE /* read */, size, xfer_done);
 	DTRACE_PROBE6(backing__store__read__end, sbd_lu_t *, sl,
 	    uint8_t *, buf, uint64_t, size, uint64_t, offset,
 	    int, ret, scsi_task_t *, task);
@@ -3065,7 +3058,6 @@
 	long resid;
 	sbd_status_t sret = SBD_SUCCESS;
 	int ioflag;
-	hrtime_t xfer_start, xfer_done;
 
 	if ((offset + size) > sl->sl_lu_size) {
 		return (SBD_IO_PAST_EOF);
@@ -3080,8 +3072,6 @@
 		ioflag = 0;
 	}
 
-	xfer_start = gethrtime();
-	stmf_lu_xfer_start(task);
 	DTRACE_PROBE5(backing__store__write__start, sbd_lu_t *, sl,
 	    uint8_t *, buf, uint64_t, size, uint64_t, offset,
 	    scsi_task_t *, task);
@@ -3102,8 +3092,6 @@
 	    &resid);
 	rw_exit(&sl->sl_access_state_lock);
 
-	xfer_done = gethrtime() - xfer_start;
-	stmf_lu_xfer_done(task, B_FALSE /* write */, size, xfer_done);
 	DTRACE_PROBE6(backing__store__write__end, sbd_lu_t *, sl,
 	    uint8_t *, buf, uint64_t, size, uint64_t, offset,
 	    int, ret, scsi_task_t *, task);
--- old/usr/src/uts/common/io/comstar/lu/stmf_sbd/sbd_scsi.c	Wed May  7 17:09:49 2014
+++ new/usr/src/uts/common/io/comstar/lu/stmf_sbd/sbd_scsi.c	Wed May  7 17:09:49 2014
@@ -20,8 +20,8 @@
  */
 /*
  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
- *
  * Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
+ * Copyright (c) 2013 by Delphix. All rights reserved.
  */
 
 #include <sys/conf.h>
@@ -218,7 +218,6 @@
 	uint_t nblks;
 	uint64_t blksize = sl->sl_blksize;
 	size_t db_private_sz;
-	hrtime_t xfer_start, xfer_elapsed;
 	uintptr_t pad;
 
 	ASSERT(rw_read_held(&sl->sl_access_state_lock));
@@ -334,18 +333,12 @@
 		 * Accounting for start of read.
 		 * Note there is no buffer address for the probe yet.
 		 */
-		stmf_lu_xfer_start(task);
 		DTRACE_PROBE5(backing__store__read__start, sbd_lu_t *, sl,
 		    uint8_t *, NULL, uint64_t, xfer_len,
 		    uint64_t, offset, scsi_task_t *, task);
-		xfer_start = gethrtime();
 
 		ret = sbd_zvol_alloc_read_bufs(sl, dbuf);
 
-		xfer_elapsed = gethrtime() - xfer_start;
-
-		stmf_lu_xfer_done(task, B_TRUE /* read */, (uint64_t)xfer_len,
-		    xfer_elapsed);
 		DTRACE_PROBE6(backing__store__read__end, sbd_lu_t *, sl,
 		    uint8_t *, NULL, uint64_t, xfer_len,
 		    uint64_t, offset, int, ret, scsi_task_t *, task);
@@ -607,7 +600,6 @@
 	int scmd_err, scmd_xfer_done;
 	stmf_status_t xfer_status = dbuf->db_xfer_status;
 	uint32_t data_size = dbuf->db_data_size;
-	hrtime_t xfer_start;
 
 	ASSERT(zvio);
 
@@ -627,12 +619,9 @@
 	    (scmd->flags & SBD_SCSI_CMD_XFER_FAIL) ||
 	    (xfer_status != STMF_SUCCESS));
 
-	/* start the accounting clock */
-	stmf_lu_xfer_start(task);
 	DTRACE_PROBE5(backing__store__write__start, sbd_lu_t *, sl,
 	    uint8_t *, NULL, uint64_t, data_size,
 	    uint64_t, zvio->zvio_offset, scsi_task_t *, task);
-	xfer_start = gethrtime();
 
 	if (scmd_err) {
 		/* just return the write buffers */
@@ -647,9 +636,6 @@
 		ret = sbd_zvol_rele_write_bufs(sl, dbuf);
 	}
 
-	/* finalize accounting */
-	stmf_lu_xfer_done(task, B_FALSE /* not read */, data_size,
-	    (gethrtime() - xfer_start));
 	DTRACE_PROBE6(backing__store__write__end, sbd_lu_t *, sl,
 	    uint8_t *, NULL, uint64_t, data_size,
 	    uint64_t, zvio->zvio_offset, int, ret,  scsi_task_t *, task);
@@ -739,7 +725,6 @@
 	struct iovec		*iov, *tiov, iov1[8];
 	uint32_t		len, resid;
 	int			ret, i, iovcnt, flags;
-	hrtime_t		xfer_start;
 	boolean_t		is_read;
 
 	ASSERT(cmd == SBD_CMD_SCSI_READ || cmd == SBD_CMD_SCSI_WRITE);
@@ -777,9 +762,6 @@
 	uio.uio_resid = (uint64_t)len;
 	uio.uio_llimit = RLIM64_INFINITY;
 
-	/* start the accounting clock */
-	stmf_lu_xfer_start(task);
-	xfer_start = gethrtime();
 	if (is_read == B_TRUE) {
 		uio.uio_fmode = FREAD;
 		uio.uio_extflg = UIO_COPY_CACHED;
@@ -808,9 +790,6 @@
 		    uint8_t *, NULL, uint64_t, len, uint64_t, laddr, int, ret,
 		    scsi_task_t *, task);
 	}
-	/* finalize accounting */
-	stmf_lu_xfer_done(task, is_read, (uint64_t)len,
-	    (gethrtime() - xfer_start));
 
 	if (iov != &iov1[0])
 		kmem_free(iov, iovcnt * sizeof (*iov));
--- old/usr/src/uts/common/io/comstar/port/iscsit/iscsit.c	Wed May  7 17:09:49 2014
+++ new/usr/src/uts/common/io/comstar/port/iscsit/iscsit.c	Wed May  7 17:09:49 2014
@@ -21,7 +21,7 @@
 /*
  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  *
- * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
  */
 
 #include <sys/cpuvar.h>
@@ -2173,6 +2173,18 @@
 	iscsit_conn_t *ict = rx_pdu->isp_ic->ic_handle;
 
 	/*
+	 * If this isn't a login packet, we need a session.  Otherwise
+	 * this is a protocol error (perhaps one IDM should've caught?).
+	 */
+	if (IDM_PDU_OPCODE(rx_pdu) != ISCSI_OP_LOGIN_CMD &&
+	    ict->ict_sess == NULL) {
+		DTRACE_PROBE2(iscsi__idm__deferred__no__session,
+		    iscsit_conn_t *, ict, idm_pdu_t *, rx_pdu);
+		idm_pdu_complete(rx_pdu, IDM_STATUS_FAIL);
+		return;
+	}
+
+	/*
 	 * If the connection has been lost then ignore new PDU's
 	 */
 	mutex_enter(&ict->ict_mutex);
--- old/usr/src/uts/common/io/comstar/port/pppt/pppt.c	Wed May  7 17:09:49 2014
+++ new/usr/src/uts/common/io/comstar/port/pppt/pppt.c	Wed May  7 17:09:49 2014
@@ -20,6 +20,7 @@
  */
 /*
  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2013, Nexenta Systems, Inc. All rights reserved.
  */
 
 #include <sys/cpuvar.h>
@@ -131,8 +132,6 @@
 
 static pppt_status_t pppt_task_try_abort(pppt_task_t *ptask);
 
-static pppt_status_t pppt_task_hold(pppt_task_t *ptask);
-
 static void pppt_task_rele(pppt_task_t *ptask);
 
 static void pppt_task_update_state(pppt_task_t *ptask,
@@ -801,7 +800,7 @@
 	pppt_task_t *ptask = task->task_port_private;
 	pppt_sess_t *ps = ptask->pt_sess;
 
-	pppt_task_free(ptask);
+	pppt_task_rele(ptask);
 	pppt_sess_rele(ps);
 }
 
@@ -1209,7 +1208,7 @@
 		ptask->pt_state = PTS_INIT;
 		ptask->pt_read_buf = NULL;
 		ptask->pt_read_xfer_msgid = 0;
-		cv_init(&ptask->pt_cv, NULL, CV_DRIVER, NULL);
+		ptask->pt_refcnt = 0;
 		mutex_init(&ptask->pt_mutex, NULL, MUTEX_DRIVER, NULL);
 		immed_pbuf = (pppt_buf_t *)(ptask + 1);
 		bzero(immed_pbuf, sizeof (*immed_pbuf));
@@ -1232,8 +1231,8 @@
 pppt_task_free(pppt_task_t *ptask)
 {
 	mutex_enter(&ptask->pt_mutex);
+	ASSERT(ptask->pt_refcnt == 0);
 	mutex_destroy(&ptask->pt_mutex);
-	cv_destroy(&ptask->pt_cv);
 	kmem_free(ptask, sizeof (pppt_task_t) + sizeof (pppt_buf_t) +
 	    sizeof (stmf_data_buf_t));
 }
@@ -1249,6 +1248,8 @@
 	mutex_enter(&ptask->pt_mutex);
 	if (avl_find(&ptask->pt_sess->ps_task_list, ptask, &where) == NULL) {
 		pppt_task_update_state(ptask, PTS_ACTIVE);
+		/* Manually increment refcnt, sincd we hold the mutex... */
+		ptask->pt_refcnt++;
 		avl_insert(&ptask->pt_sess->ps_task_list, ptask, where);
 		mutex_exit(&ptask->pt_mutex);
 		mutex_exit(&ptask->pt_sess->ps_mutex);
@@ -1289,6 +1290,8 @@
 		mutex_enter(&ptask->pt_sess->ps_mutex);
 		avl_remove(&ptask->pt_sess->ps_task_list, ptask);
 		mutex_exit(&ptask->pt_sess->ps_mutex);
+		/* Out of the AVL tree, so drop a reference. */
+		pppt_task_rele(ptask);
 	}
 
 	return (pppt_status);
@@ -1401,12 +1404,14 @@
 		mutex_enter(&ptask->pt_sess->ps_mutex);
 		avl_remove(&ptask->pt_sess->ps_task_list, ptask);
 		mutex_exit(&ptask->pt_sess->ps_mutex);
+		/* Out of the AVL tree, so drop a reference. */
+		pppt_task_rele(ptask);
 	}
 
 	return (pppt_status);
 }
 
-static pppt_status_t
+pppt_status_t
 pppt_task_hold(pppt_task_t *ptask)
 {
 	pppt_status_t	pppt_status = PPPT_STATUS_SUCCESS;
@@ -1425,10 +1430,14 @@
 static void
 pppt_task_rele(pppt_task_t *ptask)
 {
+	boolean_t freeit;
+
 	mutex_enter(&ptask->pt_mutex);
 	ptask->pt_refcnt--;
-	cv_signal(&ptask->pt_cv);
+	freeit = (ptask->pt_refcnt == 0);
 	mutex_exit(&ptask->pt_mutex);
+	if (freeit)
+		pppt_task_free(ptask);
 }
 
 static void
@@ -1440,5 +1449,4 @@
 
 	ASSERT(mutex_owned(&ptask->pt_mutex));
 	ptask->pt_state = new_state;
-	cv_signal(&ptask->pt_cv);
 }
--- old/usr/src/uts/common/io/comstar/port/pppt/pppt.h	Wed May  7 17:09:49 2014
+++ new/usr/src/uts/common/io/comstar/port/pppt/pppt.h	Wed May  7 17:09:49 2014
@@ -20,6 +20,7 @@
  */
 /*
  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2013, Nexenta Systems, Inc. All rights reserved.
  */
 #ifndef _PPPT_H
 #define	_PPPT_H
@@ -168,7 +169,6 @@
 	avl_node_t		pt_sess_ln;
 	int			pt_refcnt;
 	kmutex_t		pt_mutex;
-	kcondvar_t		pt_cv;
 	stmf_ic_msgid_t		pt_task_id;
 	uint8_t			pt_lun_id[16];
 	pppt_task_state_t	pt_state;
@@ -296,6 +296,8 @@
 
 void pppt_tgt_sm_ctl(stmf_local_port_t *lport, int cmd, void *arg);
 
+pppt_status_t pppt_task_hold(pppt_task_t *);
+
 #ifdef	__cplusplus
 }
 #endif
--- old/usr/src/uts/common/io/comstar/port/pppt/pppt_msg.c	Wed May  7 17:09:49 2014
+++ new/usr/src/uts/common/io/comstar/port/pppt/pppt_msg.c	Wed May  7 17:09:49 2014
@@ -20,6 +20,7 @@
  */
 /*
  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2013, Nexenta Systems, Inc. All rights reserved.
  */
 
 #include <sys/cpuvar.h>
@@ -316,8 +317,8 @@
 	    scmd->icsc_task_lun_no,
 	    scmd->icsc_task_cdb_length, 0);
 	if (ptask->pt_stmf_task == NULL) {
+		/* NOTE: pppt_task_done() will free ptask. */
 		(void) pppt_task_done(ptask);
-		pppt_task_free(ptask);
 		pppt_sess_rele(pppt_sess);
 		pppt_msg_tx_status(msg, STMF_ALLOC_FAILURE);
 		stmf_ic_msg_free(msg);
@@ -326,6 +327,8 @@
 	}
 
 	task = ptask->pt_stmf_task;
+	/* task_port_private reference is a real reference. */
+	(void) pppt_task_hold(ptask);
 	task->task_port_private = ptask;
 	task->task_flags = scmd->icsc_task_flags;
 	task->task_additional_flags = 0;
--- old/usr/src/uts/common/io/comstar/stmf/stmf.c	Wed May  7 17:09:49 2014
+++ new/usr/src/uts/common/io/comstar/stmf/stmf.c	Wed May  7 17:09:49 2014
@@ -23,6 +23,8 @@
  */
 /*
  * Copyright 2012, Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 2013 by Delphix. All rights reserved.
+ * Copyright (c) 2013 by Saso Kiselkov. All rights reserved.
  */
 
 #include <sys/conf.h>
@@ -65,6 +67,15 @@
 #define	MSG_ID_TM_BIT	0x8000000000000000
 #define	ALIGNED_TO_8BYTE_BOUNDARY(i)	(((i) + 7) & ~7)
 
+/*
+ * When stmf_io_deadman_enabled is set to B_TRUE, we check that finishing up
+ * I/O operations on an offlining LU doesn't take longer than stmf_io_deadman
+ * seconds. If it does, we trigger a panic to inform the user of hung I/O
+ * blocking us for too long.
+ */
+boolean_t stmf_io_deadman_enabled = B_TRUE;
+int stmf_io_deadman = 1000;			/* seconds */
+
 struct stmf_svc_clocks;
 
 static int stmf_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
@@ -91,6 +102,7 @@
 void stmf_svc_init();
 stmf_status_t stmf_svc_fini();
 void stmf_svc(void *arg);
+static void stmf_wait_ilu_tasks_finish(stmf_i_lu_t *ilu);
 void stmf_svc_queue(int cmd, void *obj, stmf_state_change_info_t *info);
 static void stmf_svc_kill_obj_requests(void *obj);
 static void stmf_svc_timeout(struct stmf_svc_clocks *);
@@ -163,14 +175,6 @@
     scsi_devid_desc_t *rport_devid);
 static void stmf_irport_deregister(stmf_i_remote_port_t *irport);
 
-static void stmf_teardown_itl_kstats(stmf_i_itl_kstat_t *ks);
-static void stmf_delete_itl_kstat_by_lport(char *);
-static void stmf_delete_itl_kstat_by_guid(char *);
-static int stmf_itl_kstat_compare(const void*, const void*);
-static stmf_i_itl_kstat_t *stmf_itl_kstat_lookup(char *kstat_nm);
-static stmf_i_itl_kstat_t *stmf_itl_kstat_create(stmf_itl_data_t *itl,
-    char *nm, scsi_devid_desc_t *lport, scsi_devid_desc_t *lun);
-
 extern struct mod_ops mod_driverops;
 
 /* =====[ Tunables ]===== */
@@ -312,9 +316,6 @@
 	    id_space_create("lport-instances", 0, MAX_ILPORT);
 	stmf_state.stmf_irport_inst_space =
 	    id_space_create("rport-instances", 0, MAX_IRPORT);
-	avl_create(&stmf_state.stmf_itl_kstat_list,
-	    stmf_itl_kstat_compare, sizeof (stmf_i_itl_kstat_t),
-	    offsetof(stmf_i_itl_kstat_t, iitl_kstat_ln));
 	stmf_view_init();
 	stmf_svc_init();
 	stmf_dlun_init();
@@ -326,7 +327,6 @@
 {
 	int ret;
 	stmf_i_remote_port_t	*irport;
-	stmf_i_itl_kstat_t	*ks_itl;
 	void			*avl_dest_cookie = NULL;
 
 	if (stmf_state.stmf_service_running)
@@ -367,14 +367,6 @@
 	id_space_destroy(stmf_state.stmf_ilport_inst_space);
 	id_space_destroy(stmf_state.stmf_irport_inst_space);
 
-	avl_dest_cookie = NULL;
-	while ((ks_itl = avl_destroy_nodes(&stmf_state.stmf_itl_kstat_list,
-	    &avl_dest_cookie)) != NULL) {
-		stmf_teardown_itl_kstats(ks_itl);
-		kmem_free(ks_itl, sizeof (ks_itl));
-	}
-	avl_destroy(&stmf_state.stmf_itl_kstat_list);
-
 	kmem_free(stmf_trace_buf, stmf_trace_buf_size);
 	mutex_destroy(&trace_buf_lock);
 	mutex_destroy(&stmf_state.stmf_lock);
@@ -1592,6 +1584,7 @@
 
 	return (0);
 }
+
 /*
  * handles registration message from pppt for a logical unit
  */
@@ -3059,6 +3052,7 @@
 	}
 	ilu->ilu_cur_task_cntr = &ilu->ilu_task_cntr1;
 	STMF_EVENT_ALLOC_HANDLE(ilu->ilu_event_hdl);
+	cv_init(&ilu->ilu_offline_pending_cv, NULL, CV_DRIVER, NULL);
 	stmf_create_kstat_lu(ilu);
 	/*
 	 * register with proxy module if available and logical unit
@@ -3196,7 +3190,7 @@
 		kstat_delete(ilu->ilu_kstat_io);
 		mutex_destroy(&ilu->ilu_kstat_lock);
 	}
-	stmf_delete_itl_kstat_by_guid(ilu->ilu_ascii_hex_guid);
+	cv_destroy(&ilu->ilu_offline_pending_cv);
 	mutex_exit(&stmf_state.stmf_lock);
 	return (STMF_SUCCESS);
 }
@@ -3374,7 +3368,6 @@
 		kstat_delete(ilport->ilport_kstat_io);
 		mutex_destroy(&ilport->ilport_kstat_lock);
 	}
-	stmf_delete_itl_kstat_by_lport(ilport->ilport_kstat_tgt_name);
 	mutex_exit(&stmf_state.stmf_lock);
 	return (STMF_SUCCESS);
 }
@@ -3703,320 +3696,6 @@
 	return (NULL);
 }
 
-#define	MAX_ALIAS		128
-
-static int
-stmf_itl_kstat_compare(const void *itl_kstat_1, const void *itl_kstat_2)
-{
-	const	stmf_i_itl_kstat_t	*kstat_nm1 = itl_kstat_1;
-	const	stmf_i_itl_kstat_t	*kstat_nm2 = itl_kstat_2;
-	int	ret;
-
-	ret = strcmp(kstat_nm1->iitl_kstat_nm, kstat_nm2->iitl_kstat_nm);
-	if (ret < 0) {
-		return (-1);
-	} else if (ret > 0) {
-		return (1);
-	}
-	return (0);
-}
-
-static stmf_i_itl_kstat_t *
-stmf_itl_kstat_lookup(char *kstat_nm)
-{
-	stmf_i_itl_kstat_t	tmp;
-	stmf_i_itl_kstat_t	*itl_kstat;
-
-	ASSERT(mutex_owned(&stmf_state.stmf_lock));
-	(void) strcpy(tmp.iitl_kstat_nm, kstat_nm);
-	itl_kstat = avl_find(&stmf_state.stmf_itl_kstat_list, &tmp, NULL);
-	return (itl_kstat);
-}
-
-static void
-stmf_delete_itl_kstat_by_lport(char *tgt)
-{
-	stmf_i_itl_kstat_t	*ks_itl, *next;
-
-	ASSERT(mutex_owned(&stmf_state.stmf_lock));
-	ks_itl = avl_first(&stmf_state.stmf_itl_kstat_list);
-	for (; ks_itl != NULL; ks_itl = next) {
-		next = AVL_NEXT(&stmf_state.stmf_itl_kstat_list, ks_itl);
-		if (strcmp(ks_itl->iitl_kstat_lport, tgt) == 0) {
-			stmf_teardown_itl_kstats(ks_itl);
-			avl_remove(&stmf_state.stmf_itl_kstat_list, ks_itl);
-			kmem_free(ks_itl, sizeof (stmf_i_itl_kstat_t));
-		}
-	}
-}
-
-static void
-stmf_delete_itl_kstat_by_guid(char *guid)
-{
-	stmf_i_itl_kstat_t	*ks_itl, *next;
-
-	ASSERT(mutex_owned(&stmf_state.stmf_lock));
-	ks_itl = avl_first(&stmf_state.stmf_itl_kstat_list);
-	for (; ks_itl != NULL; ks_itl = next) {
-		next = AVL_NEXT(&stmf_state.stmf_itl_kstat_list, ks_itl);
-		if (strcmp(ks_itl->iitl_kstat_guid, guid) == 0) {
-			stmf_teardown_itl_kstats(ks_itl);
-			avl_remove(&stmf_state.stmf_itl_kstat_list, ks_itl);
-			kmem_free(ks_itl, sizeof (stmf_i_itl_kstat_t));
-		}
-	}
-}
-
-static stmf_i_itl_kstat_t *
-stmf_itl_kstat_create(stmf_itl_data_t *itl, char *nm,
-    scsi_devid_desc_t *lport, scsi_devid_desc_t *lun)
-{
-	stmf_i_itl_kstat_t	*ks_itl;
-	int			i, len;
-
-	ASSERT(mutex_owned(&stmf_state.stmf_lock));
-	if ((ks_itl = stmf_itl_kstat_lookup(nm)) != NULL)
-		return (ks_itl);
-
-	len = sizeof (stmf_i_itl_kstat_t);
-	ks_itl = kmem_zalloc(len, KM_NOSLEEP);
-	if (ks_itl == NULL)
-		return (NULL);
-
-	(void) strcpy(ks_itl->iitl_kstat_nm, nm);
-	bcopy(lport->ident, ks_itl->iitl_kstat_lport, lport->ident_length);
-	ks_itl->iitl_kstat_lport[lport->ident_length] = '\0';
-	for (i = 0; i < STMF_GUID_INPUT / 2; i++) {
-		(void) sprintf(&ks_itl->iitl_kstat_guid[i * 2], "%02x",
-		    lun->ident[i]);
-	}
-	ks_itl->iitl_kstat_strbuf = itl->itl_kstat_strbuf;
-	ks_itl->iitl_kstat_strbuflen = itl->itl_kstat_strbuflen;
-	ks_itl->iitl_kstat_info = itl->itl_kstat_info;
-	ks_itl->iitl_kstat_taskq = itl->itl_kstat_taskq;
-	ks_itl->iitl_kstat_lu_xfer = itl->itl_kstat_lu_xfer;
-	ks_itl->iitl_kstat_lport_xfer = itl->itl_kstat_lport_xfer;
-	avl_add(&stmf_state.stmf_itl_kstat_list, ks_itl);
-
-	return (ks_itl);
-}
-
-stmf_status_t
-stmf_setup_itl_kstats(stmf_itl_data_t *itl)
-{
-	char				ks_itl_id[32];
-	char				ks_nm[KSTAT_STRLEN];
-	char				ks_itl_nm[KSTAT_STRLEN];
-	stmf_kstat_itl_info_t		*ks_itl;
-	stmf_scsi_session_t		*ss;
-	stmf_i_scsi_session_t		*iss;
-	stmf_i_local_port_t		*ilport;
-	char				*strbuf;
-	int				id, len, i;
-	char				*rport_alias;
-	char				*lport_alias;
-	char				*lu_alias;
-	stmf_i_itl_kstat_t		*tmp_kstat;
-
-	/*
-	 * Allocate enough memory in the ITL to hold the relevant
-	 * identifiers.
-	 * rport and lport identifiers come from the stmf_scsi_session_t.
-	 * ident might not be null terminated.
-	 */
-	ss = itl->itl_session->iss_ss;
-	iss = ss->ss_stmf_private;
-	ilport = ss->ss_lport->lport_stmf_private;
-	(void) snprintf(ks_itl_id, 32, "%d.%d.%d",
-	    iss->iss_irport->irport_instance, ilport->ilport_instance,
-	    itl->itl_lun);
-
-	(void) snprintf(ks_itl_nm, KSTAT_STRLEN, "itl_%s", ks_itl_id);
-	/*
-	 * let's verify this itl_kstat already exist
-	 */
-	if ((tmp_kstat = stmf_itl_kstat_lookup(ks_itl_nm)) != NULL) {
-		itl->itl_kstat_strbuf = tmp_kstat->iitl_kstat_strbuf;
-		itl->itl_kstat_strbuflen = tmp_kstat->iitl_kstat_strbuflen;
-		itl->itl_kstat_info = tmp_kstat->iitl_kstat_info;
-		itl->itl_kstat_taskq = tmp_kstat->iitl_kstat_taskq;
-		itl->itl_kstat_lu_xfer = tmp_kstat->iitl_kstat_lu_xfer;
-		itl->itl_kstat_lport_xfer = tmp_kstat->iitl_kstat_lport_xfer;
-		return (STMF_SUCCESS);
-	}
-
-	/* New itl_kstat */
-	rport_alias = (ss->ss_rport_alias == NULL) ?
-	    "" : ss->ss_rport_alias;
-	lport_alias = (ss->ss_lport->lport_alias == NULL) ?
-	    "" : ss->ss_lport->lport_alias;
-	lu_alias = (itl->itl_ilu->ilu_lu->lu_alias == NULL) ?
-	    "" : itl->itl_ilu->ilu_lu->lu_alias;
-
-	itl->itl_kstat_strbuflen = (ss->ss_rport_id->ident_length + 1) +
-	    (strnlen(rport_alias, MAX_ALIAS) + 1) +
-	    (ss->ss_lport->lport_id->ident_length + 1) +
-	    (strnlen(lport_alias, MAX_ALIAS) + 1) +
-	    (STMF_GUID_INPUT + 1) +
-	    (strnlen(lu_alias, MAX_ALIAS) + 1) +
-	    MAX_PROTO_STR_LEN;
-	itl->itl_kstat_strbuf = kmem_zalloc(itl->itl_kstat_strbuflen,
-	    KM_NOSLEEP);
-	if (itl->itl_kstat_strbuf == NULL) {
-		return (STMF_ALLOC_FAILURE);
-	}
-
-	ks_itl = (stmf_kstat_itl_info_t *)kmem_zalloc(sizeof (*ks_itl),
-	    KM_NOSLEEP);
-	if (ks_itl == NULL) {
-		kmem_free(itl->itl_kstat_strbuf, itl->itl_kstat_strbuflen);
-		return (STMF_ALLOC_FAILURE);
-	}
-
-	if ((itl->itl_kstat_info = kstat_create(STMF_MODULE_NAME,
-	    0, ks_itl_nm, "misc", KSTAT_TYPE_NAMED,
-	    sizeof (stmf_kstat_itl_info_t) / sizeof (kstat_named_t),
-	    KSTAT_FLAG_VIRTUAL)) == NULL) {
-		goto itl_kstat_cleanup;
-	}
-
-	itl->itl_kstat_info->ks_data_size += itl->itl_kstat_strbuflen;
-	itl->itl_kstat_info->ks_data = ks_itl;
-
-	kstat_named_init(&ks_itl->i_rport_name, "rport-name",
-	    KSTAT_DATA_STRING);
-	kstat_named_init(&ks_itl->i_rport_alias, "rport-alias",
-	    KSTAT_DATA_STRING);
-	kstat_named_init(&ks_itl->i_lport_name, "lport-name",
-	    KSTAT_DATA_STRING);
-	kstat_named_init(&ks_itl->i_lport_alias, "lport-alias",
-	    KSTAT_DATA_STRING);
-	kstat_named_init(&ks_itl->i_protocol, "protocol",
-	    KSTAT_DATA_STRING);
-	kstat_named_init(&ks_itl->i_lu_guid, "lu-guid",
-	    KSTAT_DATA_STRING);
-	kstat_named_init(&ks_itl->i_lu_alias, "lu-alias",
-	    KSTAT_DATA_STRING);
-	kstat_named_init(&ks_itl->i_lu_number, "lu-number",
-	    KSTAT_DATA_UINT64);
-	kstat_named_init(&ks_itl->i_task_waitq_elapsed, "task-waitq-elapsed",
-	    KSTAT_DATA_UINT64);
-	kstat_named_init(&ks_itl->i_task_read_elapsed, "task-read-elapsed",
-	    KSTAT_DATA_UINT64);
-	kstat_named_init(&ks_itl->i_task_write_elapsed, "task-write-elapsed",
-	    KSTAT_DATA_UINT64);
-	kstat_named_init(&ks_itl->i_lu_read_elapsed, "lu-read-elapsed",
-	    KSTAT_DATA_UINT64);
-	kstat_named_init(&ks_itl->i_lu_write_elapsed, "lu-write-elapsed",
-	    KSTAT_DATA_UINT64);
-	kstat_named_init(&ks_itl->i_lport_read_elapsed, "lport-read-elapsed",
-	    KSTAT_DATA_UINT64);
-	kstat_named_init(&ks_itl->i_lport_write_elapsed, "lport-write-elapsed",
-	    KSTAT_DATA_UINT64);
-
-	strbuf = itl->itl_kstat_strbuf;
-
-	/* Rport */
-	len = ss->ss_rport_id->ident_length;
-	bcopy(ss->ss_rport_id->ident, strbuf, len);
-	strbuf += len;
-	*strbuf = '\0';
-	kstat_named_setstr(&ks_itl->i_rport_name, strbuf - len);
-	strbuf++;
-
-	len = strnlen(rport_alias, MAX_ALIAS);
-	(void) strncpy(strbuf, rport_alias, len + 1);
-	kstat_named_setstr(&ks_itl->i_rport_alias, strbuf);
-	strbuf += len + 1;
-
-	/* Lport */
-	len = ss->ss_lport->lport_id->ident_length;
-	bcopy(ss->ss_lport->lport_id->ident, strbuf, len);
-	strbuf += len;
-	*strbuf = '\0';
-	kstat_named_setstr(&ks_itl->i_lport_name, strbuf - len);
-	strbuf++;
-
-	len = strnlen(lport_alias, MAX_ALIAS);
-	(void) strncpy(strbuf, lport_alias, len + 1);
-	kstat_named_setstr(&ks_itl->i_lport_alias, strbuf);
-	strbuf += len + 1;
-
-	id = (ss->ss_lport->lport_id->protocol_id > PROTOCOL_ANY) ?
-	    PROTOCOL_ANY : ss->ss_lport->lport_id->protocol_id;
-	kstat_named_setstr(&ks_itl->i_protocol, protocol_ident[id]);
-
-	/* LU */
-	for (i = 0; i < STMF_GUID_INPUT / 2; i++) {
-		(void) sprintf(&strbuf[i * 2], "%02x",
-		    itl->itl_ilu->ilu_lu->lu_id->ident[i]);
-	}
-	kstat_named_setstr(&ks_itl->i_lu_guid, strbuf);
-	strbuf += STMF_GUID_INPUT + 1;
-
-	len = strnlen(lu_alias, MAX_ALIAS);
-	(void) strncpy(strbuf, lu_alias, len + 1);
-	kstat_named_setstr(&ks_itl->i_lu_alias, strbuf);
-	strbuf += len + 1;
-
-	ks_itl->i_lu_number.value.ui64 = itl->itl_lun;
-
-	/* Now create the I/O kstats */
-	(void) snprintf(ks_nm, KSTAT_STRLEN, "itl_tasks_%s",  ks_itl_id);
-	if ((itl->itl_kstat_taskq = kstat_create(STMF_MODULE_NAME, 0,
-	    ks_nm, "io", KSTAT_TYPE_IO, 1, 0)) == NULL) {
-		goto itl_kstat_cleanup;
-	}
-
-	(void) snprintf(ks_nm, KSTAT_STRLEN, "itl_lu_%s",  ks_itl_id);
-	if ((itl->itl_kstat_lu_xfer = kstat_create(STMF_MODULE_NAME, 0,
-	    ks_nm, "io", KSTAT_TYPE_IO, 1, 0)) == NULL) {
-		goto itl_kstat_cleanup;
-	}
-
-	(void) snprintf(ks_nm, KSTAT_STRLEN, "itl_lport_%s",  ks_itl_id);
-	if ((itl->itl_kstat_lport_xfer = kstat_create(STMF_MODULE_NAME, 0,
-	    ks_nm, "io", KSTAT_TYPE_IO, 1, 0)) == NULL) {
-		goto itl_kstat_cleanup;
-	}
-
-	/* Install all the kstats */
-	kstat_install(itl->itl_kstat_info);
-	kstat_install(itl->itl_kstat_taskq);
-	kstat_install(itl->itl_kstat_lu_xfer);
-	kstat_install(itl->itl_kstat_lport_xfer);
-
-	/* Add new itl_kstat to stmf_itl_kstat_list */
-	if (stmf_itl_kstat_create(itl, ks_itl_nm, ss->ss_lport->lport_id,
-	    itl->itl_ilu->ilu_lu->lu_id) != NULL)
-		return (STMF_SUCCESS);
-
-itl_kstat_cleanup:
-	if (itl->itl_kstat_taskq)
-		kstat_delete(itl->itl_kstat_taskq);
-	if (itl->itl_kstat_lu_xfer)
-		kstat_delete(itl->itl_kstat_lu_xfer);
-	if (itl->itl_kstat_lport_xfer)
-		kstat_delete(itl->itl_kstat_lport_xfer);
-	if (itl->itl_kstat_info)
-		kstat_delete(itl->itl_kstat_info);
-	kmem_free(ks_itl, sizeof (*ks_itl));
-	kmem_free(itl->itl_kstat_strbuf, itl->itl_kstat_strbuflen);
-	cmn_err(CE_WARN, "STMF: kstat_create itl failed");
-	return (STMF_ALLOC_FAILURE);
-}
-
-static void
-stmf_teardown_itl_kstats(stmf_i_itl_kstat_t *ks)
-{
-	kstat_delete(ks->iitl_kstat_lport_xfer);
-	kstat_delete(ks->iitl_kstat_lu_xfer);
-	kstat_delete(ks->iitl_kstat_taskq);
-	kmem_free(ks->iitl_kstat_info->ks_data, sizeof (stmf_kstat_itl_info_t));
-	kstat_delete(ks->iitl_kstat_info);
-	kmem_free(ks->iitl_kstat_strbuf, ks->iitl_kstat_strbuflen);
-}
-
 void
 stmf_release_itl_handle(stmf_lu_t *lu, stmf_itl_data_t *itl)
 {
@@ -4060,9 +3739,6 @@
 		iss = (stmf_i_scsi_session_t *)ss->ss_stmf_private;
 	}
 
-	/*
-	 * Acquire stmf_lock for stmf_itl_kstat_lookup.
-	 */
 	mutex_enter(&stmf_state.stmf_lock);
 	rw_enter(iss->iss_lockp, RW_WRITER);
 	n = ((uint16_t)lun[1] | (((uint16_t)(lun[0] & 0x3F)) << 8));
@@ -4092,13 +3768,6 @@
 	itl->itl_lun = n;
 	itl->itl_handle = itl_handle;
 
-	if (stmf_setup_itl_kstats(itl) != STMF_SUCCESS) {
-		kmem_free(itl, sizeof (*itl));
-		rw_exit(iss->iss_lockp);
-		mutex_exit(&stmf_state.stmf_lock);
-		return (STMF_ALLOC_FAILURE);
-	}
-
 	mutex_enter(&ilu->ilu_task_lock);
 	itl->itl_next = ilu->ilu_itl_list;
 	ilu->ilu_itl_list = itl;
@@ -4128,10 +3797,6 @@
 	if (atomic_add_32_nv(&itl->itl_counter, -1))
 		return;
 
-	drv_usecwait(10);
-	if (itl->itl_counter)
-		return;
-
 	stmf_release_itl_handle(lu, itl);
 }
 
@@ -4202,66 +3867,6 @@
 }
 
 stmf_status_t
-stmf_deregister_itl_handle(stmf_lu_t *lu, uint8_t *lun,
-    stmf_scsi_session_t *ss, uint64_t session_id, void *itl_handle)
-{
-	stmf_i_scsi_session_t *iss;
-	stmf_itl_data_t *itl;
-	stmf_lun_map_ent_t *ent;
-	stmf_lun_map_t *lm;
-	int i;
-	uint16_t n;
-
-	if (ss == NULL) {
-		if (session_id == STMF_SESSION_ID_NONE)
-			return (STMF_INVALID_ARG);
-		iss = stmf_session_id_to_issptr(session_id, 1);
-		if (iss == NULL)
-			return (STMF_NOT_FOUND);
-	} else {
-		iss = (stmf_i_scsi_session_t *)ss->ss_stmf_private;
-		rw_enter(iss->iss_lockp, RW_WRITER);
-	}
-	lm = iss->iss_sm;
-	if (lm == NULL) {
-		rw_exit(iss->iss_lockp);
-		return (STMF_NOT_FOUND);
-	}
-
-	if (lun) {
-		n = ((uint16_t)lun[1] | (((uint16_t)(lun[0] & 0x3F)) << 8));
-		ent = (stmf_lun_map_ent_t *)
-		    stmf_get_ent_from_map(iss->iss_sm, n);
-	} else {
-		if (itl_handle == NULL) {
-			rw_exit(iss->iss_lockp);
-			return (STMF_INVALID_ARG);
-		}
-		ent = NULL;
-		for (i = 0; i < lm->lm_nentries; i++) {
-			if (lm->lm_plus[i] == NULL)
-				continue;
-			ent = (stmf_lun_map_ent_t *)lm->lm_plus[i];
-			if (ent->ent_itl_datap &&
-			    (ent->ent_itl_datap->itl_handle == itl_handle)) {
-				break;
-			}
-		}
-	}
-	if ((ent == NULL) || (ent->ent_lu != lu) ||
-	    (ent->ent_itl_datap == NULL)) {
-		rw_exit(iss->iss_lockp);
-		return (STMF_NOT_FOUND);
-	}
-	itl = ent->ent_itl_datap;
-	ent->ent_itl_datap = NULL;
-	rw_exit(iss->iss_lockp);
-	stmf_do_itl_dereg(lu, itl, STMF_ITL_REASON_DEREG_REQUEST);
-
-	return (STMF_SUCCESS);
-}
-
-stmf_status_t
 stmf_get_itl_handle(stmf_lu_t *lu, uint8_t *lun, stmf_scsi_session_t *ss,
     uint64_t session_id, void **itl_handle_retp)
 {
@@ -4447,6 +4052,8 @@
 		rw_exit(iss->iss_lockp);
 		return (NULL);
 	}
+	ASSERT(lu == dlun0 || (ilu->ilu_state != STMF_STATE_OFFLINING &&
+	    ilu->ilu_state != STMF_STATE_OFFLINE));
 	do {
 		if (ilu->ilu_free_tasks == NULL) {
 			new_task = 1;
@@ -4575,6 +4182,8 @@
 	itask->itask_lu_free_next = ilu->ilu_free_tasks;
 	ilu->ilu_free_tasks = itask;
 	ilu->ilu_ntasks_free++;
+	if (ilu->ilu_ntasks == ilu->ilu_ntasks_free)
+		cv_signal(&ilu->ilu_offline_pending_cv);
 	mutex_exit(&ilu->ilu_task_lock);
 	atomic_add_32(itask->itask_ilu_task_cntr, -1);
 }
@@ -6091,6 +5700,7 @@
 	struct ether_addr mac;
 	uint8_t *e = (uint8_t *)&mac;
 	int hid = (int)host_id;
+	uint16_t gen_number;
 
 	if (company_id == COMPANY_ID_NONE)
 		company_id = COMPANY_ID_SUN;
@@ -6100,7 +5710,7 @@
 
 	p = (uint8_t *)lu_id;
 
-	atomic_add_16(&stmf_lu_id_gen_number, 1);
+	gen_number = atomic_add_16_nv(&stmf_lu_id_gen_number, 1);
 
 	p[0] = 0xf1; p[1] = 3; p[2] = 0; p[3] = 0x10;
 	p[4] = ((company_id >> 20) & 0xf) | 0x60;
@@ -6121,8 +5731,8 @@
 	uniqtime32(&timestamp32);
 	*t = BE_32(*t);
 	bcopy(t, p+14, 4);
-	p[18] = (stmf_lu_id_gen_number >> 8) & 0xff;
-	p[19] = stmf_lu_id_gen_number & 0xff;
+	p[18] = (gen_number >> 8) & 0xff;
+	p[19] = gen_number & 0xff;
 
 	return (STMF_SUCCESS);
 }
@@ -7544,11 +7154,12 @@
 	if (itl == NULL || task->task_lu == dlun0)
 		return;
 	ilu = (stmf_i_lu_t *)task->task_lu->lu_stmf_private;
-	mutex_enter(ilu->ilu_kstat_io->ks_lock);
 	itask->itask_start_timestamp = gethrtime();
-	kstat_waitq_enter(KSTAT_IO_PTR(itl->itl_kstat_taskq));
-	stmf_update_kstat_lu_q(itask->itask_task, kstat_waitq_enter);
-	mutex_exit(ilu->ilu_kstat_io->ks_lock);
+	if (ilu->ilu_kstat_io != NULL) {
+		mutex_enter(ilu->ilu_kstat_io->ks_lock);
+		stmf_update_kstat_lu_q(itask->itask_task, kstat_waitq_enter);
+		mutex_exit(ilu->ilu_kstat_io->ks_lock);
+	}
 
 	stmf_update_kstat_lport_q(itask->itask_task, kstat_waitq_enter);
 }
@@ -7563,10 +7174,11 @@
 	if (itl == NULL || task->task_lu == dlun0)
 		return;
 	ilu = (stmf_i_lu_t *)task->task_lu->lu_stmf_private;
-	mutex_enter(ilu->ilu_kstat_io->ks_lock);
-	kstat_waitq_to_runq(KSTAT_IO_PTR(itl->itl_kstat_taskq));
-	stmf_update_kstat_lu_q(itask->itask_task, kstat_waitq_to_runq);
-	mutex_exit(ilu->ilu_kstat_io->ks_lock);
+	if (ilu->ilu_kstat_io != NULL) {
+		mutex_enter(ilu->ilu_kstat_io->ks_lock);
+		stmf_update_kstat_lu_q(itask->itask_task, kstat_waitq_to_runq);
+		mutex_exit(ilu->ilu_kstat_io->ks_lock);
+	}
 
 	stmf_update_kstat_lport_q(itask->itask_task, kstat_waitq_to_runq);
 }
@@ -7576,52 +7188,24 @@
 {
 	stmf_itl_data_t		*itl = itask->itask_itl_datap;
 	scsi_task_t		*task = itask->itask_task;
-	kstat_io_t		*kip;
-	hrtime_t		elapsed_time;
-	stmf_kstat_itl_info_t	*itli;
 	stmf_i_lu_t	*ilu;
 
+	itask->itask_done_timestamp = gethrtime();
+
 	if (itl == NULL || task->task_lu == dlun0)
 		return;
 	ilu = (stmf_i_lu_t *)task->task_lu->lu_stmf_private;
 
+	if (ilu->ilu_kstat_io == NULL)
+		return;
+
 	mutex_enter(ilu->ilu_kstat_io->ks_lock);
-	itli = (stmf_kstat_itl_info_t *)KSTAT_NAMED_PTR(itl->itl_kstat_info);
-	kip = KSTAT_IO_PTR(itl->itl_kstat_taskq);
 
-	itli->i_task_waitq_elapsed.value.ui64 += itask->itask_waitq_time;
-
-	itask->itask_done_timestamp = gethrtime();
-	elapsed_time =
-	    itask->itask_done_timestamp - itask->itask_start_timestamp;
-
-	if (task->task_flags & TF_READ_DATA) {
-		kip->reads++;
-		kip->nread += itask->itask_read_xfer;
-		itli->i_task_read_elapsed.value.ui64 += elapsed_time;
-		itli->i_lu_read_elapsed.value.ui64 +=
-		    itask->itask_lu_read_time;
-		itli->i_lport_read_elapsed.value.ui64 +=
-		    itask->itask_lport_read_time;
-	}
-
-	if (task->task_flags & TF_WRITE_DATA) {
-		kip->writes++;
-		kip->nwritten += itask->itask_write_xfer;
-		itli->i_task_write_elapsed.value.ui64 += elapsed_time;
-		itli->i_lu_write_elapsed.value.ui64 +=
-		    itask->itask_lu_write_time;
-		itli->i_lport_write_elapsed.value.ui64 +=
-		    itask->itask_lport_write_time;
-	}
-
 	if (itask->itask_flags & ITASK_KSTAT_IN_RUNQ) {
-		kstat_runq_exit(kip);
 		stmf_update_kstat_lu_q(task, kstat_runq_exit);
 		mutex_exit(ilu->ilu_kstat_io->ks_lock);
 		stmf_update_kstat_lport_q(task, kstat_runq_exit);
 	} else {
-		kstat_waitq_exit(kip);
 		stmf_update_kstat_lu_q(task, kstat_waitq_exit);
 		mutex_exit(ilu->ilu_kstat_io->ks_lock);
 		stmf_update_kstat_lport_q(task, kstat_waitq_exit);
@@ -7628,56 +7212,6 @@
 	}
 }
 
-void
-stmf_lu_xfer_start(scsi_task_t *task)
-{
-	stmf_i_scsi_task_t *itask = task->task_stmf_private;
-	stmf_itl_data_t	*itl = itask->itask_itl_datap;
-	stmf_i_lu_t	*ilu = (stmf_i_lu_t *)task->task_lu->lu_stmf_private;
-	kstat_io_t		*kip;
-
-	if (itl == NULL || task->task_lu == dlun0)
-		return;
-
-	kip = KSTAT_IO_PTR(itl->itl_kstat_lu_xfer);
-	mutex_enter(ilu->ilu_kstat_io->ks_lock);
-	kstat_runq_enter(kip);
-	mutex_exit(ilu->ilu_kstat_io->ks_lock);
-}
-
-void
-stmf_lu_xfer_done(scsi_task_t *task, boolean_t read, uint64_t xfer_bytes,
-    hrtime_t elapsed_time)
-{
-	stmf_i_scsi_task_t	*itask = task->task_stmf_private;
-	stmf_itl_data_t		*itl = itask->itask_itl_datap;
-	stmf_i_lu_t	*ilu = (stmf_i_lu_t *)task->task_lu->lu_stmf_private;
-	kstat_io_t		*kip;
-
-	if (itl == NULL || task->task_lu == dlun0)
-		return;
-
-	if (read) {
-		atomic_add_64((uint64_t *)&itask->itask_lu_read_time,
-		    elapsed_time);
-	} else {
-		atomic_add_64((uint64_t *)&itask->itask_lu_write_time,
-		    elapsed_time);
-	}
-
-	kip = KSTAT_IO_PTR(itl->itl_kstat_lu_xfer);
-	mutex_enter(ilu->ilu_kstat_io->ks_lock);
-	kstat_runq_exit(kip);
-	if (read) {
-		kip->reads++;
-		kip->nread += xfer_bytes;
-	} else {
-		kip->writes++;
-		kip->nwritten += xfer_bytes;
-	}
-	mutex_exit(ilu->ilu_kstat_io->ks_lock);
-}
-
 static void
 stmf_lport_xfer_start(stmf_i_scsi_task_t *itask, stmf_data_buf_t *dbuf)
 {
@@ -7696,9 +7230,6 @@
 stmf_lport_xfer_done(stmf_i_scsi_task_t *itask, stmf_data_buf_t *dbuf)
 {
 	stmf_itl_data_t		*itl = itask->itask_itl_datap;
-	scsi_task_t		*task;
-	stmf_i_local_port_t	*ilp;
-	kstat_io_t		*kip;
 	hrtime_t		elapsed_time;
 	uint64_t		xfer_size;
 
@@ -7705,8 +7236,6 @@
 	if (itl == NULL)
 		return;
 
-	task = (scsi_task_t *)itask->itask_task;
-	ilp = (stmf_i_local_port_t *)task->task_lport->lport_stmf_private;
 	xfer_size = (dbuf->db_xfer_status == STMF_SUCCESS) ?
 	    dbuf->db_data_size : 0;
 
@@ -7726,17 +7255,6 @@
 	DTRACE_PROBE3(scsi__xfer__end, scsi_task_t *, itask->itask_task,
 	    stmf_data_buf_t *, dbuf, hrtime_t, elapsed_time);
 
-	kip = KSTAT_IO_PTR(itl->itl_kstat_lport_xfer);
-	mutex_enter(ilp->ilport_kstat_io->ks_lock);
-	if (dbuf->db_flags & DB_DIRECTION_TO_RPORT) {
-		kip->reads++;
-		kip->nread += xfer_size;
-	} else {
-		kip->writes++;
-		kip->nwritten += xfer_size;
-	}
-	mutex_exit(ilp->ilport_kstat_io->ks_lock);
-
 	dbuf->db_xfer_start_timestamp = 0;
 }
 
@@ -7838,8 +7356,7 @@
 			    STMF_ABORTED);
 			lu = (stmf_lu_t *)req->svc_obj;
 			ilu = (stmf_i_lu_t *)lu->lu_stmf_private;
-			if (ilu->ilu_ntasks != ilu->ilu_ntasks_free)
-				break;
+			stmf_wait_ilu_tasks_finish(ilu);
 			lu->lu_ctl(lu, req->svc_cmd, &req->svc_info);
 			break;
 		default:
@@ -7847,6 +7364,7 @@
 			    req->svc_cmd);
 		}
 
+		kmem_free(req, req->svc_req_alloc_size);
 		mutex_enter(&stmf_state.stmf_lock);
 	}
 
@@ -7991,6 +7509,40 @@
 	stmf_state.stmf_svc_flags |= STMF_SVC_ACTIVE;
 }
 
+/*
+ * Waits for ongoing I/O tasks to finish on an LU in preparation for
+ * the LU's offlining. The LU should already be in an Offlining state
+ * (otherwise I/O to the LU might never end). There is an additional
+ * enforcement of this via a deadman timer check.
+ */
+static void
+stmf_wait_ilu_tasks_finish(stmf_i_lu_t *ilu)
+{
+	clock_t start, now, deadline;
+
+	start = now = ddi_get_lbolt();
+	deadline = start + drv_usectohz(stmf_io_deadman * 1000000llu);
+	mutex_enter(&ilu->ilu_task_lock);
+	while (ilu->ilu_ntasks != ilu->ilu_ntasks_free) {
+		(void) cv_timedwait(&ilu->ilu_offline_pending_cv,
+		    &ilu->ilu_task_lock, deadline);
+		now = ddi_get_lbolt();
+		if (now > deadline) {
+			if (stmf_io_deadman_enabled) {
+				cmn_err(CE_PANIC, "stmf_svc: I/O deadman hit "
+				    "on STMF_CMD_LU_OFFLINE after %d seconds",
+				    stmf_io_deadman);
+			} else {
+				/* keep on spinning */
+				deadline = now + drv_usectohz(stmf_io_deadman *
+				    1000000llu);
+			}
+		}
+	}
+	mutex_exit(&ilu->ilu_task_lock);
+	DTRACE_PROBE1(deadman__timeout__wait, clock_t, now - start);
+}
+
 void
 stmf_svc_queue(int cmd, void *obj, stmf_state_change_info_t *info)
 {
--- old/usr/src/uts/common/io/comstar/stmf/stmf_impl.h	Wed May  7 17:09:50 2014
+++ new/usr/src/uts/common/io/comstar/stmf/stmf_impl.h	Wed May  7 17:09:50 2014
@@ -20,6 +20,7 @@
  */
 /*
  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013 by Delphix. All rights reserved.
  */
 #ifndef _STMF_IMPL_H
 #define	_STMF_IMPL_H
@@ -97,6 +98,7 @@
 	kstat_t		*ilu_kstat_info;
 	kstat_t		*ilu_kstat_io;
 	kmutex_t	ilu_kstat_lock;
+	kcondvar_t	ilu_offline_pending_cv;
 
 	/* point to the luid entry in stmf_state.stmf_luid_list */
 	void		*ilu_luid;
@@ -164,19 +166,6 @@
 	avl_node_t		irport_ln;
 } stmf_i_remote_port_t;
 
-typedef struct stmf_i_itl_kstat {
-	char			iitl_kstat_nm[KSTAT_STRLEN];
-	char			iitl_kstat_lport[STMF_TGT_NAME_LEN];
-	char			iitl_kstat_guid[STMF_GUID_INPUT + 1];
-	char			*iitl_kstat_strbuf;
-	int			iitl_kstat_strbuflen;
-	kstat_t			*iitl_kstat_info;
-	kstat_t			*iitl_kstat_taskq;
-	kstat_t			*iitl_kstat_lu_xfer;
-	kstat_t			*iitl_kstat_lport_xfer;
-	avl_node_t		iitl_kstat_ln;
-} stmf_i_itl_kstat_t;
-
 /*
  * ilport flags
  */
@@ -325,12 +314,6 @@
 	uint8_t				itl_flags;
 	uint8_t				itl_hdlrm_reason;
 	uint16_t			itl_lun;
-	char				*itl_kstat_strbuf;
-	int				itl_kstat_strbuflen;
-	kstat_t				*itl_kstat_info;
-	kstat_t				*itl_kstat_taskq;
-	kstat_t				*itl_kstat_lu_xfer;
-	kstat_t				*itl_kstat_lport_xfer;
 	void				*itl_handle;
 	struct stmf_i_lu		*itl_ilu;
 	struct stmf_i_scsi_session	*itl_session;
--- old/usr/src/uts/common/io/comstar/stmf/stmf_state.h	Wed May  7 17:09:50 2014
+++ new/usr/src/uts/common/io/comstar/stmf/stmf_state.h	Wed May  7 17:09:50 2014
@@ -23,6 +23,7 @@
  */
 /*
  * Copyright 2011, Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 2013 by Delphix. All rights reserved.
  */
 #ifndef	_STMF_STATE_H
 #define	_STMF_STATE_H
@@ -42,7 +43,6 @@
 	id_space_t		*stmf_ilport_inst_space;
 	avl_tree_t		stmf_irportlist;
 	id_space_t		*stmf_irport_inst_space;
-	avl_tree_t		stmf_itl_kstat_list;
 	int			stmf_nlps;
 	int			stmf_npps;
 	int			stmf_nlus;
--- old/usr/src/uts/common/io/idm/idm_conn_sm.c	Wed May  7 17:09:50 2014
+++ new/usr/src/uts/common/io/idm/idm_conn_sm.c	Wed May  7 17:09:50 2014
@@ -21,6 +21,7 @@
 
 /*
  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013 by Delphix. All rights reserved.
  */
 
 #include <sys/cpuvar.h>
@@ -609,6 +610,7 @@
 		 * connections are shut down by a CE_LOGOUT_SESSION_SUCCESS
 		 * event sent from the session to the IDM layer.
 		 */
+		(void) untimeout(ic->ic_state_timeout);
 		if (IDM_CONN_ISTGT(ic)) {
 			ic->ic_transport_ops->it_tgt_conn_disconnect(ic);
 		} else {
--- old/usr/src/uts/common/io/idm/idm_so.c	Wed May  7 17:09:50 2014
+++ new/usr/src/uts/common/io/idm/idm_so.c	Wed May  7 17:09:50 2014
@@ -1260,10 +1260,15 @@
 		    (struct sockaddr *)&t_addr, &t_addrlen,
 		    &new_so, CRED())) != 0) {
 			mutex_enter(&svc->is_mutex);
-			if (rc == ECONNABORTED)
-				continue;
-			/* Connection problem */
-			break;
+			if (rc != ECONNABORTED && rc != EINTR) {
+				IDM_SVC_LOG(CE_NOTE, "idm_so_svc_port_watcher:"
+				    " ksocket_accept failed %d", rc);
+			}
+			/*
+			 * Unclean shutdown of this thread is not handled
+			 * wait for !is_thread_running.
+			 */
+			continue;
 		}
 		/*
 		 * Turn off SO_MAC_EXEMPT so future sobinds succeed
--- old/usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas.c	Wed May  7 17:09:50 2014
+++ new/usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas.c	Wed May  7 17:09:50 2014
@@ -22,6 +22,7 @@
 /*
  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
  * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 2014, Joyent, Inc. All rights reserved.
  * Copyright 2014 OmniTI Computer Consulting, Inc. All rights reserved.
  */
 
@@ -69,6 +70,7 @@
 #include <sys/pci.h>
 #include <sys/file.h>
 #include <sys/policy.h>
+#include <sys/model.h>
 #include <sys/sysevent.h>
 #include <sys/sysevent/eventdefs.h>
 #include <sys/sysevent/dr.h>
@@ -95,6 +97,7 @@
 #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/raidioctl.h>
 
 #include <sys/fs/dv_node.h>	/* devfs_clean */
@@ -334,12 +337,12 @@
     int *lun);
 static int mptsas_parse_smp_name(char *name, uint64_t *wwn);
 
-static mptsas_target_t *mptsas_phy_to_tgt(mptsas_t *mpt, int phymask,
-    uint8_t phy);
-static mptsas_target_t *mptsas_wwid_to_ptgt(mptsas_t *mpt, int phymask,
-    uint64_t wwid);
-static mptsas_smp_t *mptsas_wwid_to_psmp(mptsas_t *mpt, int phymask,
-    uint64_t wwid);
+static mptsas_target_t *mptsas_phy_to_tgt(mptsas_t *mpt,
+    mptsas_phymask_t phymask, uint8_t phy);
+static mptsas_target_t *mptsas_wwid_to_ptgt(mptsas_t *mpt,
+    mptsas_phymask_t phymask, uint64_t wwid);
+static mptsas_smp_t *mptsas_wwid_to_psmp(mptsas_t *mpt,
+    mptsas_phymask_t phymask, uint64_t wwid);
 
 static int mptsas_inquiry(mptsas_t *mpt, mptsas_target_t *ptgt, int lun,
     uchar_t page, unsigned char *buf, int len, int *rlen, uchar_t evpd);
@@ -354,8 +357,7 @@
     mptsas_phymask_t *phymask);
 static mptsas_target_t *mptsas_addr_to_ptgt(mptsas_t *mpt, char *addr,
     mptsas_phymask_t phymask);
-static int mptsas_set_led_status(mptsas_t *mpt, mptsas_target_t *ptgt,
-    uint32_t slotstatus);
+static int mptsas_flush_led_status(mptsas_t *mpt, mptsas_target_t *ptgt);
 
 
 /*
@@ -406,23 +408,9 @@
 static int mptsas_reg_access(mptsas_t *mpt, mptsas_reg_access_t *data,
     int mode);
 
-static void mptsas_hash_init(mptsas_hash_table_t *hashtab);
-static void mptsas_hash_uninit(mptsas_hash_table_t *hashtab, size_t datalen);
-static void mptsas_hash_add(mptsas_hash_table_t *hashtab, void *data);
-static void * mptsas_hash_rem(mptsas_hash_table_t *hashtab, uint64_t key1,
-    mptsas_phymask_t key2);
-static void * mptsas_hash_search(mptsas_hash_table_t *hashtab, uint64_t key1,
-    mptsas_phymask_t key2);
-static void * mptsas_hash_traverse(mptsas_hash_table_t *hashtab, int pos);
-
-mptsas_target_t *mptsas_tgt_alloc(mptsas_hash_table_t *, uint16_t, uint64_t,
+mptsas_target_t *mptsas_tgt_alloc(mptsas_t *, uint16_t, uint64_t,
     uint32_t, mptsas_phymask_t, uint8_t);
-static mptsas_smp_t *mptsas_smp_alloc(mptsas_hash_table_t *hashtab,
-    mptsas_smp_t *data);
-static void mptsas_smp_free(mptsas_hash_table_t *hashtab, uint64_t wwid,
-    mptsas_phymask_t phymask);
-static void mptsas_tgt_free(mptsas_hash_table_t *, uint64_t, mptsas_phymask_t);
-static void * mptsas_search_by_devhdl(mptsas_hash_table_t *, uint16_t);
+static mptsas_smp_t *mptsas_smp_alloc(mptsas_t *, mptsas_smp_t *);
 static int mptsas_online_smp(dev_info_t *pdip, mptsas_smp_t *smp_node,
     dev_info_t **smp_dip);
 
@@ -694,8 +682,103 @@
 	return (mod_info(&modlinkage, modinfop));
 }
 
+static int
+mptsas_target_eval_devhdl(const void *op, void *arg)
+{
+	uint16_t dh = *(uint16_t *)arg;
+	const mptsas_target_t *tp = op;
 
+	return ((int)tp->m_devhdl - (int)dh);
+}
+
 static int
+mptsas_target_eval_slot(const void *op, void *arg)
+{
+	mptsas_led_control_t *lcp = arg;
+	const mptsas_target_t *tp = op;
+
+	if (tp->m_enclosure != lcp->Enclosure)
+		return ((int)tp->m_enclosure - (int)lcp->Enclosure);
+
+	return ((int)tp->m_slot_num - (int)lcp->Slot);
+}
+
+static int
+mptsas_target_eval_nowwn(const void *op, void *arg)
+{
+	uint8_t phy = *(uint8_t *)arg;
+	const mptsas_target_t *tp = op;
+
+	if (tp->m_addr.mta_wwn != 0)
+		return (-1);
+
+	return ((int)tp->m_phynum - (int)phy);
+}
+
+static int
+mptsas_smp_eval_devhdl(const void *op, void *arg)
+{
+	uint16_t dh = *(uint16_t *)arg;
+	const mptsas_smp_t *sp = op;
+
+	return ((int)sp->m_devhdl - (int)dh);
+}
+
+static uint64_t
+mptsas_target_addr_hash(const void *tp)
+{
+	const mptsas_target_addr_t *tap = tp;
+
+	return ((tap->mta_wwn & 0xffffffffffffULL) |
+	    ((uint64_t)tap->mta_phymask << 48));
+}
+
+static int
+mptsas_target_addr_cmp(const void *a, const void *b)
+{
+	const mptsas_target_addr_t *aap = a;
+	const mptsas_target_addr_t *bap = b;
+
+	if (aap->mta_wwn < bap->mta_wwn)
+		return (-1);
+	if (aap->mta_wwn > bap->mta_wwn)
+		return (1);
+	return ((int)bap->mta_phymask - (int)aap->mta_phymask);
+}
+
+static void
+mptsas_target_free(void *op)
+{
+	kmem_free(op, sizeof (mptsas_target_t));
+}
+
+static void
+mptsas_smp_free(void *op)
+{
+	kmem_free(op, sizeof (mptsas_smp_t));
+}
+
+static void
+mptsas_destroy_hashes(mptsas_t *mpt)
+{
+	mptsas_target_t *tp;
+	mptsas_smp_t *sp;
+
+	for (tp = refhash_first(mpt->m_targets); tp != NULL;
+	    tp = refhash_next(mpt->m_targets, tp)) {
+		refhash_remove(mpt->m_targets, tp);
+	}
+	for (sp = refhash_first(mpt->m_smp_targets); sp != NULL;
+	    sp = refhash_next(mpt->m_smp_targets, sp)) {
+		refhash_remove(mpt->m_smp_targets, sp);
+	}
+	refhash_destroy(mpt->m_targets);
+	refhash_destroy(mpt->m_smp_targets);
+	mpt->m_targets = NULL;
+	mpt->m_smp_targets = NULL;
+}
+
+static int
 mptsas_iport_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
 {
 	dev_info_t		*pdip;
@@ -871,8 +954,8 @@
 		    "prop update failed");
 		return (DDI_FAILURE);
 	}
-	mptsas_smhba_set_phy_props(mpt,
-	    iport, dip, numphys, &attached_devhdl);
+	mptsas_smhba_set_all_phy_props(mpt, dip, numphys, phy_mask,
+	    &attached_devhdl);
 
 	mutex_enter(&mpt->m_mutex);
 	page_address = (MPI2_SAS_DEVICE_PGAD_FORM_HANDLE &
@@ -1403,11 +1486,12 @@
 			mptsas_hba_teardown(mpt);
 		}
 
+		if (mpt->m_targets)
+			refhash_destroy(mpt->m_targets);
+		if (mpt->m_smp_targets)
+			refhash_destroy(mpt->m_smp_targets);
+
 		if (mpt->m_active) {
-			mptsas_hash_uninit(&mpt->m_active->m_smptbl,
-			    sizeof (mptsas_smp_t));
-			mptsas_hash_uninit(&mpt->m_active->m_tgttbl,
-			    sizeof (mptsas_target_t));
 			mptsas_free_active_slots(mpt);
 		}
 		if (intr_added) {
@@ -1840,12 +1924,12 @@
 	 */
 	mptsas_destroy_phy_stats(mpt);
 
+	mptsas_destroy_hashes(mpt);
+
 	/*
 	 * Delete nt_active.
 	 */
 	mutex_enter(&mpt->m_mutex);
-	mptsas_hash_uninit(&mpt->m_active->m_tgttbl, sizeof (mptsas_target_t));
-	mptsas_hash_uninit(&mpt->m_active->m_smptbl, sizeof (mptsas_smp_t));
 	mptsas_free_active_slots(mpt);
 	mutex_exit(&mpt->m_mutex);
 
@@ -2106,7 +2190,11 @@
 	/*
 	 * Initialize smp hash table
 	 */
-	mptsas_hash_init(&mpt->m_active->m_smptbl);
+	mpt->m_smp_targets = refhash_create(MPTSAS_SMP_BUCKET_COUNT,
+	    mptsas_target_addr_hash, mptsas_target_addr_cmp,
+	    mptsas_smp_free, sizeof (mptsas_smp_t),
+	    offsetof(mptsas_smp_t, m_link), offsetof(mptsas_smp_t, m_addr),
+	    KM_SLEEP);
 	mpt->m_smp_devhdl = 0xFFFF;
 
 	return (TRUE);
@@ -2622,13 +2710,10 @@
 static void
 mptsas_alloc_reply_args(mptsas_t *mpt)
 {
-	if (mpt->m_replyh_args != NULL) {
-		kmem_free(mpt->m_replyh_args, sizeof (m_replyh_arg_t)
-		    * mpt->m_max_replies);
-		mpt->m_replyh_args = NULL;
+	if (mpt->m_replyh_args == NULL) {
+		mpt->m_replyh_args = kmem_zalloc(sizeof (m_replyh_arg_t) *
+		    mpt->m_max_replies, KM_SLEEP);
 	}
-	mpt->m_replyh_args = kmem_zalloc(sizeof (m_replyh_arg_t) *
-	    mpt->m_max_replies, KM_SLEEP);
 }
 
 static int
@@ -2752,8 +2837,9 @@
 	mptsas_tgt_private_t	*tgt_private = NULL;
 	mptsas_target_t		*ptgt = NULL;
 	char			*psas_wwn = NULL;
-	int			phymask = 0;
+	mptsas_phymask_t	phymask = 0;
 	uint64_t		sas_wwn = 0;
+	mptsas_target_addr_t	addr;
 	mpt = SDEV2MPT(sd);
 
 	ASSERT(scsi_hba_iport_unit_address(hba_dip) != 0);
@@ -2769,7 +2855,7 @@
 	/*
 	 * phymask is 0 means the virtual port for RAID
 	 */
-	phymask = ddi_prop_get_int(DDI_DEV_T_ANY, hba_dip, 0,
+	phymask = (mptsas_phymask_t)ddi_prop_get_int(DDI_DEV_T_ANY, hba_dip, 0,
 	    "phymask", 0);
 	if (mdi_component_is_client(tgt_dip, NULL) == MDI_SUCCESS) {
 		if ((pip = (void *)(sd->sd_private)) == NULL) {
@@ -2807,9 +2893,12 @@
 			sas_wwn = 0;
 		}
 	}
+
 	ASSERT((sas_wwn != 0) || (phymask != 0));
+	addr.mta_wwn = sas_wwn;
+	addr.mta_phymask = phymask;
 	mutex_enter(&mpt->m_mutex);
-	ptgt = mptsas_hash_search(&mpt->m_active->m_tgttbl, sas_wwn, phymask);
+	ptgt = refhash_lookup(mpt->m_targets, &addr);
 	mutex_exit(&mpt->m_mutex);
 	if (ptgt == NULL) {
 		mptsas_log(mpt, CE_WARN, "!tgt_init: target doesn't exist or "
@@ -3240,79 +3329,63 @@
 int
 mptsas_save_cmd(mptsas_t *mpt, mptsas_cmd_t *cmd)
 {
-	mptsas_slots_t	*slots;
-	int		slot;
-	mptsas_target_t	*ptgt = cmd->cmd_tgt_addr;
+	mptsas_slots_t *slots = mpt->m_active;
+	uint_t slot, start_rotor;
+	mptsas_target_t *ptgt = cmd->cmd_tgt_addr;
 
-	ASSERT(mutex_owned(&mpt->m_mutex));
-	slots = mpt->m_active;
+	ASSERT(MUTEX_HELD(&mpt->m_mutex));
 
 	/*
 	 * Account for reserved TM request slot and reserved SMID of 0.
 	 */
-	ASSERT(slots->m_n_slots == (mpt->m_max_requests - 2));
+	ASSERT(slots->m_n_normal == (mpt->m_max_requests - 2));
 
 	/*
-	 * m_tags is equivalent to the SMID when sending requests.  Since the
-	 * SMID cannot be 0, start out at one if rolling over past the size
-	 * of the request queue depth.  Also, don't use the last SMID, which is
-	 * reserved for TM requests.
+	 * Find the next available slot, beginning at m_rotor.  If no slot is
+	 * available, we'll return FALSE to indicate that.  This mechanism
+	 * considers only the normal slots, not the reserved slot 0 nor the
+	 * task management slot m_n_normal + 1.  The rotor is left to point to
+	 * the normal slot after the one we select, unless we select the last
+	 * normal slot in which case it returns to slot 1.
 	 */
-	slot = (slots->m_tags)++;
-	if (slots->m_tags > slots->m_n_slots) {
-		slots->m_tags = 1;
-	}
+	start_rotor = slots->m_rotor;
+	do {
+		slot = slots->m_rotor++;
+		if (slots->m_rotor > slots->m_n_normal)
+			slots->m_rotor = 1;
 
-alloc_tag:
-	/* Validate tag, should never fail. */
-	if (slots->m_slot[slot] == NULL) {
-		/*
-		 * Make sure SMID is not using reserved value of 0
-		 * and the TM request slot.
-		 */
-		ASSERT((slot > 0) && (slot <= slots->m_n_slots));
-		cmd->cmd_slot = slot;
-		slots->m_slot[slot] = cmd;
-		mpt->m_ncmds++;
+		if (slots->m_rotor == start_rotor)
+			break;
+	} while (slots->m_slot[slot] != NULL);
 
-		/*
-		 * only increment per target ncmds if this is not a
-		 * command that has no target associated with it (i.e. a
-		 * event acknoledgment)
-		 */
-		if ((cmd->cmd_flags & CFLAG_CMDIOC) == 0) {
-			ptgt->m_t_ncmds++;
-		}
-		cmd->cmd_active_timeout = cmd->cmd_pkt->pkt_time;
+	if (slots->m_slot[slot] != NULL)
+		return (FALSE);
 
-		/*
-		 * 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.
-		 */
-		if (cmd->cmd_active_timeout <= mptsas_scsi_watchdog_tick) {
-			cmd->cmd_active_timeout += mptsas_scsi_watchdog_tick;
-		}
-		return (TRUE);
-	} else {
-		int i;
+	ASSERT(slot != 0 && slot <= slots->m_n_normal);
 
-		/*
-		 * If slot in use, scan until a free one is found. Don't use 0
-		 * or final slot, which is reserved for TM requests.
-		 */
-		for (i = 0; i < slots->m_n_slots; i++) {
-			slot = slots->m_tags;
-			if (++(slots->m_tags) > slots->m_n_slots) {
-				slots->m_tags = 1;
-			}
-			if (slots->m_slot[slot] == NULL) {
-				NDBG22(("found free slot %d", slot));
-				goto alloc_tag;
-			}
-		}
+	cmd->cmd_slot = slot;
+	slots->m_slot[slot] = cmd;
+	mpt->m_ncmds++;
+
+	/*
+	 * only increment per target ncmds if this is not a
+	 * command that has no target associated with it (i.e. a
+	 * event acknoledgment)
+	 */
+	if ((cmd->cmd_flags & CFLAG_CMDIOC) == 0) {
+		ptgt->m_t_ncmds++;
 	}
-	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.
+	 */
+	if (cmd->cmd_active_timeout <= mptsas_scsi_watchdog_tick) {
+		cmd->cmd_active_timeout += mptsas_scsi_watchdog_tick;
+	}
+	return (TRUE);
 }
 
 /*
@@ -4653,7 +4726,7 @@
 	 * check on the SMID.  The final slot is used for TM requests, which
 	 * would not come into this reply handler.
 	 */
-	if ((SMID == 0) || (SMID > slots->m_n_slots)) {
+	if ((SMID == 0) || (SMID > slots->m_n_normal)) {
 		mptsas_log(mpt, CE_WARN, "?Received invalid SMID of %d\n",
 		    SMID);
 		ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
@@ -4756,7 +4829,7 @@
 		 * This could be a TM reply, which use the last allocated SMID,
 		 * so allow for that.
 		 */
-		if ((SMID == 0) || (SMID > (slots->m_n_slots + 1))) {
+		if ((SMID == 0) || (SMID > (slots->m_n_normal + 1))) {
 			mptsas_log(mpt, CE_WARN, "?Received invalid SMID of "
 			    "%d\n", SMID);
 			ddi_fm_service_impact(mpt->m_dip,
@@ -4830,6 +4903,12 @@
 			 */
 			NDBG20(("send mptsas_handle_event_sync success"));
 		}
+
+		if (mpt->m_in_reset) {
+			NDBG20(("dropping event received during reset"));
+			return;
+		}
+
 		if ((ddi_taskq_dispatch(mpt->m_event_taskq, mptsas_handle_event,
 		    (void *)args, DDI_NOSLEEP)) != DDI_SUCCESS) {
 			mptsas_log(mpt, CE_WARN, "No memory available"
@@ -5067,7 +5146,7 @@
 			}
 			topo_node->mpt = mpt;
 			topo_node->event = MPTSAS_DR_EVENT_RECONFIG_TARGET;
-			topo_node->un.phymask = ptgt->m_phymask;
+			topo_node->un.phymask = ptgt->m_addr.mta_phymask;
 			topo_node->devhdl = ptgt->m_devhdl;
 			topo_node->object = (void *)ptgt;
 			topo_node->flags = MPTSAS_TOPO_FLAG_LUN_ASSOCIATED;
@@ -5133,13 +5212,9 @@
 			/*
 			 * set throttles to drain
 			 */
-			ptgt = (mptsas_target_t *)mptsas_hash_traverse(
-			    &mpt->m_active->m_tgttbl, MPTSAS_HASH_FIRST);
-			while (ptgt != NULL) {
+			for (ptgt = refhash_first(mpt->m_targets); ptgt != NULL;
+			    ptgt = refhash_next(mpt->m_targets, ptgt)) {
 				mptsas_set_throttle(mpt, ptgt, DRAIN_THROTTLE);
-
-				ptgt = (mptsas_target_t *)mptsas_hash_traverse(
-				    &mpt->m_active->m_tgttbl, MPTSAS_HASH_NEXT);
 			}
 
 			/*
@@ -5767,8 +5842,14 @@
 handle_topo_change:
 
 		mutex_enter(&mpt->m_mutex);
-
-		mptsas_handle_topo_change(topo_node, parent);
+		/*
+		 * 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);
@@ -5824,8 +5905,8 @@
 			 * Get latest RAID info.
 			 */
 			(void) mptsas_get_raid_info(mpt);
-			ptgt = mptsas_search_by_devhdl(
-			    &mpt->m_active->m_tgttbl, topo_node->devhdl);
+			ptgt = refhash_linear_search(mpt->m_targets,
+			    mptsas_target_eval_devhdl, &topo_node->devhdl);
 			if (ptgt == NULL)
 				break;
 		} else {
@@ -5874,7 +5955,7 @@
 		flags = topo_node->flags;
 
 		if (flags == MPTSAS_TOPO_FLAG_RAID_PHYSDRV_ASSOCIATED) {
-			phymask = ptgt->m_phymask;
+			phymask = ptgt->m_addr.mta_phymask;
 			phy_mask_name = kmem_zalloc(MPTSAS_MAX_PHYS, KM_SLEEP);
 			(void) sprintf(phy_mask_name, "%x", phymask);
 			parent = scsi_hba_iport_find(mpt->m_dip,
@@ -5913,7 +5994,7 @@
 				bzero(attached_wwnstr,
 				    sizeof (attached_wwnstr));
 				(void) sprintf(attached_wwnstr, "w%016"PRIx64,
-				    ptgt->m_sas_wwn);
+				    ptgt->m_addr.mta_wwn);
 				if (ddi_prop_update_string(DDI_DEV_T_NONE,
 				    parent,
 				    SCSI_ADDR_PROP_ATTACHED_PORT,
@@ -5947,9 +6028,14 @@
 					return;
 				}
 				mutex_exit(&mpt->m_mutex);
-				mptsas_smhba_set_phy_props(mpt,
-				    ddi_get_name_addr(parent), parent,
-				    1, &attached_devhdl);
+
+				/*
+				 * topo_node->un.physport is really the PHY#
+				 * for direct attached devices
+				 */
+				mptsas_smhba_set_one_phy_props(mpt, parent,
+				    topo_node->un.physport, &attached_devhdl);
+
 				if (ddi_prop_update_int(DDI_DEV_T_NONE, parent,
 				    MPTSAS_VIRTUAL_PORT, 0) !=
 				    DDI_PROP_SUCCESS) {
@@ -5966,18 +6052,18 @@
 
 		NDBG20(("mptsas%d handle_topo_change to online devhdl:%x, "
 		    "phymask:%x.", mpt->m_instance, ptgt->m_devhdl,
-		    ptgt->m_phymask));
+		    ptgt->m_addr.mta_phymask));
 		break;
 	}
 	case MPTSAS_DR_EVENT_OFFLINE_TARGET:
 	{
-		mptsas_hash_table_t *tgttbl = &mpt->m_active->m_tgttbl;
 		devhdl = topo_node->devhdl;
-		ptgt = mptsas_search_by_devhdl(tgttbl, devhdl);
+		ptgt = refhash_linear_search(mpt->m_targets,
+		    mptsas_target_eval_devhdl, &devhdl);
 		if (ptgt == NULL)
 			break;
 
-		sas_wwn = ptgt->m_sas_wwn;
+		sas_wwn = ptgt->m_addr.mta_wwn;
 		phy = ptgt->m_phynum;
 
 		addr = kmem_zalloc(SCSI_MAXNAMELEN, KM_SLEEP);
@@ -6005,8 +6091,8 @@
 		if (rval) {
 			NDBG20(("mptsas%d handle_topo_change to reset target "
 			    "before offline devhdl:%x, phymask:%x, rval:%x",
-			    mpt->m_instance, ptgt->m_devhdl, ptgt->m_phymask,
-			    rval));
+			    mpt->m_instance, ptgt->m_devhdl,
+			    ptgt->m_addr.mta_phymask, rval));
 		}
 
 		mutex_exit(&mpt->m_mutex);
@@ -6018,7 +6104,7 @@
 		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_phymask, rval));
+		    ptgt->m_devhdl, ptgt->m_addr.mta_phymask, rval));
 
 		kmem_free(addr, SCSI_MAXNAMELEN);
 
@@ -6058,13 +6144,10 @@
 		}
 
 		mutex_enter(&mpt->m_mutex);
-		if (mptsas_set_led_status(mpt, ptgt, 0) != DDI_SUCCESS) {
-			NDBG14(("mptsas: clear LED for tgt %x failed",
-			    ptgt->m_slot_num));
-		}
+		ptgt->m_led_status = 0;
+		(void) mptsas_flush_led_status(mpt, ptgt);
 		if (rval == DDI_SUCCESS) {
-			mptsas_tgt_free(&mpt->m_active->m_tgttbl,
-			    ptgt->m_sas_wwn, ptgt->m_phymask);
+			refhash_remove(mpt->m_targets, ptgt);
 			ptgt = NULL;
 		} else {
 			/*
@@ -6121,7 +6204,6 @@
 	{
 		mptsas_smp_t smp;
 		dev_info_t *smpdip;
-		mptsas_hash_table_t *smptbl = &mpt->m_active->m_smptbl;
 
 		devhdl = topo_node->devhdl;
 
@@ -6134,7 +6216,7 @@
 			return;
 		}
 
-		psmp = mptsas_smp_alloc(smptbl, &smp);
+		psmp = mptsas_smp_alloc(mpt, &smp);
 		if (psmp == NULL) {
 			return;
 		}
@@ -6149,11 +6231,11 @@
 	}
 	case MPTSAS_DR_EVENT_OFFLINE_SMP:
 	{
-		mptsas_hash_table_t *smptbl = &mpt->m_active->m_smptbl;
 		devhdl = topo_node->devhdl;
 		uint32_t dev_info;
 
-		psmp = mptsas_search_by_devhdl(smptbl, devhdl);
+		psmp = refhash_linear_search(mpt->m_smp_targets,
+		    mptsas_smp_eval_devhdl, &devhdl);
 		if (psmp == NULL)
 			break;
 		/*
@@ -6209,8 +6291,7 @@
 		NDBG20(("mptsas%d handle_topo_change to remove devhdl:%x, "
 		    "rval:%x", mpt->m_instance, psmp->m_devhdl, rval));
 		if (rval == DDI_SUCCESS) {
-			mptsas_smp_free(smptbl, psmp->m_sasaddr,
-			    psmp->m_phymask);
+			refhash_remove(mpt->m_smp_targets, psmp);
 		} else {
 			psmp->m_devhdl = MPTSAS_INVALID_DEVHDL;
 		}
@@ -6369,15 +6450,11 @@
 		mptsas_topo_change_list_t	*topo_node = NULL;
 		mptsas_target_t			*ptgt;
 		mptsas_smp_t			*psmp;
-		mptsas_hash_table_t		*tgttbl, *smptbl;
 		uint8_t				flags = 0, exp_flag;
 		smhba_info_t			*pSmhba = NULL;
 
 		NDBG20(("mptsas_handle_event_sync: SAS topology change"));
 
-		tgttbl = &mpt->m_active->m_tgttbl;
-		smptbl = &mpt->m_active->m_smptbl;
-
 		sas_topo_change_list = (pMpi2EventDataSasTopologyChangeList_t)
 		    eventreply->EventData;
 
@@ -6423,8 +6500,8 @@
 			case MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING:
 				(void) sprintf(string, " not responding, "
 				    "removed");
-				psmp = mptsas_search_by_devhdl(smptbl,
-				    expd_handle);
+				psmp = refhash_linear_search(mpt->m_smp_targets,
+				    mptsas_smp_eval_devhdl, &expd_handle);
 				if (psmp == NULL)
 					break;
 
@@ -6432,7 +6509,8 @@
 				    sizeof (mptsas_topo_change_list_t),
 				    KM_SLEEP);
 				topo_node->mpt = mpt;
-				topo_node->un.phymask = psmp->m_phymask;
+				topo_node->un.phymask =
+				    psmp->m_addr.mta_phymask;
 				topo_node->event = MPTSAS_DR_EVENT_OFFLINE_SMP;
 				topo_node->devhdl = expd_handle;
 				topo_node->flags = flags;
@@ -6583,8 +6661,8 @@
 				 * Before the device is really offline from
 				 * from system.
 				 */
-				ptgt = mptsas_search_by_devhdl(tgttbl,
-				    dev_handle);
+				ptgt = refhash_linear_search(mpt->m_targets,
+				    mptsas_target_eval_devhdl, &dev_handle);
 				/*
 				 * If ptgt is NULL here, it means that the
 				 * DevHandle is not in the hash table.  This is
@@ -6636,7 +6714,8 @@
 				    sizeof (mptsas_topo_change_list_t),
 				    KM_SLEEP);
 				topo_node->mpt = mpt;
-				topo_node->un.phymask = ptgt->m_phymask;
+				topo_node->un.phymask =
+				    ptgt->m_addr.mta_phymask;
 				topo_node->event =
 				    MPTSAS_DR_EVENT_OFFLINE_TARGET;
 				topo_node->devhdl = dev_handle;
@@ -6796,7 +6875,6 @@
 		mptsas_topo_change_list_t		*topo_tail = NULL;
 		mptsas_topo_change_list_t		*topo_node = NULL;
 		mptsas_target_t				*ptgt;
-		mptsas_hash_table_t			*tgttbl;
 		uint8_t					num_entries, i, reason;
 		uint16_t				volhandle, diskhandle;
 
@@ -6805,8 +6883,6 @@
 		num_entries = ddi_get8(mpt->m_acc_reply_frame_hdl,
 		    &irChangeList->NumElements);
 
-		tgttbl = &mpt->m_active->m_tgttbl;
-
 		NDBG20(("mptsas%d IR_CONFIGURATION_CHANGE_LIST event received",
 		    mpt->m_instance));
 
@@ -6850,8 +6926,8 @@
 			{
 				NDBG20(("mptsas %d volume deleted\n",
 				    mpt->m_instance));
-				ptgt = mptsas_search_by_devhdl(tgttbl,
-				    volhandle);
+				ptgt = refhash_linear_search(mpt->m_targets,
+				    mptsas_target_eval_devhdl, &volhandle);
 				if (ptgt == NULL)
 					break;
 
@@ -6871,7 +6947,8 @@
 				    sizeof (mptsas_topo_change_list_t),
 				    KM_SLEEP);
 				topo_node->mpt = mpt;
-				topo_node->un.phymask = ptgt->m_phymask;
+				topo_node->un.phymask =
+				    ptgt->m_addr.mta_phymask;
 				topo_node->event =
 				    MPTSAS_DR_EVENT_OFFLINE_TARGET;
 				topo_node->devhdl = volhandle;
@@ -6889,8 +6966,8 @@
 			case MPI2_EVENT_IR_CHANGE_RC_PD_CREATED:
 			case MPI2_EVENT_IR_CHANGE_RC_HIDE:
 			{
-				ptgt = mptsas_search_by_devhdl(tgttbl,
-				    diskhandle);
+				ptgt = refhash_linear_search(mpt->m_targets,
+				    mptsas_target_eval_devhdl, &diskhandle);
 				if (ptgt == NULL)
 					break;
 
@@ -6905,7 +6982,8 @@
 				    sizeof (mptsas_topo_change_list_t),
 				    KM_SLEEP);
 				topo_node->mpt = mpt;
-				topo_node->un.phymask = ptgt->m_phymask;
+				topo_node->un.phymask =
+				    ptgt->m_addr.mta_phymask;
 				topo_node->event =
 				    MPTSAS_DR_EVENT_OFFLINE_TARGET;
 				topo_node->devhdl = diskhandle;
@@ -6994,6 +7072,14 @@
 	mpt = replyh_arg->mpt;
 
 	mutex_enter(&mpt->m_mutex);
+	/*
+	 * If HBA is being reset, drop incoming event.
+	 */
+	if (mpt->m_in_reset) {
+		NDBG20(("dropping event received prior to reset"));
+		mutex_exit(&mpt->m_mutex);
+		return;
+	}
 
 	eventreply = (pMpi2EventNotificationReply_t)
 	    (mpt->m_reply_frame + (rfm - mpt->m_reply_frame_dma_addr));
@@ -7322,7 +7408,6 @@
 		uint16_t			devhandle;
 		uint32_t			state;
 		int				config, vol;
-		mptsas_slots_t			*slots = mpt->m_active;
 		uint8_t				found = FALSE;
 
 		irVolume = (pMpi2EventDataIrVolume_t)eventreply->EventData;
@@ -7339,10 +7424,10 @@
 		 * just exit the event.
 		 */
 		(void) mptsas_get_raid_info(mpt);
-		for (config = 0; (config < slots->m_num_raid_configs) &&
+		for (config = 0; (config < mpt->m_num_raid_configs) &&
 		    (!found); config++) {
 			for (vol = 0; vol < MPTSAS_MAX_RAIDVOLS; vol++) {
-				if (slots->m_raidconfig[config].m_raidvol[vol].
+				if (mpt->m_raidconfig[config].m_raidvol[vol].
 				    m_raidhandle == devhandle) {
 					found = TRUE;
 					break;
@@ -7357,7 +7442,7 @@
 		case MPI2_EVENT_IR_VOLUME_RC_SETTINGS_CHANGED:
 		{
 			uint32_t i;
-			slots->m_raidconfig[config].m_raidvol[vol].m_settings =
+			mpt->m_raidconfig[config].m_raidvol[vol].m_settings =
 			    state;
 
 			i = state & MPI2_RAIDVOL0_SETTING_MASK_WRITE_CACHING;
@@ -7380,7 +7465,7 @@
 		}
 		case MPI2_EVENT_IR_VOLUME_RC_STATE_CHANGED:
 		{
-			slots->m_raidconfig[config].m_raidvol[vol].m_state =
+			mpt->m_raidconfig[config].m_raidvol[vol].m_state =
 			    (uint8_t)state;
 
 			mptsas_log(mpt, CE_NOTE,
@@ -7402,7 +7487,7 @@
 		}
 		case MPI2_EVENT_IR_VOLUME_RC_STATUS_FLAGS_CHANGED:
 		{
-			slots->m_raidconfig[config].m_raidvol[vol].
+			mpt->m_raidconfig[config].m_raidvol[vol].
 			    m_statusflags = state;
 
 			mptsas_log(mpt, CE_NOTE,
@@ -7551,9 +7636,8 @@
 
 	mpt->m_restart_cmd_timeid = 0;
 
-	ptgt = (mptsas_target_t *)mptsas_hash_traverse(&mpt->m_active->m_tgttbl,
-	    MPTSAS_HASH_FIRST);
-	while (ptgt != NULL) {
+	for (ptgt = refhash_first(mpt->m_targets); ptgt != NULL;
+	    ptgt = refhash_next(mpt->m_targets, ptgt)) {
 		if (ptgt->m_reset_delay == 0) {
 			if (ptgt->m_t_throttle == QFULL_THROTTLE) {
 				mptsas_set_throttle(mpt, ptgt,
@@ -7560,9 +7644,6 @@
 				    MAX_THROTTLE);
 			}
 		}
-
-		ptgt = (mptsas_target_t *)mptsas_hash_traverse(
-		    &mpt->m_active->m_tgttbl, MPTSAS_HASH_NEXT);
 	}
 	mptsas_restart_hba(mpt);
 	mutex_exit(&mpt->m_mutex);
@@ -7634,7 +7715,7 @@
 	 * If no duplicates, we have to scan through tag que and
 	 * find the longest timeout value and use it.  This is
 	 * going to take a while...
-	 * Add 1 to m_n_slots to account for TM request.
+	 * 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) {
@@ -7641,7 +7722,7 @@
 			if (ptgt->m_t_ncmds) {
 				mptsas_cmd_t *ssp;
 				uint_t n = 0;
-				ushort_t nslots = (slots->m_n_slots + 1);
+				ushort_t nslots = (slots->m_n_normal + 1);
 				ushort_t i;
 				/*
 				 * This crude check assumes we don't do
@@ -8400,7 +8481,6 @@
 {
 	int		rval = FALSE;
 	uint8_t		config, disk;
-	mptsas_slots_t	*slots = mpt->m_active;
 
 	ASSERT(mutex_owned(&mpt->m_mutex));
 
@@ -8415,9 +8495,9 @@
 	 * Phys Disk list of DevHandles.  If the target's DevHandle is in this
 	 * list, then don't reset this target.
 	 */
-	for (config = 0; config < slots->m_num_raid_configs; config++) {
+	for (config = 0; config < mpt->m_num_raid_configs; config++) {
 		for (disk = 0; disk < MPTSAS_MAX_DISKS_IN_CONFIG; disk++) {
-			if (devhdl == slots->m_raidconfig[config].
+			if (devhdl == mpt->m_raidconfig[config].
 			    m_physdisk_devhdl[disk]) {
 				return (TRUE);
 			}
@@ -8513,7 +8593,7 @@
 	 * and target/lun for abort task set.
 	 * Account for TM requests, which use the last SMID.
 	 */
-	for (slot = 0; slot <= mpt->m_active->m_n_slots; slot++) {
+	for (slot = 0; slot <= mpt->m_active->m_n_normal; slot++) {
 		if ((cmd = slots->m_slot[slot]) == NULL)
 			continue;
 		reason = CMD_RESET;
@@ -8645,7 +8725,7 @@
 	 * sure all commands have been flushed.
 	 * Account for TM request, which use the last SMID.
 	 */
-	for (slot = 0; slot <= mpt->m_active->m_n_slots; slot++) {
+	for (slot = 0; slot <= mpt->m_active->m_n_normal; slot++) {
 		if ((cmd = slots->m_slot[slot]) == NULL)
 			continue;
 
@@ -8708,6 +8788,14 @@
 		mutex_enter(&mpt->m_tx_waitq_mutex);
 	}
 	mutex_exit(&mpt->m_tx_waitq_mutex);
+
+	/*
+	 * Drain the taskqs prior to reallocating resources.
+	 */
+	mutex_exit(&mpt->m_mutex);
+	ddi_taskq_wait(mpt->m_event_taskq);
+	ddi_taskq_wait(mpt->m_dr_taskq);
+	mutex_enter(&mpt->m_mutex);
 }
 
 /*
@@ -8752,15 +8840,13 @@
 {
 	mptsas_target_t	*ptgt = NULL;
 
+	ASSERT(MUTEX_HELD(&mpt->m_mutex));
+
 	NDBG22(("mptsas_setup_bus_reset_delay"));
-	ptgt = (mptsas_target_t *)mptsas_hash_traverse(&mpt->m_active->m_tgttbl,
-	    MPTSAS_HASH_FIRST);
-	while (ptgt != NULL) {
+	for (ptgt = refhash_first(mpt->m_targets); ptgt != NULL;
+	    ptgt = refhash_next(mpt->m_targets, ptgt)) {
 		mptsas_set_throttle(mpt, ptgt, HOLD_THROTTLE);
 		ptgt->m_reset_delay = mpt->m_scsi_reset_delay;
-
-		ptgt = (mptsas_target_t *)mptsas_hash_traverse(
-		    &mpt->m_active->m_tgttbl, MPTSAS_HASH_NEXT);
 	}
 
 	mptsas_start_watch_reset_delay();
@@ -8812,9 +8898,8 @@
 
 	ASSERT(mutex_owned(&mpt->m_mutex));
 
-	ptgt = (mptsas_target_t *)mptsas_hash_traverse(&mpt->m_active->m_tgttbl,
-	    MPTSAS_HASH_FIRST);
-	while (ptgt != NULL) {
+	for (ptgt = refhash_first(mpt->m_targets); ptgt != NULL;
+	    ptgt = refhash_next(mpt->m_targets, ptgt)) {
 		if (ptgt->m_reset_delay != 0) {
 			ptgt->m_reset_delay -=
 			    MPTSAS_WATCH_RESET_DELAY_TICK;
@@ -8827,9 +8912,6 @@
 				done = -1;
 			}
 		}
-
-		ptgt = (mptsas_target_t *)mptsas_hash_traverse(
-		    &mpt->m_active->m_tgttbl, MPTSAS_HASH_NEXT);
 	}
 
 	if (restart > 0) {
@@ -9133,7 +9215,6 @@
 	mptsas_slots_t	*old_active = mpt->m_active;
 	mptsas_slots_t	*new_active;
 	size_t		size;
-	int		rval = -1, i;
 
 	/*
 	 * if there are active commands, then we cannot
@@ -9145,7 +9226,7 @@
 	new_active = kmem_zalloc(size, flag);
 	if (new_active == NULL) {
 		NDBG1(("new active alloc failed"));
-		return (rval);
+		return (-1);
 	}
 	/*
 	 * Since SMID 0 is reserved and the TM slot is reserved, the
@@ -9152,24 +9233,14 @@
 	 * number of slots that can be used at any one time is
 	 * m_max_requests - 2.
 	 */
-	new_active->m_n_slots = (mpt->m_max_requests - 2);
+	new_active->m_n_normal = (mpt->m_max_requests - 2);
 	new_active->m_size = size;
-	new_active->m_tags = 1;
-	if (old_active) {
-		new_active->m_tgttbl = old_active->m_tgttbl;
-		new_active->m_smptbl = old_active->m_smptbl;
-		new_active->m_num_raid_configs =
-		    old_active->m_num_raid_configs;
-		for (i = 0; i < new_active->m_num_raid_configs; i++) {
-			new_active->m_raidconfig[i] =
-			    old_active->m_raidconfig[i];
-		}
+	new_active->m_rotor = 1;
+	if (old_active)
 		mptsas_free_active_slots(mpt);
-	}
 	mpt->m_active = new_active;
-	rval = 0;
 
-	return (rval);
+	return (0);
 }
 
 static void
@@ -9314,6 +9385,8 @@
 	mptsas_cmd_t	*cmd;
 	mptsas_target_t	*ptgt = NULL;
 
+	ASSERT(MUTEX_HELD(&mpt->m_mutex));
+
 	NDBG30(("mptsas_watchsubr: mpt=0x%p", (void *)mpt));
 
 #ifdef MPTSAS_TEST
@@ -9326,7 +9399,7 @@
 	 * Check for commands stuck in active slot
 	 * Account for TM requests, which use the last SMID.
 	 */
-	for (i = 0; i <= mpt->m_active->m_n_slots; i++) {
+	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 -=
@@ -9360,9 +9433,8 @@
 		}
 	}
 
-	ptgt = (mptsas_target_t *)mptsas_hash_traverse(&mpt->m_active->m_tgttbl,
-	    MPTSAS_HASH_FIRST);
-	while (ptgt != NULL) {
+	for (ptgt = refhash_first(mpt->m_targets); ptgt != NULL;
+	    ptgt = refhash_next(mpt->m_targets, ptgt)) {
 		/*
 		 * If we were draining due to a qfull condition,
 		 * go back to full throttle.
@@ -9381,8 +9453,6 @@
 			    mptsas_scsi_watchdog_tick) {
 				ptgt->m_timebase +=
 				    mptsas_scsi_watchdog_tick;
-				ptgt = (mptsas_target_t *)mptsas_hash_traverse(
-				    &mpt->m_active->m_tgttbl, MPTSAS_HASH_NEXT);
 				continue;
 			}
 
@@ -9390,8 +9460,6 @@
 
 			if (ptgt->m_timeout < 0) {
 				mptsas_cmd_timeout(mpt, ptgt->m_devhdl);
-				ptgt = (mptsas_target_t *)mptsas_hash_traverse(
-				    &mpt->m_active->m_tgttbl, MPTSAS_HASH_NEXT);
 				continue;
 			}
 
@@ -9402,9 +9470,6 @@
 				    DRAIN_THROTTLE);
 			}
 		}
-
-		ptgt = (mptsas_target_t *)mptsas_hash_traverse(
-		    &mpt->m_active->m_tgttbl, MPTSAS_HASH_NEXT);
 	}
 }
 
@@ -9468,13 +9533,9 @@
 	mutex_enter(&mpt->m_mutex);
 
 	/* Set all the throttles to zero */
-	ptgt = (mptsas_target_t *)mptsas_hash_traverse(&mpt->m_active->m_tgttbl,
-	    MPTSAS_HASH_FIRST);
-	while (ptgt != NULL) {
+	for (ptgt = refhash_first(mpt->m_targets); ptgt != NULL;
+	    ptgt = refhash_next(mpt->m_targets, ptgt)) {
 		mptsas_set_throttle(mpt, ptgt, HOLD_THROTTLE);
-
-		ptgt = (mptsas_target_t *)mptsas_hash_traverse(
-		    &mpt->m_active->m_tgttbl, MPTSAS_HASH_NEXT);
 	}
 
 	/* If there are any outstanding commands in the queue */
@@ -9487,13 +9548,9 @@
 			 * Quiesce has been interrupted
 			 */
 			mpt->m_softstate &= ~MPTSAS_SS_DRAINING;
-			ptgt = (mptsas_target_t *)mptsas_hash_traverse(
-			    &mpt->m_active->m_tgttbl, MPTSAS_HASH_FIRST);
-			while (ptgt != NULL) {
+			for (ptgt = refhash_first(mpt->m_targets); ptgt != NULL;
+			    ptgt = refhash_next(mpt->m_targets, ptgt)) {
 				mptsas_set_throttle(mpt, ptgt, MAX_THROTTLE);
-
-				ptgt = (mptsas_target_t *)mptsas_hash_traverse(
-				    &mpt->m_active->m_tgttbl, MPTSAS_HASH_NEXT);
 			}
 			mptsas_restart_hba(mpt);
 			if (mpt->m_quiesce_timeid != 0) {
@@ -9528,13 +9585,9 @@
 	NDBG28(("mptsas_unquiesce_bus"));
 	mutex_enter(&mpt->m_mutex);
 	mpt->m_softstate &= ~MPTSAS_SS_QUIESCED;
-	ptgt = (mptsas_target_t *)mptsas_hash_traverse(&mpt->m_active->m_tgttbl,
-	    MPTSAS_HASH_FIRST);
-	while (ptgt != NULL) {
+	for (ptgt = refhash_first(mpt->m_targets); ptgt != NULL;
+	    ptgt = refhash_next(mpt->m_targets, ptgt)) {
 		mptsas_set_throttle(mpt, ptgt, MAX_THROTTLE);
-
-		ptgt = (mptsas_target_t *)mptsas_hash_traverse(
-		    &mpt->m_active->m_tgttbl, MPTSAS_HASH_NEXT);
 	}
 	mptsas_restart_hba(mpt);
 	mutex_exit(&mpt->m_mutex);
@@ -9558,13 +9611,9 @@
 			 * The throttle may have been reset because
 			 * of a SCSI bus reset
 			 */
-			ptgt = (mptsas_target_t *)mptsas_hash_traverse(
-			    &mpt->m_active->m_tgttbl, MPTSAS_HASH_FIRST);
-			while (ptgt != NULL) {
+			for (ptgt = refhash_first(mpt->m_targets); ptgt != NULL;
+			    ptgt = refhash_next(mpt->m_targets, ptgt)) {
 				mptsas_set_throttle(mpt, ptgt, HOLD_THROTTLE);
-
-				ptgt = (mptsas_target_t *)mptsas_hash_traverse(
-				    &mpt->m_active->m_tgttbl, MPTSAS_HASH_NEXT);
 			}
 
 			mpt->m_quiesce_timeid = timeout(mptsas_ncmds_checkdrain,
@@ -11271,6 +11320,149 @@
 }
 
 static int
+led_control(mptsas_t *mpt, intptr_t data, int mode)
+{
+	int ret = 0;
+	mptsas_led_control_t lc;
+	mptsas_target_t *ptgt;
+
+	if (ddi_copyin((void *)data, &lc, sizeof (lc), mode) != 0) {
+		return (EFAULT);
+	}
+
+	if ((lc.Command != MPTSAS_LEDCTL_FLAG_SET &&
+	    lc.Command != MPTSAS_LEDCTL_FLAG_GET) ||
+	    lc.Led < MPTSAS_LEDCTL_LED_MIN ||
+	    lc.Led > MPTSAS_LEDCTL_LED_MAX ||
+	    (lc.Command == MPTSAS_LEDCTL_FLAG_SET && lc.LedStatus != 0 &&
+	    lc.LedStatus != 1)) {
+		return (EINVAL);
+	}
+
+	if ((lc.Command == MPTSAS_LEDCTL_FLAG_SET && (mode & FWRITE) == 0) ||
+	    (lc.Command == MPTSAS_LEDCTL_FLAG_GET && (mode & FREAD) == 0))
+		return (EACCES);
+
+	/* Locate the target we're interrogating... */
+	mutex_enter(&mpt->m_mutex);
+	ptgt = refhash_linear_search(mpt->m_targets,
+	    mptsas_target_eval_slot, &lc);
+	if (ptgt == NULL) {
+		/* We could not find a target for that enclosure/slot. */
+		mutex_exit(&mpt->m_mutex);
+		return (ENOENT);
+	}
+
+	if (lc.Command == MPTSAS_LEDCTL_FLAG_SET) {
+		/* Update our internal LED state. */
+		ptgt->m_led_status &= ~(1 << (lc.Led - 1));
+		ptgt->m_led_status |= lc.LedStatus << (lc.Led - 1);
+
+		/* Flush it to the controller. */
+		ret = mptsas_flush_led_status(mpt, ptgt);
+		mutex_exit(&mpt->m_mutex);
+		return (ret);
+	}
+
+	/* Return our internal LED state. */
+	lc.LedStatus = (ptgt->m_led_status >> (lc.Led - 1)) & 1;
+	mutex_exit(&mpt->m_mutex);
+
+	if (ddi_copyout(&lc, (void *)data, sizeof (lc), mode) != 0) {
+		return (EFAULT);
+	}
+
+	return (0);
+}
+
+static int
+get_disk_info(mptsas_t *mpt, intptr_t data, int mode)
+{
+	uint16_t i = 0;
+	uint16_t count = 0;
+	int ret = 0;
+	mptsas_target_t *ptgt;
+	mptsas_disk_info_t *di;
+	STRUCT_DECL(mptsas_get_disk_info, gdi);
+
+	if ((mode & FREAD) == 0)
+		return (EACCES);
+
+	STRUCT_INIT(gdi, get_udatamodel());
+
+	if (ddi_copyin((void *)data, STRUCT_BUF(gdi), STRUCT_SIZE(gdi),
+	    mode) != 0) {
+		return (EFAULT);
+	}
+
+	/* Find out how many targets there are. */
+	mutex_enter(&mpt->m_mutex);
+	for (ptgt = refhash_first(mpt->m_targets); ptgt != NULL;
+	    ptgt = refhash_next(mpt->m_targets, ptgt)) {
+		count++;
+	}
+	mutex_exit(&mpt->m_mutex);
+
+	/*
+	 * If we haven't been asked to copy out information on each target,
+	 * then just return the count.
+	 */
+	STRUCT_FSET(gdi, DiskCount, count);
+	if (STRUCT_FGETP(gdi, PtrDiskInfoArray) == NULL)
+		goto copy_out;
+
+	/*
+	 * If we haven't been given a large enough buffer to copy out into,
+	 * let the caller know.
+	 */
+	if (STRUCT_FGET(gdi, DiskInfoArraySize) <
+	    count * sizeof (mptsas_disk_info_t)) {
+		ret = ENOSPC;
+		goto copy_out;
+	}
+
+	di = kmem_zalloc(count * sizeof (mptsas_disk_info_t), KM_SLEEP);
+
+	mutex_enter(&mpt->m_mutex);
+	for (ptgt = refhash_first(mpt->m_targets); ptgt != NULL;
+	    ptgt = refhash_next(mpt->m_targets, ptgt)) {
+		if (i >= count) {
+			/*
+			 * The number of targets changed while we weren't
+			 * looking, so give up.
+			 */
+			refhash_rele(mpt->m_targets, ptgt);
+			mutex_exit(&mpt->m_mutex);
+			kmem_free(di, count * sizeof (mptsas_disk_info_t));
+			return (EAGAIN);
+		}
+		di[i].Instance = mpt->m_instance;
+		di[i].Enclosure = ptgt->m_enclosure;
+		di[i].Slot = ptgt->m_slot_num;
+		di[i].SasAddress = ptgt->m_addr.mta_wwn;
+		i++;
+	}
+	mutex_exit(&mpt->m_mutex);
+	STRUCT_FSET(gdi, DiskCount, i);
+
+	/* Copy out the disk information to the caller. */
+	if (ddi_copyout((void *)di, STRUCT_FGETP(gdi, PtrDiskInfoArray),
+	    i * sizeof (mptsas_disk_info_t), mode) != 0) {
+		ret = EFAULT;
+	}
+
+	kmem_free(di, count * sizeof (mptsas_disk_info_t));
+
+copy_out:
+	if (ddi_copyout(STRUCT_BUF(gdi), (void *)data, STRUCT_SIZE(gdi),
+	    mode) != 0) {
+		ret = EFAULT;
+	}
+
+	return (ret);
+}
+
+static int
 mptsas_ioctl(dev_t dev, int cmd, intptr_t data, int mode, cred_t *credp,
     int *rval)
 {
@@ -11286,7 +11478,6 @@
 	dev_info_t		*dip = NULL;
 	mptsas_phymask_t	phymask = 0;
 	struct devctl_iocdata	*dcp = NULL;
-	uint32_t		slotstatus = 0;
 	char			*addr = NULL;
 	mptsas_target_t		*ptgt = NULL;
 
@@ -11357,34 +11548,14 @@
 			} else if (cmd == DEVCTL_DEVICE_OFFLINE) {
 				ptgt->m_tgt_unconfigured = 1;
 			}
-			slotstatus = 0;
-#ifdef MPTSAS_GET_LED
-			/*
-			 * The get led status can't get a valid/reasonable
-			 * state, so ignore the get led status, and write the
-			 * required value directly
-			 */
-			if (mptsas_get_led_status(mpt, ptgt, &slotstatus) !=
-			    DDI_SUCCESS) {
-				NDBG14(("mptsas_ioctl: get LED for tgt %s "
-				    "failed %x", addr, slotstatus));
-				slotstatus = 0;
-			}
-			NDBG14(("mptsas_ioctl: LED status %x for %s",
-			    slotstatus, addr));
-#endif
 			if (cmd == DEVCTL_DEVICE_OFFLINE) {
-				slotstatus |=
-				    MPI2_SEP_REQ_SLOTSTATUS_REQUEST_REMOVE;
+				ptgt->m_led_status |=
+				    (1 << (MPTSAS_LEDCTL_LED_OK2RM - 1));
 			} else {
-				slotstatus &=
-				    ~MPI2_SEP_REQ_SLOTSTATUS_REQUEST_REMOVE;
+				ptgt->m_led_status &=
+				    ~(1 << (MPTSAS_LEDCTL_LED_OK2RM - 1));
 			}
-			if (mptsas_set_led_status(mpt, ptgt, slotstatus) !=
-			    DDI_SUCCESS) {
-				NDBG14(("mptsas_ioctl: set LED for tgt %s "
-				    "failed %x", addr, slotstatus));
-			}
+			(void) mptsas_flush_led_status(mpt, ptgt);
 			mutex_exit(&mpt->m_mutex);
 			ndi_dc_freehdl(dcp);
 		}
@@ -11391,6 +11562,12 @@
 		goto out;
 	}
 	switch (cmd) {
+		case MPTIOCTL_GET_DISK_INFO:
+			status = get_disk_info(mpt, data, mode);
+			break;
+		case MPTIOCTL_LED_CONTROL:
+			status = led_control(mpt, data, mode);
+			break;
 		case MPTIOCTL_UPDATE_FLASH:
 			if (ddi_copyin((void *)data, &flashdata,
 				sizeof (struct mptsas_update_flash), mode)) {
@@ -11568,13 +11745,9 @@
 	/*
 	 * Set all throttles to HOLD
 	 */
-	ptgt = (mptsas_target_t *)mptsas_hash_traverse(&mpt->m_active->m_tgttbl,
-	    MPTSAS_HASH_FIRST);
-	while (ptgt != NULL) {
+	for (ptgt = refhash_first(mpt->m_targets); ptgt != NULL;
+	    ptgt = refhash_next(mpt->m_targets, ptgt)) {
 		mptsas_set_throttle(mpt, ptgt, HOLD_THROTTLE);
-
-		ptgt = (mptsas_target_t *)mptsas_hash_traverse(
-		    &mpt->m_active->m_tgttbl, MPTSAS_HASH_NEXT);
 	}
 
 	/*
@@ -11610,13 +11783,9 @@
 	/*
 	 * Reset the throttles
 	 */
-	ptgt = (mptsas_target_t *)mptsas_hash_traverse(&mpt->m_active->m_tgttbl,
-	    MPTSAS_HASH_FIRST);
-	while (ptgt != NULL) {
+	for (ptgt = refhash_first(mpt->m_targets); ptgt != NULL;
+	    ptgt = refhash_next(mpt->m_targets, ptgt)) {
 		mptsas_set_throttle(mpt, ptgt, MAX_THROTTLE);
-
-		ptgt = (mptsas_target_t *)mptsas_hash_traverse(
-		    &mpt->m_active->m_tgttbl, MPTSAS_HASH_NEXT);
 	}
 
 	mptsas_doneq_empty(mpt);
@@ -11682,6 +11851,12 @@
 		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),
+	    offsetof(mptsas_target_t, m_link),
+	    offsetof(mptsas_target_t, m_addr), KM_SLEEP);
+
 	if (mptsas_alloc_active_slots(mpt, KM_SLEEP)) {
 		goto fail;
 	}
@@ -12320,7 +12495,6 @@
 	uint64_t	sas_wwn;
 	mptsas_phymask_t phymask;
 	uint8_t		physport, phynum, config, disk;
-	mptsas_slots_t	*slots = mpt->m_active;
 	uint64_t	devicename;
 	uint16_t	pdev_hdl;
 	mptsas_target_t	*tmp_tgt = NULL;
@@ -12347,9 +12521,9 @@
 	 * Check if the dev handle is for a Phys Disk. If so, set return value
 	 * and exit.  Don't add Phys Disks to hash.
 	 */
-	for (config = 0; config < slots->m_num_raid_configs; config++) {
+	for (config = 0; config < mpt->m_num_raid_configs; config++) {
 		for (disk = 0; disk < MPTSAS_MAX_DISKS_IN_CONFIG; disk++) {
-			if (*dev_handle == slots->m_raidconfig[config].
+			if (*dev_handle == mpt->m_raidconfig[config].
 			    m_physdisk_devhdl[disk]) {
 				rval = DEV_INFO_PHYS_DISK;
 				return (rval);
@@ -12359,7 +12533,7 @@
 
 	/*
 	 * Get SATA Device Name from SAS device page0 for
-	 * sata device, if device name doesn't exist, set m_sas_wwn to
+	 * sata device, if device name doesn't exist, set mta_wwn to
 	 * 0 for direct attached SATA. For the device behind the expander
 	 * we still can use STP address assigned by expander.
 	 */
@@ -12386,7 +12560,7 @@
 	}
 
 	phymask = mptsas_physport_to_phymask(mpt, physport);
-	*pptgt = mptsas_tgt_alloc(&slots->m_tgttbl, *dev_handle, sas_wwn,
+	*pptgt = mptsas_tgt_alloc(mpt, *dev_handle, sas_wwn,
 	    dev_info, phymask, phynum);
 	if (*pptgt == NULL) {
 		mptsas_log(mpt, CE_WARN, "Failed to allocated target"
@@ -12816,7 +12990,7 @@
 		 * possible?
 		 * tgt_private->t_private != ptgt
 		 */
-		if (sasaddr != ptgt->m_sas_wwn) {
+		if (sasaddr != ptgt->m_addr.mta_wwn) {
 			/*
 			 * The device has changed although the devhdl is the
 			 * same (Enclosure mapping mode, change drive on the
@@ -12845,13 +13019,13 @@
 {
 	int		rval;
 	mptsas_t	*mpt = DIP2MPT(pdip);
-	int		phymask;
+	mptsas_phymask_t phymask;
 	mptsas_target_t	*ptgt = NULL;
 
 	/*
 	 * Get the physical port associated to the iport
 	 */
-	phymask = ddi_prop_get_int(DDI_DEV_T_ANY, pdip, 0,
+	phymask = (mptsas_phymask_t)ddi_prop_get_int(DDI_DEV_T_ANY, pdip, 0,
 	    "phymask", 0);
 
 	ptgt = mptsas_phy_to_tgt(mpt, phymask, phy);
@@ -12938,7 +13112,7 @@
 	uint32_t		dev_info = 0;
 
 	mutex_enter(&mpt->m_mutex);
-	sas_wwn = ptgt->m_sas_wwn;
+	sas_wwn = ptgt->m_addr.mta_wwn;
 	phy = ptgt->m_phynum;
 	dev_info = ptgt->m_deviceinfo;
 	mutex_exit(&mpt->m_mutex);
@@ -13053,7 +13227,8 @@
 	mptsas_target_t		*ptgt = NULL;
 
 	mutex_enter(&mpt->m_mutex);
-	ptgt = mptsas_search_by_devhdl(&mpt->m_active->m_tgttbl, target);
+	ptgt = refhash_linear_search(mpt->m_targets,
+	    mptsas_target_eval_devhdl, &target);
 	mutex_exit(&mpt->m_mutex);
 	if (ptgt == NULL) {
 		mptsas_log(mpt, CE_WARN, "Volume with VolDevHandle of 0x%x "
@@ -13086,7 +13261,6 @@
 	int		config, vol;
 	int		target;
 	dev_info_t	*lundip = NULL;
-	mptsas_slots_t	*slots = mpt->m_active;
 
 	/*
 	 * Get latest RAID info and search for any Volume DevHandles.  If any
@@ -13093,11 +13267,11 @@
 	 * are found, configure the volume.
 	 */
 	mutex_enter(&mpt->m_mutex);
-	for (config = 0; config < slots->m_num_raid_configs; config++) {
+	for (config = 0; config < mpt->m_num_raid_configs; config++) {
 		for (vol = 0; vol < MPTSAS_MAX_RAIDVOLS; vol++) {
-			if (slots->m_raidconfig[config].m_raidvol[vol].m_israid
+			if (mpt->m_raidconfig[config].m_raidvol[vol].m_israid
 			    == 1) {
-				target = slots->m_raidconfig[config].
+				target = mpt->m_raidconfig[config].
 				    m_raidvol[vol].m_raidhandle;
 				mutex_exit(&mpt->m_mutex);
 				(void) mptsas_config_raid(pdip, target,
@@ -13125,7 +13299,7 @@
 	mptsas_t	*mpt = DIP2MPT(pdip);
 
 	mutex_enter(&mpt->m_mutex);
-	wwid = ptgt->m_sas_wwn;
+	wwid = ptgt->m_addr.mta_wwn;
 	mutex_exit(&mpt->m_mutex);
 
 	child = ddi_get_child(pdip);
@@ -13229,7 +13403,7 @@
 			break;
 		}
 		mpt->m_smp_devhdl = dev_handle = smp_node.m_devhdl;
-		(void) mptsas_smp_alloc(&mpt->m_active->m_smptbl, &smp_node);
+		(void) mptsas_smp_alloc(mpt, &smp_node);
 	}
 
 	/*
@@ -13261,24 +13435,13 @@
 }
 
 void
-mptsas_invalid_hashtab(mptsas_hash_table_t *hashtab)
-{
-	mptsas_hash_data_t *data;
-	data = mptsas_hash_traverse(hashtab, MPTSAS_HASH_FIRST);
-	while (data != NULL) {
-		data->devhdl = MPTSAS_INVALID_DEVHDL;
-		data->device_info = 0;
-		/*
-		 * For tgttbl, clear dr_flag.
-		 */
-		data->dr_flag = MPTSAS_DR_INACTIVE;
-		data = mptsas_hash_traverse(hashtab, MPTSAS_HASH_NEXT);
-	}
-}
-
-void
 mptsas_update_driver_data(struct mptsas *mpt)
 {
+	mptsas_target_t *tp;
+	mptsas_smp_t *sp;
+
+	ASSERT(MUTEX_HELD(&mpt->m_mutex));
+
 	/*
 	 * TODO after hard reset, update the driver data structures
 	 * 1. update port/phymask mapping table mpt->m_phy_info
@@ -13289,9 +13452,24 @@
 	mptsas_update_phymask(mpt);
 	/*
 	 * Invalid the existing entries
+	 *
+	 * XXX - It seems like we should just delete everything here.  We are
+	 * holding the lock and are about to refresh all the targets in both
+	 * hashes anyway.  Given the path we're in, what outstanding async
+	 * event could possibly be trying to reference one of these things
+	 * without taking the lock, and how would that be useful anyway?
 	 */
-	mptsas_invalid_hashtab(&mpt->m_active->m_tgttbl);
-	mptsas_invalid_hashtab(&mpt->m_active->m_smptbl);
+	for (tp = refhash_first(mpt->m_targets); tp != NULL;
+	    tp = refhash_next(mpt->m_targets, tp)) {
+		tp->m_devhdl = MPTSAS_INVALID_DEVHDL;
+		tp->m_deviceinfo = 0;
+		tp->m_dr_flag = MPTSAS_DR_INACTIVE;
+	}
+	for (sp = refhash_first(mpt->m_smp_targets); sp != NULL;
+	    sp = refhash_next(mpt->m_smp_targets, sp)) {
+		sp->m_devhdl = MPTSAS_INVALID_DEVHDL;
+		sp->m_deviceinfo = 0;
+	}
 	mpt->m_done_traverse_dev = 0;
 	mpt->m_done_traverse_smp = 0;
 	mpt->m_dev_handle = mpt->m_smp_devhdl = MPTSAS_INVALID_DEVHDL;
@@ -13328,10 +13506,9 @@
 		mptsas_update_hashtab(mpt);
 	}
 
-	psmp = (mptsas_smp_t *)mptsas_hash_traverse(&mpt->m_active->m_smptbl,
-	    MPTSAS_HASH_FIRST);
-	while (psmp != NULL) {
-		phy_mask = psmp->m_phymask;
+	for (psmp = refhash_first(mpt->m_smp_targets); psmp != NULL;
+	    psmp = refhash_next(mpt->m_smp_targets, psmp)) {
+		phy_mask = psmp->m_addr.mta_phymask;
 		if (phy_mask == phymask) {
 			smpdip = NULL;
 			mutex_exit(&mpt->m_mutex);
@@ -13338,22 +13515,16 @@
 			(void) mptsas_online_smp(pdip, psmp, &smpdip);
 			mutex_enter(&mpt->m_mutex);
 		}
-		psmp = (mptsas_smp_t *)mptsas_hash_traverse(
-		    &mpt->m_active->m_smptbl, MPTSAS_HASH_NEXT);
 	}
 
-	ptgt = (mptsas_target_t *)mptsas_hash_traverse(&mpt->m_active->m_tgttbl,
-	    MPTSAS_HASH_FIRST);
-	while (ptgt != NULL) {
-		phy_mask = ptgt->m_phymask;
+	for (ptgt = refhash_first(mpt->m_targets); ptgt != NULL;
+	    ptgt = refhash_next(mpt->m_targets, ptgt)) {
+		phy_mask = ptgt->m_addr.mta_phymask;
 		if (phy_mask == phymask) {
 			mutex_exit(&mpt->m_mutex);
 			(void) mptsas_config_target(pdip, ptgt);
 			mutex_enter(&mpt->m_mutex);
 		}
-
-		ptgt = (mptsas_target_t *)mptsas_hash_traverse(
-		    &mpt->m_active->m_tgttbl, MPTSAS_HASH_NEXT);
 	}
 	mutex_exit(&mpt->m_mutex);
 }
@@ -13535,7 +13706,7 @@
 	char		wwn_str[MPTSAS_WWN_STRLEN];
 	dev_info_t	*cdip;
 
-	(void) sprintf(wwn_str, "%"PRIx64, smp_node->m_sasaddr);
+	(void) sprintf(wwn_str, "%"PRIx64, smp_node->m_addr.mta_wwn);
 
 	cdip = mptsas_find_smp_child(pdip, wwn_str);
 
@@ -13815,7 +13986,7 @@
 
 	mutex_enter(&mpt->m_mutex);
 	target = ptgt->m_devhdl;
-	sas_wwn = ptgt->m_sas_wwn;
+	sas_wwn = ptgt->m_addr.mta_wwn;
 	devinfo = ptgt->m_deviceinfo;
 	phy = ptgt->m_phynum;
 	mutex_exit(&mpt->m_mutex);
@@ -13842,8 +14013,9 @@
 				    (ptgt->m_tgt_unconfigured == 0)) {
 					rval = mdi_pi_online(*pip, 0);
 					mutex_enter(&mpt->m_mutex);
-					(void) mptsas_set_led_status(mpt, ptgt,
-					    0);
+					ptgt->m_led_status = 0;
+					(void) mptsas_flush_led_status(mpt,
+					    ptgt);
 					mutex_exit(&mpt->m_mutex);
 				} else {
 					rval = DDI_SUCCESS;
@@ -14100,11 +14272,8 @@
 		mdi_rtn = mdi_pi_online(*pip, 0);
 		if (mdi_rtn == MDI_SUCCESS) {
 			mutex_enter(&mpt->m_mutex);
-			if (mptsas_set_led_status(mpt, ptgt, 0) !=
-			    DDI_SUCCESS) {
-				NDBG14(("mptsas: clear LED for slot %x "
-				    "failed", ptgt->m_slot_num));
-			}
+			ptgt->m_led_status = 0;
+			(void) mptsas_flush_led_status(mpt, ptgt);
 			mutex_exit(&mpt->m_mutex);
 		}
 		if (mdi_rtn == MDI_NOT_SUPPORTED) {
@@ -14166,7 +14335,7 @@
 
 	mutex_enter(&mpt->m_mutex);
 	target = ptgt->m_devhdl;
-	sas_wwn = ptgt->m_sas_wwn;
+	sas_wwn = ptgt->m_addr.mta_wwn;
 	devinfo = ptgt->m_deviceinfo;
 	phy = ptgt->m_phynum;
 	mutex_exit(&mpt->m_mutex);
@@ -14285,7 +14454,7 @@
 		 * The following code is to set properties for SM-HBA support,
 		 * it doesn't apply to RAID volumes
 		 */
-		if (ptgt->m_phymask == 0)
+		if (ptgt->m_addr.mta_phymask == 0)
 			goto phys_raid_lun;
 
 		mutex_enter(&mpt->m_mutex);
@@ -14439,7 +14608,7 @@
 		/*
 		 * Create the phy-num property for non-raid disk
 		 */
-		if (ptgt->m_phymask != 0) {
+		if (ptgt->m_addr.mta_phymask != 0) {
 			if (ndi_prop_update_int(DDI_DEV_T_NONE,
 			    *lun_dip, "phy-num", ptgt->m_phynum) !=
 			    DDI_PROP_SUCCESS) {
@@ -14462,11 +14631,8 @@
 		}
 		if (ndi_rtn == NDI_SUCCESS) {
 			mutex_enter(&mpt->m_mutex);
-			if (mptsas_set_led_status(mpt, ptgt, 0) !=
-			    DDI_SUCCESS) {
-				NDBG14(("mptsas: clear LED for tgt %x "
-				    "failed", ptgt->m_slot_num));
-			}
+			ptgt->m_led_status = 0;
+			(void) mptsas_flush_led_status(mpt, ptgt);
 			mutex_exit(&mpt->m_mutex);
 		}
 
@@ -14564,13 +14730,13 @@
 	uint16_t	attached_devhdl;
 	uint16_t	bay_num, enclosure;
 
-	(void) sprintf(wwn_str, "%"PRIx64, smp_node->m_sasaddr);
+	(void) sprintf(wwn_str, "%"PRIx64, smp_node->m_addr.mta_wwn);
 
 	/*
 	 * Probe smp device, prevent the node of removed device from being
 	 * configured succesfully
 	 */
-	if (mptsas_probe_smp(pdip, smp_node->m_sasaddr) != NDI_SUCCESS) {
+	if (mptsas_probe_smp(pdip, smp_node->m_addr.mta_wwn) != NDI_SUCCESS) {
 		return (DDI_FAILURE);
 	}
 
@@ -14598,7 +14764,7 @@
 			ndi_rtn = NDI_FAILURE;
 			goto smp_create_done;
 		}
-		(void) sprintf(wwn_str, "w%"PRIx64, smp_node->m_sasaddr);
+		(void) sprintf(wwn_str, "w%"PRIx64, smp_node->m_addr.mta_wwn);
 		if (ndi_prop_update_string(DDI_DEV_T_NONE,
 		    *smp_dip, SCSI_ADDR_PROP_TARGET_PORT, wwn_str) !=
 		    DDI_PROP_SUCCESS) {
@@ -14742,8 +14908,8 @@
 		}
 		mutex_exit(&mpt->m_mutex);
 
-		mptsas_smhba_set_phy_props(mpt, iport, pdip,
-		    numphys, &attached_devhdl);
+		mptsas_smhba_set_all_phy_props(mpt, pdip, numphys, phy_mask,
+		    &attached_devhdl);
 
 		if (ddi_prop_update_int(DDI_DEV_T_NONE, pdip,
 		    MPTSAS_NUM_PHYS, numphys) !=
@@ -14882,7 +15048,7 @@
  * untill we get a match. If failed, return NULL
  */
 static mptsas_target_t *
-mptsas_phy_to_tgt(mptsas_t *mpt, int phymask, uint8_t phy)
+mptsas_phy_to_tgt(mptsas_t *mpt, mptsas_phymask_t phymask, uint8_t phy)
 {
 	int		i, j = 0;
 	int		rval = 0;
@@ -14914,16 +15080,11 @@
 
 	mutex_enter(&mpt->m_mutex);
 
-	ptgt = (mptsas_target_t *)mptsas_hash_traverse(&mpt->m_active->m_tgttbl,
-	    MPTSAS_HASH_FIRST);
-	while (ptgt != NULL) {
-			if ((ptgt->m_sas_wwn == 0) && (ptgt->m_phynum == phy)) {
-			mutex_exit(&mpt->m_mutex);
-			return (ptgt);
-		}
-
-		ptgt = (mptsas_target_t *)mptsas_hash_traverse(
-		    &mpt->m_active->m_tgttbl, MPTSAS_HASH_NEXT);
+	ptgt = refhash_linear_search(mpt->m_targets, mptsas_target_eval_nowwn,
+	    &phy);
+	if (ptgt != NULL) {
+		mutex_exit(&mpt->m_mutex);
+		return (ptgt);
 	}
 
 	if (mpt->m_done_traverse_dev) {
@@ -14949,7 +15110,7 @@
 		}
 		mpt->m_dev_handle = cur_handle;
 
-		if ((ptgt->m_sas_wwn == 0) && (ptgt->m_phynum == phy)) {
+		if ((ptgt->m_addr.mta_wwn == 0) && (ptgt->m_phynum == phy)) {
 			break;
 		}
 	}
@@ -14959,7 +15120,7 @@
 }
 
 /*
- * The ptgt->m_sas_wwn contains the wwid for each disk.
+ * The ptgt->m_addr.mta_wwn contains the wwid for each disk.
  * For Raid volumes, we need to check m_raidvol[x].m_raidwwid
  * If we didn't get a match, we need to get sas page0 for each device, and
  * untill we get a match
@@ -14966,16 +15127,18 @@
  * If failed, return NULL
  */
 static mptsas_target_t *
-mptsas_wwid_to_ptgt(mptsas_t *mpt, int phymask, uint64_t wwid)
+mptsas_wwid_to_ptgt(mptsas_t *mpt, mptsas_phymask_t phymask, uint64_t wwid)
 {
 	int		rval = 0;
 	uint16_t	cur_handle;
 	uint32_t	page_address;
 	mptsas_target_t	*tmp_tgt = NULL;
+	mptsas_target_addr_t addr;
 
+	addr.mta_wwn = wwid;
+	addr.mta_phymask = phymask;
 	mutex_enter(&mpt->m_mutex);
-	tmp_tgt = (struct mptsas_target *)mptsas_hash_search(
-	    &mpt->m_active->m_tgttbl, wwid, phymask);
+	tmp_tgt = refhash_lookup(mpt->m_targets, &addr);
 	if (tmp_tgt != NULL) {
 		mutex_exit(&mpt->m_mutex);
 		return (tmp_tgt);
@@ -14987,8 +15150,7 @@
 		 */
 		rval = mptsas_get_raid_info(mpt);
 		if (rval) {
-			tmp_tgt = (struct mptsas_target *)mptsas_hash_search(
-			    &mpt->m_active->m_tgttbl, wwid, phymask);
+			tmp_tgt = refhash_lookup(mpt->m_targets, &addr);
 		}
 		mutex_exit(&mpt->m_mutex);
 		return (tmp_tgt);
@@ -15001,7 +15163,7 @@
 
 	/* If didn't get a match, come here */
 	cur_handle = mpt->m_dev_handle;
-	for (; ; ) {
+	for (;;) {
 		tmp_tgt = NULL;
 		page_address = (MPI2_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE &
 		    MPI2_SAS_DEVICE_PGAD_FORM_MASK) | cur_handle;
@@ -15017,8 +15179,9 @@
 			continue;
 		}
 		mpt->m_dev_handle = cur_handle;
-		if ((tmp_tgt->m_sas_wwn) && (tmp_tgt->m_sas_wwn == wwid) &&
-		    (tmp_tgt->m_phymask == phymask)) {
+		if ((tmp_tgt->m_addr.mta_wwn) &&
+		    (tmp_tgt->m_addr.mta_wwn == wwid) &&
+		    (tmp_tgt->m_addr.mta_phymask == phymask)) {
 			break;
 		}
 	}
@@ -15028,16 +15191,18 @@
 }
 
 static mptsas_smp_t *
-mptsas_wwid_to_psmp(mptsas_t *mpt, int phymask, uint64_t wwid)
+mptsas_wwid_to_psmp(mptsas_t *mpt, mptsas_phymask_t phymask, uint64_t wwid)
 {
 	int		rval = 0;
 	uint16_t	cur_handle;
 	uint32_t	page_address;
 	mptsas_smp_t	smp_node, *psmp = NULL;
+	mptsas_target_addr_t addr;
 
+	addr.mta_wwn = wwid;
+	addr.mta_phymask = phymask;
 	mutex_enter(&mpt->m_mutex);
-	psmp = (struct mptsas_smp *)mptsas_hash_search(&mpt->m_active->m_smptbl,
-	    wwid, phymask);
+	psmp = refhash_lookup(mpt->m_smp_targets, &addr);
 	if (psmp != NULL) {
 		mutex_exit(&mpt->m_mutex);
 		return (psmp);
@@ -15050,7 +15215,7 @@
 
 	/* If didn't get a match, come here */
 	cur_handle = mpt->m_smp_devhdl;
-	for (; ; ) {
+	for (;;) {
 		psmp = NULL;
 		page_address = (MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL &
 		    MPI2_SAS_EXPAND_PGAD_FORM_MASK) | (uint32_t)cur_handle;
@@ -15060,10 +15225,10 @@
 			break;
 		}
 		mpt->m_smp_devhdl = cur_handle = smp_node.m_devhdl;
-		psmp = mptsas_smp_alloc(&mpt->m_active->m_smptbl, &smp_node);
+		psmp = mptsas_smp_alloc(mpt, &smp_node);
 		ASSERT(psmp);
-		if ((psmp->m_sasaddr) && (psmp->m_sasaddr == wwid) &&
-		    (psmp->m_phymask == phymask)) {
+		if ((psmp->m_addr.mta_wwn) && (psmp->m_addr.mta_wwn == wwid) &&
+		    (psmp->m_addr.mta_phymask == phymask)) {
 			break;
 		}
 	}
@@ -15072,38 +15237,20 @@
 	return (psmp);
 }
 
-/* helper functions using hash */
-
-/*
- * Can't have duplicate entries for same devhdl,
- * if there are invalid entries, the devhdl should be set to 0xffff
- */
-static void *
-mptsas_search_by_devhdl(mptsas_hash_table_t *hashtab, uint16_t devhdl)
-{
-	mptsas_hash_data_t *data;
-
-	data = mptsas_hash_traverse(hashtab, MPTSAS_HASH_FIRST);
-	while (data != NULL) {
-		if (data->devhdl == devhdl) {
-			break;
-		}
-		data = mptsas_hash_traverse(hashtab, MPTSAS_HASH_NEXT);
-	}
-	return (data);
-}
-
 mptsas_target_t *
-mptsas_tgt_alloc(mptsas_hash_table_t *hashtab, uint16_t devhdl, uint64_t wwid,
+mptsas_tgt_alloc(mptsas_t *mpt, uint16_t devhdl, uint64_t wwid,
     uint32_t devinfo, mptsas_phymask_t phymask, uint8_t phynum)
 {
 	mptsas_target_t *tmp_tgt = NULL;
+	mptsas_target_addr_t addr;
 
-	tmp_tgt = mptsas_hash_search(hashtab, wwid, phymask);
+	addr.mta_wwn = wwid;
+	addr.mta_phymask = phymask;
+	tmp_tgt = refhash_lookup(mpt->m_targets, &addr);
 	if (tmp_tgt != NULL) {
 		NDBG20(("Hash item already exist"));
 		tmp_tgt->m_deviceinfo = devinfo;
-		tmp_tgt->m_devhdl = devhdl;
+		tmp_tgt->m_devhdl = devhdl;	/* XXX - duplicate? */
 		return (tmp_tgt);
 	}
 	tmp_tgt = kmem_zalloc(sizeof (struct mptsas_target), KM_SLEEP);
@@ -15112,9 +15259,9 @@
 		return (NULL);
 	}
 	tmp_tgt->m_devhdl = devhdl;
-	tmp_tgt->m_sas_wwn = wwid;
+	tmp_tgt->m_addr.mta_wwn = wwid;
 	tmp_tgt->m_deviceinfo = devinfo;
-	tmp_tgt->m_phymask = phymask;
+	tmp_tgt->m_addr.mta_phymask = phymask;
 	tmp_tgt->m_phynum = phynum;
 	/* Initialized the tgt structure */
 	tmp_tgt->m_qfull_retries = QFULL_RETRIES;
@@ -15122,210 +15269,47 @@
 	    drv_usectohz(QFULL_RETRY_INTERVAL * 1000);
 	tmp_tgt->m_t_throttle = MAX_THROTTLE;
 
-	mptsas_hash_add(hashtab, tmp_tgt);
+	refhash_insert(mpt->m_targets, tmp_tgt);
 
 	return (tmp_tgt);
 }
 
 static void
-mptsas_tgt_free(mptsas_hash_table_t *hashtab, uint64_t wwid,
-    mptsas_phymask_t phymask)
+mptsas_smp_target_copy(mptsas_smp_t *src, mptsas_smp_t *dst)
 {
-	mptsas_target_t *tmp_tgt;
-	tmp_tgt = mptsas_hash_rem(hashtab, wwid, phymask);
-	if (tmp_tgt == NULL) {
-		cmn_err(CE_WARN, "Tgt not found, nothing to free");
-	} else {
-		kmem_free(tmp_tgt, sizeof (struct mptsas_target));
-	}
+	dst->m_devhdl = src->m_devhdl;
+	dst->m_deviceinfo = src->m_deviceinfo;
+	dst->m_pdevhdl = src->m_pdevhdl;
+	dst->m_pdevinfo = src->m_pdevinfo;
 }
 
-/*
- * Return the entry in the hash table
- */
 static mptsas_smp_t *
-mptsas_smp_alloc(mptsas_hash_table_t *hashtab, mptsas_smp_t *data)
+mptsas_smp_alloc(mptsas_t *mpt, mptsas_smp_t *data)
 {
-	uint64_t key1 = data->m_sasaddr;
-	mptsas_phymask_t key2 = data->m_phymask;
+	mptsas_target_addr_t addr;
 	mptsas_smp_t *ret_data;
 
-	ret_data = mptsas_hash_search(hashtab, key1, key2);
+	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));
+		mptsas_smp_target_copy(data, ret_data);
 		return (ret_data);
 	}
 
 	ret_data = kmem_alloc(sizeof (mptsas_smp_t), KM_SLEEP);
 	bcopy(data, ret_data, sizeof (mptsas_smp_t));
-	mptsas_hash_add(hashtab, ret_data);
+	refhash_insert(mpt->m_smp_targets, ret_data);
 	return (ret_data);
 }
 
-static void
-mptsas_smp_free(mptsas_hash_table_t *hashtab, uint64_t wwid,
-    mptsas_phymask_t phymask)
-{
-	mptsas_smp_t *tmp_smp;
-	tmp_smp = mptsas_hash_rem(hashtab, wwid, phymask);
-	if (tmp_smp == NULL) {
-		cmn_err(CE_WARN, "Smp element not found, nothing to free");
-	} else {
-		kmem_free(tmp_smp, sizeof (struct mptsas_smp));
-	}
-}
-
 /*
- * Hash operation functions
- * key1 is the sas_wwn, key2 is the phymask
- */
-static void
-mptsas_hash_init(mptsas_hash_table_t *hashtab)
-{
-	if (hashtab == NULL) {
-		return;
-	}
-	bzero(hashtab->head, sizeof (mptsas_hash_node_t) *
-	    MPTSAS_HASH_ARRAY_SIZE);
-	hashtab->cur = NULL;
-	hashtab->line = 0;
-}
-
-static void
-mptsas_hash_uninit(mptsas_hash_table_t *hashtab, size_t datalen)
-{
-	uint16_t line = 0;
-	mptsas_hash_node_t *cur = NULL, *last = NULL;
-
-	if (hashtab == NULL) {
-		return;
-	}
-	for (line = 0; line < MPTSAS_HASH_ARRAY_SIZE; line++) {
-		cur = hashtab->head[line];
-		while (cur != NULL) {
-			last = cur;
-			cur = cur->next;
-			kmem_free(last->data, datalen);
-			kmem_free(last, sizeof (mptsas_hash_node_t));
-		}
-	}
-}
-
-/*
- * You must guarantee the element doesn't exist in the hash table
- * before you call mptsas_hash_add()
- */
-static void
-mptsas_hash_add(mptsas_hash_table_t *hashtab, void *data)
-{
-	uint64_t key1 = ((mptsas_hash_data_t *)data)->key1;
-	mptsas_phymask_t key2 = ((mptsas_hash_data_t *)data)->key2;
-	mptsas_hash_node_t **head = NULL;
-	mptsas_hash_node_t *node = NULL;
-
-	if (hashtab == NULL) {
-		return;
-	}
-	ASSERT(mptsas_hash_search(hashtab, key1, key2) == NULL);
-	node = kmem_zalloc(sizeof (mptsas_hash_node_t), KM_NOSLEEP);
-	node->data = data;
-
-	head = &(hashtab->head[key1 % MPTSAS_HASH_ARRAY_SIZE]);
-	if (*head == NULL) {
-		*head = node;
-	} else {
-		node->next = *head;
-		*head = node;
-	}
-}
-
-static void *
-mptsas_hash_rem(mptsas_hash_table_t *hashtab, uint64_t key1,
-    mptsas_phymask_t key2)
-{
-	mptsas_hash_node_t **head = NULL;
-	mptsas_hash_node_t *last = NULL, *cur = NULL;
-	mptsas_hash_data_t *data;
-	if (hashtab == NULL) {
-		return (NULL);
-	}
-	head = &(hashtab->head[key1 % MPTSAS_HASH_ARRAY_SIZE]);
-	cur = *head;
-	while (cur != NULL) {
-		data = cur->data;
-		if ((data->key1 == key1) && (data->key2 == key2)) {
-			if (last == NULL) {
-				(*head) = cur->next;
-			} else {
-				last->next = cur->next;
-			}
-			kmem_free(cur, sizeof (mptsas_hash_node_t));
-			return (data);
-		} else {
-			last = cur;
-			cur = cur->next;
-		}
-	}
-	return (NULL);
-}
-
-static void *
-mptsas_hash_search(mptsas_hash_table_t *hashtab, uint64_t key1,
-    mptsas_phymask_t key2)
-{
-	mptsas_hash_node_t *cur = NULL;
-	mptsas_hash_data_t *data;
-	if (hashtab == NULL) {
-		return (NULL);
-	}
-	cur = hashtab->head[key1 % MPTSAS_HASH_ARRAY_SIZE];
-	while (cur != NULL) {
-		data = cur->data;
-		if ((data->key1 == key1) && (data->key2 == key2)) {
-			return (data);
-		} else {
-			cur = cur->next;
-		}
-	}
-	return (NULL);
-}
-
-static void *
-mptsas_hash_traverse(mptsas_hash_table_t *hashtab, int pos)
-{
-	mptsas_hash_node_t *this = NULL;
-
-	if (hashtab == NULL) {
-		return (NULL);
-	}
-
-	if (pos == MPTSAS_HASH_FIRST) {
-		hashtab->line = 0;
-		hashtab->cur = NULL;
-		this = hashtab->head[0];
-	} else {
-		if (hashtab->cur == NULL) {
-			return (NULL);
-		} else {
-			this = hashtab->cur->next;
-		}
-	}
-
-	while (this == NULL) {
-		hashtab->line++;
-		if (hashtab->line >= MPTSAS_HASH_ARRAY_SIZE) {
-			/* the traverse reaches the end */
-			hashtab->cur = NULL;
-			return (NULL);
-		} else {
-			this = hashtab->head[hashtab->line];
-		}
-	}
-	hashtab->cur = this;
-	return (this->data);
-}
-
-/*
  * Functions for SGPIO LED support
  */
 static dev_info_t *
@@ -15361,27 +15345,31 @@
 	return (ptgt);
 }
 
-#ifdef MPTSAS_GET_LED
 static int
-mptsas_get_led_status(mptsas_t *mpt, mptsas_target_t *ptgt,
-    uint32_t *slotstatus)
+mptsas_flush_led_status(mptsas_t *mpt, mptsas_target_t *ptgt)
 {
-	return (mptsas_send_sep(mpt, ptgt, slotstatus,
-	    MPI2_SEP_REQ_ACTION_READ_STATUS));
-}
-#endif
-static int
-mptsas_set_led_status(mptsas_t *mpt, mptsas_target_t *ptgt, uint32_t slotstatus)
-{
+	uint32_t slotstatus = 0;
+
+	/* Build an MPI2 Slot Status based on our view of the world */
+	if (ptgt->m_led_status & (1 << (MPTSAS_LEDCTL_LED_IDENT - 1)))
+		slotstatus |= MPI2_SEP_REQ_SLOTSTATUS_IDENTIFY_REQUEST;
+	if (ptgt->m_led_status & (1 << (MPTSAS_LEDCTL_LED_FAIL - 1)))
+		slotstatus |= MPI2_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT;
+	if (ptgt->m_led_status & (1 << (MPTSAS_LEDCTL_LED_OK2RM - 1)))
+		slotstatus |= MPI2_SEP_REQ_SLOTSTATUS_REQUEST_REMOVE;
+
+	/* Write it to the controller */
 	NDBG14(("mptsas_ioctl: set LED status %x for slot %x",
 	    slotstatus, ptgt->m_slot_num));
 	return (mptsas_send_sep(mpt, ptgt, &slotstatus,
 	    MPI2_SEP_REQ_ACTION_WRITE_STATUS));
 }
+
 /*
  *  send sep request, use enclosure/slot addressing
  */
-static int mptsas_send_sep(mptsas_t *mpt, mptsas_target_t *ptgt,
+static int
+mptsas_send_sep(mptsas_t *mpt, mptsas_target_t *ptgt,
     uint32_t *status, uint8_t act)
 {
 	Mpi2SepRequest_t	req;
@@ -15390,15 +15378,27 @@
 
 	ASSERT(mutex_owned(&mpt->m_mutex));
 
+	/*
+	 * We only support SEP control of directly-attached targets, in which
+	 * case the "SEP" we're talking to is a virtual one contained within
+	 * the HBA itself.  This is necessary because DA targets typically have
+	 * no other mechanism for LED control.  Targets for which a separate
+	 * enclosure service processor exists should be controlled via ses(7d)
+	 * or sgen(7d).  Furthermore, since such requests can time out, they
+	 * should be made in user context rather than in response to
+	 * asynchronous fabric changes.
+	 *
+	 * In addition, we do not support this operation for RAID volumes,
+	 * since there is no slot associated with them.
+	 */
+	if (!(ptgt->m_deviceinfo & DEVINFO_DIRECT_ATTACHED) ||
+	    ptgt->m_addr.mta_phymask == 0) {
+		return (ENOTTY);
+	}
+
 	bzero(&req, sizeof (req));
 	bzero(&rep, sizeof (rep));
 
-	/* Do nothing for RAID volumes */
-	if (ptgt->m_phymask == 0) {
-		NDBG14(("mptsas_send_sep: Skip RAID volumes"));
-		return (DDI_FAILURE);
-	}
-
 	req.Function = MPI2_FUNCTION_SCSI_ENCLOSURE_PROCESSOR;
 	req.Action = act;
 	req.Flags = MPI2_SEP_REQ_FLAGS_ENCLOSURE_SLOT_ADDRESS;
@@ -15412,26 +15412,41 @@
 	if (ret != 0) {
 		mptsas_log(mpt, CE_NOTE, "mptsas_send_sep: passthru SEP "
 		    "Processor Request message error %d", ret);
-		return (DDI_FAILURE);
+		return (ret);
 	}
 	/* do passthrough success, check the ioc status */
 	if (LE_16(rep.IOCStatus) != MPI2_IOCSTATUS_SUCCESS) {
-		if ((LE_16(rep.IOCStatus) & MPI2_IOCSTATUS_MASK) ==
-		    MPI2_IOCSTATUS_INVALID_FIELD) {
-			mptsas_log(mpt, CE_NOTE, "send sep act %x: Not "
-			    "supported action, loginfo %x", act,
-			    LE_32(rep.IOCLogInfo));
-			return (DDI_FAILURE);
-		}
 		mptsas_log(mpt, CE_NOTE, "send_sep act %x: ioc "
-		    "status:%x", act, LE_16(rep.IOCStatus));
-		return (DDI_FAILURE);
+		    "status:%x loginfo %x", act, LE_16(rep.IOCStatus),
+		    LE_32(rep.IOCLogInfo));
+		switch (LE_16(rep.IOCStatus) & MPI2_IOCSTATUS_MASK) {
+		case MPI2_IOCSTATUS_INVALID_FUNCTION:
+		case MPI2_IOCSTATUS_INVALID_VPID:
+		case MPI2_IOCSTATUS_INVALID_FIELD:
+		case MPI2_IOCSTATUS_INVALID_STATE:
+		case MPI2_IOCSTATUS_OP_STATE_NOT_SUPPORTED:
+		case MPI2_IOCSTATUS_CONFIG_INVALID_ACTION:
+		case MPI2_IOCSTATUS_CONFIG_INVALID_TYPE:
+		case MPI2_IOCSTATUS_CONFIG_INVALID_PAGE:
+		case MPI2_IOCSTATUS_CONFIG_INVALID_DATA:
+		case MPI2_IOCSTATUS_CONFIG_NO_DEFAULTS:
+			return (EINVAL);
+		case MPI2_IOCSTATUS_BUSY:
+			return (EBUSY);
+		case MPI2_IOCSTATUS_INSUFFICIENT_RESOURCES:
+			return (EAGAIN);
+		case MPI2_IOCSTATUS_INVALID_SGL:
+		case MPI2_IOCSTATUS_INTERNAL_ERROR:
+		case MPI2_IOCSTATUS_CONFIG_CANT_COMMIT:
+		default:
+			return (EIO);
+		}
 	}
 	if (act != MPI2_SEP_REQ_ACTION_WRITE_STATUS) {
 		*status = LE_32(rep.SlotStatus);
 	}
 
-	return (DDI_SUCCESS);
+	return (0);
 }
 
 int
--- /dev/null	Wed May  7 17:09:52 2014
+++ new/usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas_hash.c	Wed May  7 17:09:52 2014
@@ -0,0 +1,215 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2014 Joyent, Inc.  All rights reserved.
+ */
+
+#include <sys/scsi/adapters/mpt_sas/mptsas_hash.h>
+#include <sys/sysmacros.h>
+#include <sys/types.h>
+#include <sys/kmem.h>
+#include <sys/list.h>
+#include <sys/ddi.h>
+
+#ifdef lint
+extern refhash_link_t *obj_to_link(refhash_t *, void *);
+extern void *link_to_obj(refhash_t *, refhash_link_t *);
+extern void *obj_to_tag(refhash_t *, void *);
+#else
+#define	obj_to_link(_h, _o)	\
+	((refhash_link_t *)(((char *)(_o)) + (_h)->rh_link_off))
+#define	link_to_obj(_h, _l)	\
+	((void *)(((char *)(_l)) - (_h)->rh_link_off))
+#define	obj_to_tag(_h, _o)	\
+	((void *)(((char *)(_o)) + (_h)->rh_tag_off))
+#endif
+
+refhash_t *
+refhash_create(uint_t bucket_count, refhash_hash_f hash,
+    refhash_cmp_f cmp, refhash_dtor_f dtor, size_t obj_size, size_t link_off,
+    size_t tag_off, int km_flags)
+{
+	refhash_t *hp;
+	uint_t i;
+
+	hp = kmem_alloc(sizeof (refhash_t), km_flags);
+	if (hp == NULL)
+		return (NULL);
+	hp->rh_buckets = kmem_zalloc(bucket_count * sizeof (list_t), km_flags);
+	if (hp->rh_buckets == NULL) {
+		kmem_free(hp, sizeof (refhash_t));
+		return (NULL);
+	}
+	hp->rh_bucket_count = bucket_count;
+
+	for (i = 0; i < bucket_count; i++) {
+		list_create(&hp->rh_buckets[i], sizeof (refhash_link_t),
+		    offsetof(refhash_link_t, rhl_chain_link));
+	}
+	list_create(&hp->rh_objs, sizeof (refhash_link_t),
+	    offsetof(refhash_link_t, rhl_global_link));
+
+	hp->rh_obj_size = obj_size;
+	hp->rh_link_off = link_off;
+	hp->rh_tag_off = tag_off;
+	hp->rh_hash = hash;
+	hp->rh_cmp = cmp;
+	hp->rh_dtor = dtor;
+
+	return (hp);
+}
+
+void
+refhash_destroy(refhash_t *hp)
+{
+	ASSERT(list_is_empty(&hp->rh_objs));
+
+	kmem_free(hp->rh_buckets, hp->rh_bucket_count * sizeof (list_t));
+	kmem_free(hp, sizeof (refhash_t));
+}
+
+void
+refhash_insert(refhash_t *hp, void *op)
+{
+	uint_t bucket;
+	refhash_link_t *lp = obj_to_link(hp, op);
+
+	bucket = hp->rh_hash(obj_to_tag(hp, op)) % hp->rh_bucket_count;
+	list_link_init(&lp->rhl_chain_link);
+	list_link_init(&lp->rhl_global_link);
+	lp->rhl_flags = 0;
+	lp->rhl_refcnt = 0;
+	list_insert_tail(&hp->rh_buckets[bucket], lp);
+	list_insert_tail(&hp->rh_objs, lp);
+}
+
+static void
+refhash_delete(refhash_t *hp, void *op)
+{
+	refhash_link_t *lp = obj_to_link(hp, op);
+	uint_t bucket;
+
+	bucket = hp->rh_hash(obj_to_tag(hp, op)) % hp->rh_bucket_count;
+	list_remove(&hp->rh_buckets[bucket], lp);
+	list_remove(&hp->rh_objs, lp);
+	hp->rh_dtor(op);
+}
+
+void
+refhash_remove(refhash_t *hp, void *op)
+{
+	refhash_link_t *lp = obj_to_link(hp, op);
+
+	if (lp->rhl_refcnt > 0) {
+		lp->rhl_flags |= RHL_F_DEAD;
+	} else {
+		refhash_delete(hp, op);
+	}
+}
+
+void *
+refhash_lookup(refhash_t *hp, const void *tp)
+{
+	uint_t bucket;
+	refhash_link_t *lp;
+	void *op;
+
+	bucket = hp->rh_hash(tp) % hp->rh_bucket_count;
+	for (lp = list_head(&hp->rh_buckets[bucket]); lp != NULL;
+	    lp = list_next(&hp->rh_buckets[bucket], lp)) {
+		op = link_to_obj(hp, lp);
+		if (hp->rh_cmp(obj_to_tag(hp, op), tp) == 0 &&
+		    !(lp->rhl_flags & RHL_F_DEAD)) {
+			return (op);
+		}
+	}
+
+	return (NULL);
+}
+
+void *
+refhash_linear_search(refhash_t *hp, refhash_eval_f eval, void *arg)
+{
+	void *op;
+	refhash_link_t *lp;
+
+	for (lp = list_head(&hp->rh_objs); lp != NULL;
+	    lp = list_next(&hp->rh_objs, lp)) {
+		op = link_to_obj(hp, lp);
+		if (eval(op, arg) == 0)
+			return (op);
+	}
+
+	return (NULL);
+}
+
+void
+refhash_hold(refhash_t *hp, void *op)
+{
+	refhash_link_t *lp = obj_to_link(hp, op);
+
+	++lp->rhl_refcnt;
+}
+
+void
+refhash_rele(refhash_t *hp, void *op)
+{
+	refhash_link_t *lp = obj_to_link(hp, op);
+
+	ASSERT(lp->rhl_refcnt > 0);
+
+	if (--lp->rhl_refcnt == 0 && (lp->rhl_flags & RHL_F_DEAD))
+		refhash_remove(hp, op);
+}
+
+void *
+refhash_first(refhash_t *hp)
+{
+	refhash_link_t *lp;
+
+	lp = list_head(&hp->rh_objs);
+	if (lp == NULL)
+		return (NULL);
+
+	++lp->rhl_refcnt;
+
+	return (link_to_obj(hp, lp));
+}
+
+void *
+refhash_next(refhash_t *hp, void *op)
+{
+	refhash_link_t *lp;
+
+	lp = obj_to_link(hp, op);
+	while ((lp = list_next(&hp->rh_objs, lp)) != NULL) {
+		if (!(lp->rhl_flags & RHL_F_DEAD))
+			break;
+	}
+
+	refhash_rele(hp, op);
+	if (lp == NULL)
+		return (NULL);
+
+	++lp->rhl_refcnt;
+
+	return (link_to_obj(hp, lp));
+}
+
+boolean_t
+refhash_obj_valid(refhash_t *hp, const void *op)
+{
+	/* LINTED - E_ARG_INCOMPATIBLE_WITH_ARG_L */
+	const refhash_link_t *lp = obj_to_link(hp, op);
+
+	return ((lp->rhl_flags & RHL_F_DEAD) != 0);
+}
--- old/usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas_impl.c	Wed May  7 17:09:52 2014
+++ new/usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas_impl.c	Wed May  7 17:09:52 2014
@@ -1529,7 +1529,7 @@
 	    MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
 	    MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER, 0, page_address,
 	    mptsas_sasexpdpage_0_cb, page_address, &info->m_devhdl,
-	    &info->m_sasaddr, &info->m_phymask, &info->m_pdevhdl);
+	    &info->m_addr.mta_wwn, &info->m_addr.mta_phymask, &info->m_pdevhdl);
 
 	return (rval);
 }
--- old/usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas_raid.c	Wed May  7 17:09:53 2014
+++ new/usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas_raid.c	Wed May  7 17:09:53 2014
@@ -91,7 +91,7 @@
 
 extern int mptsas_check_dma_handle(ddi_dma_handle_t handle);
 extern int mptsas_check_acc_handle(ddi_acc_handle_t handle);
-extern mptsas_target_t *mptsas_tgt_alloc(mptsas_hash_table_t *, uint16_t,
+extern mptsas_target_t *mptsas_tgt_alloc(mptsas_t *, uint16_t,
     uint64_t, uint32_t, mptsas_phymask_t, uint8_t);
 
 static int
@@ -110,7 +110,6 @@
 	uint16_t elementtype, voldevhandle;
 	uint16_t etype_vol, etype_pd, etype_hs;
 	uint16_t etype_oce;
-	mptsas_slots_t *slots = mpt->m_active;
 	m_raidconfig_t *raidconfig;
 	uint64_t raidwwn;
 	uint32_t native;
@@ -148,8 +147,8 @@
 	 * Point to the right config in the structure.
 	 * Increment the number of valid RAID configs.
 	 */
-	raidconfig = &slots->m_raidconfig[configindex];
-	slots->m_num_raid_configs++;
+	raidconfig = &mpt->m_raidconfig[configindex];
+	mpt->m_num_raid_configs++;
 
 	/*
 	 * Set the native flag if this is not a foreign
@@ -216,7 +215,7 @@
 			/*
 			 * RAID uses phymask of 0.
 			 */
-			ptgt = mptsas_tgt_alloc(&slots->m_tgttbl,
+			ptgt = mptsas_tgt_alloc(mpt,
 			    voldevhandle, raidwwn, 0, 0, 0);
 
 			raidconfig->m_raidvol[vol].m_raidtgt =
@@ -258,7 +257,6 @@
 	int rval = DDI_SUCCESS;
 	uint32_t confignum, pageaddress;
 	uint8_t configindex;
-	mptsas_slots_t *slots = mpt->m_active;
 
 	ASSERT(mutex_owned(&mpt->m_mutex));
 
@@ -265,8 +263,8 @@
 	/*
 	 * Clear all RAID info before starting.
 	 */
-	bzero(slots->m_raidconfig, sizeof (slots->m_raidconfig));
-	slots->m_num_raid_configs = 0;
+	bzero(mpt->m_raidconfig, sizeof (mpt->m_raidconfig));
+	mpt->m_num_raid_configs = 0;
 
 	configindex = 0;
 	confignum = 0xff;
@@ -466,7 +464,6 @@
 		raidvol->m_raidwwid = sas_wwn;
 	}
 
-done:
 	return (rval);
 }
 
@@ -586,10 +583,10 @@
 	 * supports IR and make sure there is a valid volume for the request.
 	 */
 	if (mpt->m_ir_capable) {
-		for (config = 0; (config < slots->m_num_raid_configs) &&
+		for (config = 0; (config < mpt->m_num_raid_configs) &&
 		    (!ir_active); config++) {
 			for (vol = 0; vol < MPTSAS_MAX_RAIDVOLS; vol++) {
-				if (slots->m_raidconfig[config].m_raidvol[vol].
+				if (mpt->m_raidconfig[config].m_raidvol[vol].
 				    m_israid) {
 					ir_active = TRUE;
 					break;
@@ -758,12 +755,11 @@
 mptsas_delete_volume(mptsas_t *mpt, uint16_t volid)
 {
 	int		config, i = 0, vol = (-1);
-	mptsas_slots_t	*slots = mpt->m_active;
 
-	for (config = 0; (config < slots->m_num_raid_configs) && (vol != i);
+	for (config = 0; (config < mpt->m_num_raid_configs) && (vol != i);
 	    config++) {
 		for (i = 0; i < MPTSAS_MAX_RAIDVOLS; i++) {
-			if (slots->m_raidconfig[config].m_raidvol[i].
+			if (mpt->m_raidconfig[config].m_raidvol[i].
 			    m_raidhandle == volid) {
 				vol = i;
 				break;
@@ -777,11 +773,11 @@
 		return (-1);
 	}
 
-	slots->m_raidconfig[config].m_raidvol[vol].m_israid = 0;
-	slots->m_raidconfig[config].m_raidvol[vol].m_ndisks = 0;
+	mpt->m_raidconfig[config].m_raidvol[vol].m_israid = 0;
+	mpt->m_raidconfig[config].m_raidvol[vol].m_ndisks = 0;
 	for (i = 0; i < MPTSAS_MAX_DISKS_IN_VOL; i++) {
-		slots->m_raidconfig[config].m_raidvol[vol].m_disknum[i] = 0;
-		slots->m_raidconfig[config].m_raidvol[vol].m_devhdl[i] = 0;
+		mpt->m_raidconfig[config].m_raidvol[vol].m_disknum[i] = 0;
+		mpt->m_raidconfig[config].m_raidvol[vol].m_devhdl[i] = 0;
 	}
 
 	return (0);
--- old/usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas_smhba.c	Wed May  7 17:09:53 2014
+++ new/usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas_smhba.c	Wed May  7 17:09:53 2014
@@ -21,6 +21,7 @@
 
 /*
  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
  */
 /*
  * This file contains SM-HBA support for MPT SAS driver
@@ -59,6 +60,11 @@
  */
 extern char *mptsas_driver_rev;
 
+static void mptsas_smhba_create_phy_props(nvlist_t **, smhba_info_t *, uint8_t,
+    uint16_t *);
+static void mptsas_smhba_update_phy_props(mptsas_t *, dev_info_t *, nvlist_t **,
+    uint8_t);
+
 static void
 mptsas_smhba_add_hba_prop(mptsas_t *mpt, data_type_t dt,
     char *prop_name, void *prop_val);
@@ -116,79 +122,48 @@
 	}
 }
 
-void
-mptsas_smhba_set_phy_props(mptsas_t *mpt, char *iport, dev_info_t *dip,
-    uint8_t phy_nums, uint16_t *attached_devhdl)
+static void
+mptsas_smhba_create_phy_props(nvlist_t **phy_props, smhba_info_t *pSmhba,
+    uint8_t phy_id, uint16_t *attached_devhdl)
 {
-	int		i;
-	int		j = 0;
+	(void) nvlist_alloc(phy_props, NV_UNIQUE_NAME, KM_SLEEP);
+	(void) nvlist_add_uint8(*phy_props, SAS_PHY_ID, phy_id);
+	(void) nvlist_add_uint8(*phy_props, "phyState",
+	    (pSmhba->negotiated_link_rate & 0x0f));
+	(void) nvlist_add_int8(*phy_props, SAS_NEG_LINK_RATE,
+	    (pSmhba->negotiated_link_rate & 0x0f));
+	(void) nvlist_add_int8(*phy_props, SAS_PROG_MIN_LINK_RATE,
+	    (pSmhba->programmed_link_rate & 0x0f));
+	(void) nvlist_add_int8(*phy_props, SAS_HW_MIN_LINK_RATE,
+	    (pSmhba->hw_link_rate & 0x0f));
+	(void) nvlist_add_int8(*phy_props, SAS_PROG_MAX_LINK_RATE,
+	    ((pSmhba->programmed_link_rate & 0xf0) >> 4));
+	(void) nvlist_add_int8(*phy_props, SAS_HW_MAX_LINK_RATE,
+	    ((pSmhba->hw_link_rate & 0xf0) >> 4));
+
+	if (pSmhba->attached_devhdl && (attached_devhdl != NULL))
+		*attached_devhdl = pSmhba->attached_devhdl;
+}
+
+static void
+mptsas_smhba_update_phy_props(mptsas_t *mpt, dev_info_t *dip,
+    nvlist_t **phy_props, uint8_t phy_nums)
+{
 	int		rval;
 	size_t		packed_size;
 	char		*packed_data = NULL;
-	char		phymask[MPTSAS_MAX_PHYS];
-	nvlist_t	**phy_props;
 	nvlist_t	*nvl;
-	smhba_info_t	*pSmhba = NULL;
 
-	if (phy_nums == 0) {
+	if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP) != 0) {
+		mptsas_log(mpt, CE_WARN, "%s: nvlist_alloc() failed", __func__);
 		return;
 	}
-	if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) {
-		mptsas_log(mpt, CE_WARN, "%s: nvlist_alloc() failed", __func__);
-	}
 
-	phy_props = kmem_zalloc(sizeof (nvlist_t *) * phy_nums,
-	    KM_SLEEP);
-
-	for (i = 0; i < mpt->m_num_phys; i++) {
-
-		bzero(phymask, sizeof (phymask));
-		(void) sprintf(phymask, "%x", mpt->m_phy_info[i].phy_mask);
-		if (strcmp(phymask, iport) == 0) {
-			pSmhba = &mpt->m_phy_info[i].smhba_info;
-			(void) nvlist_alloc(&phy_props[j], NV_UNIQUE_NAME, 0);
-			(void) nvlist_add_uint8(phy_props[j], SAS_PHY_ID, i);
-			(void) nvlist_add_uint8(phy_props[j],
-			    "phyState",
-			    (pSmhba->negotiated_link_rate
-			    & 0x0f));
-			(void) nvlist_add_int8(phy_props[j],
-			    SAS_NEG_LINK_RATE,
-			    (pSmhba->negotiated_link_rate
-			    & 0x0f));
-			(void) nvlist_add_int8(phy_props[j],
-			    SAS_PROG_MIN_LINK_RATE,
-			    (pSmhba->programmed_link_rate
-			    & 0x0f));
-			(void) nvlist_add_int8(phy_props[j],
-			    SAS_HW_MIN_LINK_RATE,
-			    (pSmhba->hw_link_rate
-			    & 0x0f));
-			(void) nvlist_add_int8(phy_props[j],
-			    SAS_PROG_MAX_LINK_RATE,
-			    ((pSmhba->programmed_link_rate
-			    & 0xf0) >> 4));
-			(void) nvlist_add_int8(phy_props[j],
-			    SAS_HW_MAX_LINK_RATE,
-			    ((pSmhba->hw_link_rate
-			    & 0xf0) >> 4));
-
-			j++;
-
-			if (pSmhba->attached_devhdl &&
-			    (attached_devhdl != NULL)) {
-				*attached_devhdl =
-				    pSmhba->attached_devhdl;
-			}
-		}
-	}
-
 	rval = nvlist_add_nvlist_array(nvl, SAS_PHY_INFO_NVL, phy_props,
 	    phy_nums);
 	if (rval) {
 		mptsas_log(mpt, CE_WARN,
-		    " nv list array add failed, return value %d.",
-		    rval);
+		    " nv list array add failed, return value %d.", rval);
 		goto exit;
 	}
 	(void) nvlist_size(nvl, &packed_size, NV_ENCODE_NATIVE);
@@ -200,11 +175,7 @@
 	    SAS_PHY_INFO, (uchar_t *)packed_data, packed_size);
 
 exit:
-	for (i = 0; i < phy_nums && phy_props[i] != NULL; i++) {
-		nvlist_free(phy_props[i]);
-	}
 	nvlist_free(nvl);
-	kmem_free(phy_props, sizeof (nvlist_t *) * phy_nums);
 
 	if (packed_data != NULL) {
 		kmem_free(packed_data, packed_size);
@@ -211,6 +182,47 @@
 	}
 }
 
+void
+mptsas_smhba_set_one_phy_props(mptsas_t *mpt, dev_info_t *dip, uint8_t phy_id,
+    uint16_t *attached_devhdl)
+{
+	nvlist_t	*phy_props;
+
+	ASSERT(phy_id < mpt->m_num_phys);
+
+	mptsas_smhba_create_phy_props(&phy_props,
+	    &mpt->m_phy_info[phy_id].smhba_info, phy_id, attached_devhdl);
+
+	mptsas_smhba_update_phy_props(mpt, dip, &phy_props, 1);
+
+	nvlist_free(phy_props);
+}
+
+void
+mptsas_smhba_set_all_phy_props(mptsas_t *mpt, dev_info_t *dip, uint8_t phy_nums,
+    mptsas_phymask_t phy_mask, uint16_t *attached_devhdl)
+{
+	int		i, j;
+	nvlist_t	**phy_props;
+
+	if (phy_nums == 0)
+		return;
+
+	phy_props = kmem_zalloc(sizeof (nvlist_t *) * phy_nums, KM_SLEEP);
+
+	for (i = 0, j = 0; i < mpt->m_num_phys && j < phy_nums; i++)
+		if (phy_mask == mpt->m_phy_info[i].phy_mask)
+			mptsas_smhba_create_phy_props(&phy_props[j++],
+			    &mpt->m_phy_info[i].smhba_info, i, attached_devhdl);
+
+	mptsas_smhba_update_phy_props(mpt, dip, phy_props, j);
+
+	for (i = 0; i < j && phy_props[i] != NULL; i++)
+		nvlist_free(phy_props[i]);
+
+	kmem_free(phy_props, sizeof (nvlist_t *) * phy_nums);
+}
+
 /*
  * Called with PHY lock held on phyp
  */
--- old/usr/src/uts/common/sys/lpif.h	Wed May  7 17:09:53 2014
+++ new/usr/src/uts/common/sys/lpif.h	Wed May  7 17:09:53 2014
@@ -20,6 +20,7 @@
  */
 /*
  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013 by Delphix. All rights reserved.
  */
 #ifndef	_LPIF_H
 #define	_LPIF_H
@@ -131,9 +132,6 @@
 stmf_status_t stmf_set_lu_access(stmf_lu_t *lup, uint8_t access_state);
 stmf_status_t stmf_proxy_scsi_cmd(scsi_task_t *, stmf_data_buf_t *dbuf);
 int stmf_is_standby_port(scsi_task_t *);
-void stmf_lu_xfer_start(struct scsi_task *task);
-void stmf_lu_xfer_done(struct scsi_task *task, boolean_t read,
-    uint64_t xfer_bytes, hrtime_t elapsed_time);
 
 #ifdef	__cplusplus
 }
--- /dev/null	Wed May  7 17:09:53 2014
+++ new/usr/src/uts/common/sys/scsi/adapters/mpt_sas/mptsas_hash.h	Wed May  7 17:09:53 2014
@@ -0,0 +1,61 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2014 Joyent, Inc.  All rights reserved.
+ */
+
+#ifndef	_SYS_SCSI_ADAPTERS_MPTHASH_H
+#define	_SYS_SCSI_ADAPTERS_MPTHASH_H
+
+#include <sys/types.h>
+#include <sys/list.h>
+
+#define	RHL_F_DEAD	0x01
+
+typedef struct refhash_link {
+	list_node_t rhl_chain_link;
+	list_node_t rhl_global_link;
+	uint_t rhl_flags;
+	uint_t rhl_refcnt;
+} refhash_link_t;
+
+typedef uint64_t (*refhash_hash_f)(const void *);
+typedef int (*refhash_cmp_f)(const void *, const void *);
+typedef void (*refhash_dtor_f)(void *);
+typedef int (*refhash_eval_f)(const void *, void *);
+
+typedef struct refhash {
+	list_t *rh_buckets;
+	uint_t rh_bucket_count;
+	list_t rh_objs;
+	size_t rh_obj_size;	/* used by mdb */
+	size_t rh_link_off;
+	size_t rh_tag_off;
+	refhash_hash_f rh_hash;
+	refhash_cmp_f rh_cmp;
+	refhash_dtor_f rh_dtor;
+} refhash_t;
+
+extern refhash_t *refhash_create(uint_t, refhash_hash_f, refhash_cmp_f,
+    refhash_dtor_f, size_t, size_t, size_t, int);
+extern void refhash_destroy(refhash_t *);
+extern void refhash_insert(refhash_t *, void *);
+extern void refhash_remove(refhash_t *, void *);
+extern void *refhash_lookup(refhash_t *, const void *);
+extern void *refhash_linear_search(refhash_t *, refhash_eval_f, void *);
+extern void refhash_hold(refhash_t *, void *);
+extern void refhash_rele(refhash_t *, void *);
+extern void *refhash_first(refhash_t *);
+extern void *refhash_next(refhash_t *, void *);
+extern boolean_t refhash_obj_valid(refhash_t *hp, const void *);
+
+#endif	/* _SYS_SCSI_ADAPTERS_MPTHASH_H */
--- old/usr/src/uts/common/sys/scsi/adapters/mpt_sas/mptsas_ioctl.h	Wed May  7 17:09:53 2014
+++ new/usr/src/uts/common/sys/scsi/adapters/mpt_sas/mptsas_ioctl.h	Wed May  7 17:09:53 2014
@@ -23,6 +23,9 @@
  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
+/*
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ */
 
 /*
  * Copyright (c) 2000 to 2010, LSI Corporation.
@@ -71,6 +74,8 @@
 #define	MPTIOCTL_GET_PCI_INFO		(MPTIOCTL | 8)
 #define	MPTIOCTL_DIAG_ACTION		(MPTIOCTL | 9)
 #define	MPTIOCTL_REG_ACCESS		(MPTIOCTL | 10)
+#define	MPTIOCTL_GET_DISK_INFO		(MPTIOCTL | 11)
+#define	MPTIOCTL_LED_CONTROL		(MPTIOCTL | 12)
 
 /*
  *  The following are our ioctl() return status values.  If everything went
@@ -296,6 +301,58 @@
 	uint32_t	RegData;
 } mptsas_reg_access_t;
 
+/*
+ * Disk Toplogy Information
+ */
+typedef struct mptsas_disk_info
+{
+	uint64_t	SasAddress;
+	uint16_t	Instance;
+	uint16_t	Enclosure;
+	uint16_t	Slot;
+} mptsas_disk_info_t;
+
+typedef struct mptsas_get_disk_info
+{
+	uint16_t		DiskCount;
+	mptsas_disk_info_t	*PtrDiskInfoArray;
+	uint64_t		DiskInfoArraySize;
+} mptsas_get_disk_info_t;
+
+#ifdef _KERNEL
+
+typedef struct mptsas_get_disk_info32
+{
+	uint16_t		DiskCount;
+	caddr32_t		PtrDiskInfoArray;
+	uint64_t		DiskInfoArraySize;
+} mptsas_get_disk_info32_t;
+
+#endif /* _KERNEL */
+
+/*
+ * LED Control
+ */
+
+typedef struct mptsas_led_control
+{
+	uint8_t		Command;
+	uint16_t	Enclosure;
+	uint16_t	Slot;
+	uint8_t		Led;
+	uint8_t		LedStatus;
+} mptsas_led_control_t;
+
+#define	MPTSAS_LEDCTL_FLAG_SET		1
+#define	MPTSAS_LEDCTL_FLAG_GET		2
+
+#define	MPTSAS_LEDCTL_LED_IDENT		1
+#define	MPTSAS_LEDCTL_LED_FAIL		2
+#define	MPTSAS_LEDCTL_LED_OK2RM		3
+
+#define	MPTSAS_LEDCTL_LED_MIN		MPTSAS_LEDCTL_LED_IDENT
+#define	MPTSAS_LEDCTL_LED_MAX		MPTSAS_LEDCTL_LED_OK2RM
+
 #ifdef  __cplusplus
 }
 #endif
--- old/usr/src/uts/common/sys/scsi/adapters/mpt_sas/mptsas_smhba.h	Wed May  7 17:09:53 2014
+++ new/usr/src/uts/common/sys/scsi/adapters/mpt_sas/mptsas_smhba.h	Wed May  7 17:09:53 2014
@@ -21,6 +21,7 @@
 
 /*
  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
  */
 
 /*
@@ -63,8 +64,10 @@
  */
 int mptsas_smhba_setup(mptsas_t *);
 void mptsas_smhba_show_phy_info(mptsas_t *);
-void mptsas_smhba_set_phy_props(mptsas_t *mpt, char *iport, dev_info_t *dip,
-    uint8_t phy_nums, uint16_t *attached_devhdl);
+void mptsas_smhba_set_all_phy_props(mptsas_t *mpt, dev_info_t *dip,
+    uint8_t phy_nums, mptsas_phymask_t phy_mask, uint16_t *attached_devhdl);
+void mptsas_smhba_set_one_phy_props(mptsas_t *mpt, dev_info_t *dip,
+    uint8_t phy_id, uint16_t *attached_devhdl);
 void mptsas_smhba_log_sysevent(mptsas_t *mpt, char *subclass, char *etype,
     smhba_info_t *phyp);
 void
--- old/usr/src/uts/common/sys/scsi/adapters/mpt_sas/mptsas_var.h	Wed May  7 17:09:53 2014
+++ new/usr/src/uts/common/sys/scsi/adapters/mpt_sas/mptsas_var.h	Wed May  7 17:09:53 2014
@@ -22,6 +22,7 @@
 /*
  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
  * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
  */
 
 /*
@@ -58,6 +59,7 @@
 #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>
@@ -89,6 +91,15 @@
 #define	MPTSAS_SATA_GUID	"sata-guid"
 
 /*
+ * Hash table sizes for SMP targets (i.e., expanders) and ordinary SSP/STP
+ * targets.  There's no need to go overboard here, as the ordinary paths for
+ * I/O do not normally require hashed target lookups.  These should be good
+ * enough and then some for any fabric within the hardware's capabilities.
+ */
+#define	MPTSAS_SMP_BUCKET_COUNT		23
+#define	MPTSAS_TARGET_BUCKET_COUNT	97
+
+/*
  * MPT HW defines
  */
 #define	MPTSAS_MAX_DISKS_IN_CONFIG	14
@@ -184,14 +195,15 @@
 #define	MPTSAS_RAID_WWID(wwid) \
 	((wwid & 0x0FFFFFFFFFFFFFFF) | 0x3000000000000000)
 
+typedef struct mptsas_target_addr {
+	uint64_t mta_wwn;
+	mptsas_phymask_t mta_phymask;
+} mptsas_target_addr_t;
+
 typedef	struct mptsas_target {
-		uint64_t		m_sas_wwn;	/* hash key1 */
-		mptsas_phymask_t	m_phymask;	/* hash key2 */
-		/*
-		 * m_dr_flag is a flag for DR, make sure the member
-		 * take the place of dr_flag of mptsas_hash_data.
-		 */
-		uint8_t			m_dr_flag;	/* dr_flag */
+		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;
@@ -208,27 +220,23 @@
 		uint16_t		m_enclosure;
 		uint16_t		m_slot_num;
 		uint32_t		m_tgt_unconfigured;
+		uint8_t			m_led_status;
 
 } mptsas_target_t;
 
+/*
+ * If you change this structure, be sure that mptsas_smp_target_copy()
+ * does the right thing.
+ */
 typedef struct mptsas_smp {
-	uint64_t	m_sasaddr;	/* hash key1 */
-	mptsas_phymask_t m_phymask;	/* hash key2 */
-	uint8_t		reserved1;
-	uint16_t	m_devhdl;
-	uint32_t	m_deviceinfo;
-	uint16_t	m_pdevhdl;
-	uint32_t	m_pdevinfo;
+	mptsas_target_addr_t	m_addr;
+	refhash_link_t		m_link;
+	uint16_t		m_devhdl;
+	uint32_t		m_deviceinfo;
+	uint16_t		m_pdevhdl;
+	uint32_t		m_pdevinfo;
 } mptsas_smp_t;
 
-typedef struct mptsas_hash_data {
-	uint64_t	key1;
-	mptsas_phymask_t key2;
-	uint8_t		dr_flag;
-	uint16_t	devhdl;
-	uint32_t	device_info;
-} mptsas_hash_data_t;
-
 typedef struct mptsas_cache_frames {
 	ddi_dma_handle_t m_dma_hdl;
 	ddi_acc_handle_t m_acc_hdl;
@@ -443,17 +451,24 @@
 } m_raidconfig_t;
 
 /*
- * Structure to hold active outstanding cmds.  Also, keep
- * timeout on a per target basis.
+ * Track outstanding commands.  The index into the m_slot array is the SMID
+ * (system message ID) of the outstanding command.  SMID 0 is reserved by the
+ * software/firmware protocol and is never used for any command we generate;
+ * as such, the assertion m_slot[0] == NULL is universally true.  The last
+ * entry in the array is slot number MPTSAS_TM_SLOT(mpt) and is used ONLY for
+ * task management commands.  No normal SCSI or ATA command will ever occupy
+ * that slot.  Finally, the relationship m_slot[X]->cmd_slot == X holds at any
+ * time that a consistent view of the target array is obtainable.
+ *
+ * As such, m_n_normal is the maximum number of slots available to ordinary
+ * commands, and the relationship:
+ * mpt->m_active->m_n_normal == mpt->m_max_requests - 2
+ * always holds after initialisation.
  */
 typedef struct mptsas_slots {
-	mptsas_hash_table_t	m_tgttbl;
-	mptsas_hash_table_t	m_smptbl;
-	m_raidconfig_t		m_raidconfig[MPTSAS_MAX_RAIDCONFIGS];
-	uint8_t			m_num_raid_configs;
-	uint16_t		m_tags;
-	size_t			m_size;
-	uint16_t		m_n_slots;
+	size_t			m_size;		/* size of struct, bytes */
+	uint_t			m_n_normal;	/* see above */
+	uint_t			m_rotor;	/* next slot idx to consider */
 	mptsas_cmd_t		*m_slot[1];
 } mptsas_slots_t;
 
@@ -671,6 +686,12 @@
 	 */
 	uint_t		m_softstate;
 
+	refhash_t	*m_targets;
+	refhash_t	*m_smp_targets;
+
+	m_raidconfig_t	m_raidconfig[MPTSAS_MAX_RAIDCONFIGS];
+	uint8_t		m_num_raid_configs;
+
 	struct mptsas_slots *m_active;	/* outstanding cmds */
 
 	mptsas_cmd_t	*m_waitq;	/* cmd queue for active request */
--- old/usr/src/uts/common/sys/stmf.h	Wed May  7 17:09:53 2014
+++ new/usr/src/uts/common/sys/stmf.h	Wed May  7 17:09:53 2014
@@ -20,6 +20,7 @@
  */
 /*
  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013 by Delphix. All rights reserved.
  */
 #ifndef	_STMF_H
 #define	_STMF_H
@@ -384,8 +385,6 @@
 stmf_status_t stmf_ctl(int cmd, void *obj, void *arg);
 stmf_status_t stmf_register_itl_handle(struct stmf_lu *lu, uint8_t *lun,
     struct stmf_scsi_session *ss, uint64_t session_id, void *itl_handle);
-stmf_status_t stmf_deregister_itl_handle(struct stmf_lu *lu, uint8_t *lun,
-    struct stmf_scsi_session *ss, uint64_t session_id, void *itl_handle);
 stmf_status_t stmf_deregister_all_lu_itl_handles(struct stmf_lu *lu);
 stmf_status_t stmf_get_itl_handle(struct stmf_lu *lu, uint8_t *lun,
     struct stmf_scsi_session *ss, uint64_t session_id, void **itl_handle_retp);
--- old/usr/src/uts/intel/mpt_sas/Makefile	Wed May  7 17:09:53 2014
+++ new/usr/src/uts/intel/mpt_sas/Makefile	Wed May  7 17:09:53 2014
@@ -62,7 +62,6 @@
 
 CERRWARN	+= -_gcc=-Wno-parentheses
 CERRWARN	+= -_gcc=-Wno-uninitialized
-CERRWARN	+= -_gcc=-Wno-unused-label
 CERRWARN	+= -_gcc=-Wno-switch
 
 #
--- old/usr/src/uts/sparc/mpt_sas/Makefile	Wed May  7 17:09:53 2014
+++ new/usr/src/uts/sparc/mpt_sas/Makefile	Wed May  7 17:09:53 2014
@@ -67,7 +67,6 @@
 
 CERRWARN	+= -_gcc=-Wno-parentheses
 CERRWARN	+= -_gcc=-Wno-uninitialized
-CERRWARN	+= -_gcc=-Wno-unused-label
 CERRWARN	+= -_gcc=-Wno-switch
 
 #
