--- old/usr/src/lib/fm/topo/modules/common/disk/Makefile	2013-03-07 19:48:51.676974965 +0000
+++ new/usr/src/lib/fm/topo/modules/common/disk/Makefile	2013-03-07 19:48:51.682682183 +0000
@@ -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	2013-03-07 19:48:51.800181502 +0000
+++ new/usr/src/lib/fm/topo/modules/common/disk/disk.c	2013-03-07 19:48:51.805893002 +0000
@@ -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,13 +47,38 @@
 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,
     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	2013-03-07 19:48:51.925884826 +0000
+++ new/usr/src/lib/fm/topo/modules/common/disk/disk.h	2013-03-07 19:48:51.931521678 +0000
@@ -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,6 +57,15 @@
  */
 #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.
--- /dev/null	2013-03-07 19:48:52.000000000 +0000
+++ new/usr/src/lib/fm/topo/modules/common/disk/disk_drivers.h	2013-03-07 19:48:52.055912678 +0000
@@ -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	2013-03-07 19:48:52.000000000 +0000
+++ new/usr/src/lib/fm/topo/modules/common/disk/disk_mptsas.c	2013-03-07 19:48:52.115864800 +0000
@@ -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));
+
+}
--- old/usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas.c	2013-03-07 19:48:52.173505923 +0000
+++ new/usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas.c	2013-03-07 19:48:52.179659701 +0000
@@ -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.
  */
 
 /*
@@ -69,6 +70,7 @@
 #include <sys/file.h>
 #include <sys/cpuvar.h>
 #include <sys/policy.h>
+#include <sys/model.h>
 #include <sys/sysevent.h>
 #include <sys/sysevent/eventdefs.h>
 #include <sys/sysevent/dr.h>
@@ -11951,6 +11953,96 @@
 }
 
 static int
+get_disk_info(mptsas_t *mpt, intptr_t data, int mode)
+{
+	int i = 0;
+	int count = 0;
+	int ret = 0;
+	mptsas_target_t *ptgt;
+	mptsas_disk_info_t *di;
+	STRUCT_DECL(mptsas_get_disk_info, gdi);
+
+	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);
+	ptgt = (mptsas_target_t *)mptsas_hash_traverse(&mpt->m_active->m_tgttbl,
+	    MPTSAS_HASH_FIRST);
+	while (ptgt != NULL) {
+		count++;
+		ptgt = (mptsas_target_t *)mptsas_hash_traverse(
+		    &mpt->m_active->m_tgttbl, MPTSAS_HASH_NEXT);
+	}
+	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);
+	ptgt = (mptsas_target_t *)mptsas_hash_traverse(&mpt->m_active->m_tgttbl,
+	    MPTSAS_HASH_FIRST);
+	while (ptgt != NULL) {
+		if (i >= count) {
+			/*
+			 * The number of targets changed while we weren't
+			 * looking, so give up.
+			 */
+			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_sas_wwn;
+
+		ptgt = (mptsas_target_t *)mptsas_hash_traverse(
+		    &mpt->m_active->m_tgttbl, MPTSAS_HASH_NEXT);
+		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)
 {
@@ -12071,6 +12163,9 @@
 		goto out;
 	}
 	switch (cmd) {
+		case MPTIOCTL_GET_DISK_INFO:
+			status = get_disk_info(mpt, data, mode);
+			break;
 		case MPTIOCTL_UPDATE_FLASH:
 			if (ddi_copyin((void *)data, &flashdata,
 				sizeof (struct mptsas_update_flash), mode)) {
--- old/usr/src/uts/common/sys/scsi/adapters/mpt_sas/mptsas_ioctl.h	2013-03-07 19:48:52.647034128 +0000
+++ new/usr/src/uts/common/sys/scsi/adapters/mpt_sas/mptsas_ioctl.h	2013-03-07 19:48:52.652724952 +0000
@@ -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,7 @@
 #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)
 
 /*
  *  The following are our ioctl() return status values.  If everything went
@@ -296,6 +300,35 @@
 	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 */
+
 #ifdef  __cplusplus
 }
 #endif
