PSARC/2009/019 SAS Management Protocol library
authorHyon Kim <Hyon.Kim@Sun.COM>
Sun, 11 Apr 2010 11:20:12 -0700
changeset 12126 60364f3f65c7
parent 12125 5f4c01af2e82
child 12127 222a61afc336
PSARC/2009/019 SAS Management Protocol library 6791689 need a userland mechanism for access to smp(7D) targets 6901865 need to enumerate SAS expanders in storage enclosures 6927621 need to enumerate receptacles around SAS expanders in storage enclosures 6927623 need representation of SAS HBA receptacles in topo tree 6934815 should add scsi-device and smp-device nodes beneath hba/iport nodes in topology 6791643 libses needs to link with libumem 6791646 ses2 ucode upload should allow selection of chunk size 6791730 libscsi and friends mishandle plugin paths with multiple candidates 6831769 fmd dumps core repeatedly in libses with huge enclosure 6863967 substring and subhelp pages ignored due to length mishandling 6900516 add support for SPMS-1 rev 111 SUBCHASSIS ID 6900520 ses topo enumerator ignores some enclosures 6900856 need SES_PROP_INTERNAL workaround for X4275 6901298 libscsi should work around devices intolerant of odd INQUIRY lengths 6900822 SUN libses plugin should support FRUID page 6905410 memory handling problems in libfruraw and libnvfru 6905409 use after free in libfruraw fru_close_container()
exception_lists/packaging
usr/src/cmd/scsi/Makefile
usr/src/cmd/scsi/smp/Makefile
usr/src/cmd/scsi/smp/Makefile.com
usr/src/cmd/scsi/smp/common/smp.c
usr/src/cmd/scsi/smp/i386/Makefile
usr/src/cmd/scsi/smp/sparc/Makefile
usr/src/lib/Makefile
usr/src/lib/fm/Makefile
usr/src/lib/fm/topo/libtopo/common/hc.c
usr/src/lib/fm/topo/libtopo/common/topo_hc.h
usr/src/lib/fm/topo/modules/common/disk/disk.c
usr/src/lib/fm/topo/modules/common/disk/disk.h
usr/src/lib/fm/topo/modules/common/disk/disk_common.c
usr/src/lib/fm/topo/modules/common/pcibus/did_props.h
usr/src/lib/fm/topo/modules/common/pcibus/pcibus.c
usr/src/lib/fm/topo/modules/common/pcibus/pcibus_hba.c
usr/src/lib/fm/topo/modules/common/ses/ses.c
usr/src/lib/fm/topo/modules/common/ses/ses.h
usr/src/lib/fm/topo/modules/i86pc/pcibus/Makefile
usr/src/lib/fm/topo/modules/sun4/pcibus/Makefile.pci
usr/src/lib/libfru/libfruraw/fruraw.c
usr/src/lib/libfru/libfruraw/raw_access.c
usr/src/lib/libfru/libnvfru/nvfru.c
usr/src/lib/scsi/Makefile
usr/src/lib/scsi/Makefile.rootdirs
usr/src/lib/scsi/libscsi/common/libscsi.h
usr/src/lib/scsi/libscsi/common/scsi_engine.c
usr/src/lib/scsi/libscsi/common/scsi_subr.c
usr/src/lib/scsi/libses/Makefile.defs
usr/src/lib/scsi/libses/common/libses_plugin.h
usr/src/lib/scsi/libses/common/ses_node.c
usr/src/lib/scsi/libses/common/ses_plugin.c
usr/src/lib/scsi/libses/common/ses_snap.c
usr/src/lib/scsi/libsmp/Makefile
usr/src/lib/scsi/libsmp/Makefile.com
usr/src/lib/scsi/libsmp/amd64/Makefile
usr/src/lib/scsi/libsmp/common/libsmp.h
usr/src/lib/scsi/libsmp/common/libsmp_plugin.h
usr/src/lib/scsi/libsmp/common/mkerrno.sh
usr/src/lib/scsi/libsmp/common/smp_engine.c
usr/src/lib/scsi/libsmp/common/smp_impl.h
usr/src/lib/scsi/libsmp/common/smp_plugin.c
usr/src/lib/scsi/libsmp/common/smp_subr.c
usr/src/lib/scsi/libsmp/i386/Makefile
usr/src/lib/scsi/libsmp/libsmp_api.map
usr/src/lib/scsi/libsmp/llib-lsmp
usr/src/lib/scsi/libsmp/mapfile-vers
usr/src/lib/scsi/libsmp/sparc/Makefile
usr/src/lib/scsi/libsmp/sparcv9/Makefile
usr/src/lib/scsi/plugins/Makefile
usr/src/lib/scsi/plugins/ses/LSILOGIC-SASX28-A.0/Makefile.com
usr/src/lib/scsi/plugins/ses/SUN/Makefile
usr/src/lib/scsi/plugins/ses/SUN/Makefile.com
usr/src/lib/scsi/plugins/ses/SUN/common/sun.c
usr/src/lib/scsi/plugins/ses/SUN/common/sun.h
usr/src/lib/scsi/plugins/ses/SUN/common/sun_element.c
usr/src/lib/scsi/plugins/ses/SUN/common/sun_enclosure.c
usr/src/lib/scsi/plugins/ses/SUN/common/sun_impl.h
usr/src/lib/scsi/plugins/ses/SUN/common/sun_pages.c
usr/src/lib/scsi/plugins/ses/SUN/common/sun_spms.c
usr/src/lib/scsi/plugins/ses/libses/Makefile.com
usr/src/lib/scsi/plugins/ses/libses/common/libses.h
usr/src/lib/scsi/plugins/ses/ses2/common/ses2.h
usr/src/lib/scsi/plugins/ses/ses2/common/ses2_enclosure.c
usr/src/lib/scsi/plugins/ses/ses2/common/ses2_enclosure_ctl.c
usr/src/lib/scsi/plugins/ses/ses2/common/ses2_impl.h
usr/src/lib/scsi/plugins/ses/ses2/common/ses2_pages.c
usr/src/lib/scsi/plugins/smp/Makefile
usr/src/lib/scsi/plugins/smp/Makefile.lib
usr/src/lib/scsi/plugins/smp/Makefile.plugin
usr/src/lib/scsi/plugins/smp/Makefile.targ
usr/src/lib/scsi/plugins/smp/sas2/Makefile
usr/src/lib/scsi/plugins/smp/sas2/Makefile.com
usr/src/lib/scsi/plugins/smp/sas2/amd64/Makefile
usr/src/lib/scsi/plugins/smp/sas2/common/sas2.c
usr/src/lib/scsi/plugins/smp/sas2/common/sas2.h
usr/src/lib/scsi/plugins/smp/sas2/common/sas2_functions.c
usr/src/lib/scsi/plugins/smp/sas2/i386/Makefile
usr/src/lib/scsi/plugins/smp/sas2/sparc/Makefile
usr/src/lib/scsi/plugins/smp/sas2/sparcv9/Makefile
usr/src/lib/scsi/plugins/smp/usmp/Makefile
usr/src/lib/scsi/plugins/smp/usmp/Makefile.com
usr/src/lib/scsi/plugins/smp/usmp/amd64/Makefile
usr/src/lib/scsi/plugins/smp/usmp/common/usmp.c
usr/src/lib/scsi/plugins/smp/usmp/i386/Makefile
usr/src/lib/scsi/plugins/smp/usmp/sparc/Makefile
usr/src/lib/scsi/plugins/smp/usmp/sparcv9/Makefile
usr/src/pkg/manifests/developer-library-lint.mf
usr/src/pkg/manifests/system-header.mf
usr/src/pkg/manifests/system-io-tests.mf
usr/src/pkg/manifests/system-library-storage-scsi-plugins.mf
usr/src/pkg/manifests/system-library.mf
usr/src/uts/common/sys/Makefile
usr/src/uts/common/sys/scsi/generic/sff_frames.h
--- a/exception_lists/packaging	Sun Apr 11 11:07:03 2010 +0800
+++ b/exception_lists/packaging	Sun Apr 11 11:20:12 2010 -0700
@@ -20,8 +20,7 @@
 #
 
 #
-# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
 #
 
 #
@@ -45,6 +44,7 @@
 usr/include/sys/clock_impl.h
 usr/include/sys/ieeefp.h
 usr/include/sys/winlockio.h
+usr/include/scsi/plugins/ses/vendor/sun_impl.h
 #
 # Private/Internal libraries of the Cryptographic Framework.
 #
--- a/usr/src/cmd/scsi/Makefile	Sun Apr 11 11:07:03 2010 +0800
+++ b/usr/src/cmd/scsi/Makefile	Sun Apr 11 11:20:12 2010 -0700
@@ -19,14 +19,12 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
 #
-#ident	"%Z%%M%	%I%	%E% SMI"
 
 SUBDIRS = \
-	sestopo
-
+	sestopo \
+	smp
 _msg:
 
 include ./Makefile.subdirs
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/scsi/smp/Makefile	Sun Apr 11 11:20:12 2010 -0700
@@ -0,0 +1,27 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+SUBDIRS = $(MACH)
+
+include ../Makefile.subdirs
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/scsi/smp/Makefile.com	Sun Apr 11 11:20:12 2010 -0700
@@ -0,0 +1,67 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+.KEEP_STATE:
+.SUFFIXES:
+
+PROG = smp
+SRCS = $(PROG:%=../common/%.c)
+OBJS = $(PROG:%=%.o)
+
+include ../../../Makefile.cmd
+
+ROOTLIBSCSI = $(ROOT)/usr/lib/scsi
+ROOTPROG = $(ROOTLIBSCSI)/$(PROG)
+
+$(NOT_RELEASE_BUILD)CPPFLAGS += -DDEBUG
+CPPFLAGS += -I. -I../common
+CFLAGS += $(CTF_FLAGS) $(CCVERBOSE) $(XSTRCONST)
+LDLIBS += -L$(ROOT)/usr/lib/scsi -lsmp
+LDFLAGS += -R/usr/lib/scsi
+
+all: $(PROG)
+
+$(PROG): $(OBJS)
+	$(LINK.c) $(OBJS) -o $@ $(LDLIBS)
+	$(CTFMERGE) -L VERSION -o $@ $(OBJS)
+	$(POST_PROCESS)
+
+%.o: ../common/%.c
+	$(COMPILE.c) $<
+	$(CTFCONVERT_O)
+
+clean:
+	$(RM) $(OBJS)
+
+lint: lint_SRCS
+
+$(ROOTLIBSCSI)/%: %
+	$(INS.file)
+
+install_h:
+
+install: all $(ROOTPROG)
+
+include ../../../Makefile.targ
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/scsi/smp/common/smp.c	Sun Apr 11 11:20:12 2010 -0700
@@ -0,0 +1,215 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+#include <sys/types.h>
+#include <sys/scsi/generic/smp_frames.h>
+#include <sys/scsi/generic/commands.h>
+#include <sys/scsi/impl/commands.h>
+#include <sys/ccompile.h>
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <strings.h>
+#include <ctype.h>
+
+#include <scsi/libsmp.h>
+#include <scsi/libsmp_plugin.h>
+
+static void fatal(int, const char *, ...) __NORETURN;
+
+static void
+fatal(int err, const char *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+	(void) vfprintf(stderr, fmt, ap);
+	va_end(ap);
+
+	(void) fprintf(stderr, "\n");
+	(void) fflush(stderr);
+
+	_exit(err);
+}
+
+int
+main(int argc, char *argv[])
+{
+	smp_target_t *tp;
+	smp_action_t *ap;
+	smp_errno_t err;
+	smp_function_t func;
+	smp_result_t result;
+	smp_target_def_t tdef;
+	smp_discover_resp_t *rp;
+	smp_report_manufacturer_info_resp_t *ip;
+	uint8_t *resp;
+	size_t len;
+	uint_t cap;
+	void *x;
+	uint_t i, j;
+
+	if (argc < 3)
+		fatal(-1, "Usage: %s <device> <function> ...\n", argv[0]);
+
+	errno = 0;
+	func = strtoul(argv[2], NULL, 0);
+	if (errno != 0)
+		fatal(-1, "Usage: %s <device> <function> ...\n", argv[0]);
+
+	if (smp_init(LIBSMP_VERSION) != 0)
+		fatal(-1, "libsmp initialization failed: %s", smp_errmsg());
+
+	bzero(&tdef, sizeof (smp_target_def_t));
+	tdef.std_def = argv[1];
+
+	if ((tp = smp_open(&tdef)) == NULL) {
+		smp_fini();
+		fatal(-2, "failed to open %s: %s", argv[1], smp_errmsg());
+	}
+
+	cap = smp_target_getcap(tp);
+	ap = smp_action_alloc(func, tp, 0);
+	if (ap == NULL) {
+		smp_close(tp);
+		smp_fini();
+		fatal(-3, "failed to allocate action: %s", smp_errmsg());
+	}
+
+	if (func == SMP_FUNC_DISCOVER) {
+		smp_discover_req_t *dp;
+		if (argc < 4)
+			fatal(-1,
+			    "Usage: %s <device> 0x10 <phy identifier>\n",
+			    argv[0]);
+
+		smp_action_get_request(ap, (void **)&dp, NULL);
+		dp->sdr_phy_identifier = strtoul(argv[3], NULL, 0);
+	} else if (func == SMP_FUNC_REPORT_ROUTE_INFO) {
+		smp_report_route_info_req_t *rp;
+		if (argc < 5)
+			fatal(-1, "Usage: %s <device> 0x13 <expander route "
+			    "index> <phy identifier>\n",
+			    argv[0]);
+
+		smp_action_get_request(ap, (void **)&rp, NULL);
+		rp->srrir_exp_route_index = strtoul(argv[3], NULL, 0);
+		rp->srrir_phy_identifier = strtoul(argv[4], NULL, 0);
+	} else if (func == SMP_FUNC_ENABLE_DISABLE_ZONING) {
+		smp_enable_disable_zoning_req_t *rp;
+		if (argc < 4)
+			fatal(-1,
+			    "Usage: %s <device> 0x81 "
+			    "[0(no change) | 1(enable)| 2(disable)]\n",
+			    argv[0]);
+
+		smp_action_get_request(ap, (void **)&rp, NULL);
+		rp->sedzr_enable_disable_zoning = strtoul(argv[3], NULL, 0);
+	} else if (func == SMP_FUNC_PHY_CONTROL) {
+		smp_phy_control_req_t *rp;
+		if (argc < 5)
+			fatal(-1,
+			    "Usage: %s <device> 0x91 <phy identifier> "
+			    " <phy operation>\n",
+			    argv[0]);
+
+		smp_action_get_request(ap, (void **)&rp, NULL);
+
+		smp_action_get_request(ap, (void **)&rp, NULL);
+		rp->spcr_phy_identifier = strtoul(argv[3], NULL, 0);
+		rp->spcr_phy_operation = strtoul(argv[4], NULL, 0);
+	} else if (func == SMP_FUNC_REPORT_EXP_ROUTE_TABLE_LIST) {
+		smp_report_exp_route_table_list_req_t *rp;
+		if (argc < 4)
+			fatal(-1,
+			    "Usage: %s <device> 0x22 <SAS Address Index> \n",
+			    argv[0]);
+
+		smp_action_get_request(ap, (void **)&rp, NULL);
+		SCSI_WRITE16(&rp->srertlr_max_descrs, 64);
+		SCSI_WRITE16(&rp->srertlr_starting_routed_sas_addr_index,
+		    strtoull(argv[3], NULL, 0));
+		rp->srertlr_starting_phy_identifier = 0;
+	}
+
+	(void) printf("%s\n", argv[0]);
+	(void) printf("\tSAS Address: %016llx\n", smp_target_addr(tp));
+	(void) printf("\tVendor: %s\n", smp_target_vendor(tp));
+	(void) printf("\tProduct: %s\n", smp_target_product(tp));
+	(void) printf("\tRevision: %s\n", smp_target_revision(tp));
+	(void) printf("\tExp Vendor: %s\n", smp_target_component_vendor(tp));
+	(void) printf("\tExp ID: %04x\n", smp_target_component_id(tp));
+	(void) printf("\tExp Rev: %02x\n", smp_target_component_revision(tp));
+
+	if (smp_exec(ap, tp) != 0) {
+		smp_close(tp);
+		smp_action_free(ap);
+		smp_fini();
+		fatal(-4, "exec failed: %s", smp_errmsg());
+	}
+
+	smp_close(tp);
+	smp_action_get_response(ap, &result, (void **)&resp, &len);
+
+	if (result != SMP_RES_FUNCTION_ACCEPTED) {
+		smp_action_free(ap);
+		smp_fini();
+		fatal(-5, "command failed with status code %d", result);
+	}
+
+	(void) printf("Response: (len %d)\n", len);
+	for (i = 0; i < len; i += 8) {
+		(void) printf("%02x: ", i);
+		for (j = i; j < i + 8; j++)
+			if (j < len)
+				(void) printf("%02x ", resp[j]);
+			else
+				(void) printf("   ");
+		for (j = i; j < i + 8; j++)
+			(void) printf("%c",
+			    j < len && isprint(resp[j]) ? resp[j] :
+			    j < len ? '.' : '\0');
+		(void) printf("\n");
+	}
+
+	if (func == SMP_FUNC_DISCOVER) {
+		rp = (smp_discover_resp_t *)resp;
+		(void) printf("Addr: %016llx Phy: %02x\n",
+		    SCSI_READ64(&rp->sdr_sas_addr), rp->sdr_phy_identifier);
+		(void) printf("Peer: %016llx Phy: %02x\n",
+		    SCSI_READ64(&rp->sdr_attached_sas_addr),
+		    rp->sdr_attached_phy_identifier);
+		(void) printf("Device type: %01x\n",
+		    rp->sdr_attached_device_type);
+	}
+
+	smp_action_free(ap);
+	smp_fini();
+
+	return (0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/scsi/smp/i386/Makefile	Sun Apr 11 11:20:12 2010 -0700
@@ -0,0 +1,26 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+include ../../../Makefile.cmd
+include ../Makefile.com
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/scsi/smp/sparc/Makefile	Sun Apr 11 11:20:12 2010 -0700
@@ -0,0 +1,26 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+include ../../../Makefile.cmd
+include ../Makefile.com
--- a/usr/src/lib/Makefile	Sun Apr 11 11:07:03 2010 +0800
+++ b/usr/src/lib/Makefile	Sun Apr 11 11:20:12 2010 -0700
@@ -659,7 +659,8 @@
 libv12n:	libds libuuid
 libvrrpadm:	libsocket libdladm libscf
 libvscan:	libscf
-scsi:		libnvpair
+libfru:		libfruutils
+scsi:		libnvpair libfru
 mpapi:		libpthread libdevinfo libsysevent libnvpair
 sun_fc:		libdevinfo libsysevent libnvpair
 libsun_ima:	libdevinfo libsysevent libnsl
--- a/usr/src/lib/fm/Makefile	Sun Apr 11 11:07:03 2010 +0800
+++ b/usr/src/lib/fm/Makefile	Sun Apr 11 11:20:12 2010 -0700
@@ -20,8 +20,7 @@
 #
 
 #
-# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
+# Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
 #
 
 include ../Makefile.lib
@@ -49,6 +48,6 @@
 
 libfmd_snmp: libfmd_adm topo
 
-topo: $($(MACH)_SUBDIRS) libfmd_agent
+topo: $($(MACH)_SUBDIRS) libfmd_agent libdiskstatus
 
 include ./Makefile.subdirs
--- a/usr/src/lib/fm/topo/libtopo/common/hc.c	Sun Apr 11 11:07:03 2010 +0800
+++ b/usr/src/lib/fm/topo/libtopo/common/hc.c	Sun Apr 11 11:20:12 2010 -0700
@@ -21,8 +21,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 #include <stdio.h>
@@ -160,6 +159,7 @@
 	{ HOSTBRIDGE, TOPO_STABILITY_PRIVATE },
 	{ INTERCONNECT, TOPO_STABILITY_PRIVATE },
 	{ IOBOARD, TOPO_STABILITY_PRIVATE },
+	{ IPORT, TOPO_STABILITY_PRIVATE },
 	{ MEMBOARD, TOPO_STABILITY_PRIVATE },
 	{ MEMORYBUFFER, TOPO_STABILITY_PRIVATE },
 	{ MEMORYCONTROL, TOPO_STABILITY_PRIVATE },
@@ -179,9 +179,13 @@
 	{ POWERMODULE, TOPO_STABILITY_PRIVATE },
 	{ PSU, TOPO_STABILITY_PRIVATE },
 	{ RANK, TOPO_STABILITY_PRIVATE },
+	{ RECEPTACLE, TOPO_STABILITY_PRIVATE },
 	{ RISER, TOPO_STABILITY_PRIVATE },
+	{ SASEXPANDER, TOPO_STABILITY_PRIVATE },
+	{ SCSI_DEVICE, TOPO_STABILITY_PRIVATE },
 	{ SHELF, TOPO_STABILITY_PRIVATE },
 	{ SES_ENCLOSURE, TOPO_STABILITY_PRIVATE },
+	{ SMP_DEVICE, TOPO_STABILITY_PRIVATE },
 	{ SP, TOPO_STABILITY_PRIVATE },
 	{ STRAND, TOPO_STABILITY_PRIVATE },
 	{ SUBCHASSIS, TOPO_STABILITY_PRIVATE },
--- a/usr/src/lib/fm/topo/libtopo/common/topo_hc.h	Sun Apr 11 11:07:03 2010 +0800
+++ b/usr/src/lib/fm/topo/libtopo/common/topo_hc.h	Sun Apr 11 11:20:12 2010 -0700
@@ -56,6 +56,7 @@
 #define	HOSTBRIDGE	"hostbridge"
 #define	INTERCONNECT	"interconnect"
 #define	IOBOARD		"ioboard"
+#define	IPORT		"iport"
 #define	MEMBOARD	"memboard"
 #define	MEMORYBUFFER	"memory-buffer"
 #define	MEMORYCONTROL	"memory-controller"
@@ -75,9 +76,13 @@
 #define	POWERMODULE	"powermodule"
 #define	PSU		"psu"
 #define	RANK		"rank"
+#define	RECEPTACLE	"receptacle"
 #define	RISER		"riser"
+#define	SASEXPANDER	"sas-expander"
 #define	SHELF		"shelf"
+#define	SCSI_DEVICE	"scsi-device"
 #define	SES_ENCLOSURE	"ses-enclosure"
+#define	SMP_DEVICE	"smp-device"
 #define	SP		"sp"
 #define	SUBCHASSIS	"subchassis"
 #define	SYSTEMBOARD	"systemboard"
@@ -105,12 +110,28 @@
 #define	TOPO_PCI_CLASS		"class-code"
 #define	TOPO_PCI_AADDR		"assigned-addresses"
 
+#define	TOPO_PGROUP_BINDING	"binding"
+#define	TOPO_BINDING_OCCUPANT	"occupant-path"
+
 #define	TOPO_PGROUP_STORAGE	"storage"
+#define	TOPO_STORAGE_INITIATOR_PORT	"initiator-port"
+#define	TOPO_STORAGE_INITIATOR_PORT_PM	"initiator-port-pm"
+#define	TOPO_STORAGE_TARGET_PORT	"target-port"
 #define	TOPO_STORAGE_TARGET_PORT_L0ID	"target-port-l0id"
 #define	TOPO_STORAGE_TARGET_PORT_L0IDS	"target-port-l0ids"
-
-#define	TOPO_PGROUP_BINDING	"binding"
-#define	TOPO_BINDING_OCCUPANT	"occupant-path"
+#define	TOPO_STORAGE_ATTACHED_PORT	"attached-port"
+#define	TOPO_STORAGE_TARGET_PORT_PM	"target-port-pm"
+#define	TOPO_STORAGE_ATTACHED_PORT_PM	"attached-port-pm"
+#define	TOPO_STORAGE_DEVID		"devid"
+#define	TOPO_STORAGE_LUN64		"lun64"
+#define	TOPO_STORAGE_DEVICE_TYPE	"inquiry-device-type"
+#define	TOPO_STORAGE_MANUFACTURER	"manufacturer"
+#define	TOPO_STORAGE_MODEL		"model"
+#define	TOPO_STORAGE_FIRMWARE_REV	"firmware-revision"
+#define	TOPO_STORAGE_TARGET_PORT_L0ID	"target-port-l0id"
+#define	TOPO_STORAGE_TARGET_PORT_L0IDS	"target-port-l0ids"
+#define	TOPO_STORAGE_SAS_PHY_MASK	"receptacle-pm"
+#define	TOPO_STORAGE_SAS_CONNECTOR_TYPE	"sas-connector-type"
 
 #ifdef	__cplusplus
 }
--- a/usr/src/lib/fm/topo/modules/common/disk/disk.c	Sun Apr 11 11:07:03 2010 +0800
+++ b/usr/src/lib/fm/topo/modules/common/disk/disk.c	Sun Apr 11 11:20:12 2010 -0700
@@ -19,10 +19,8 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  */
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
 
 #include <strings.h>
 #include <devid.h>
@@ -121,7 +119,7 @@
 		return (-1);
 	}
 
-	if (disk_list_gather(mod, dlistp) != 0) {
+	if (dev_list_gather(mod, dlistp) != 0) {
 		topo_mod_unregister(mod);
 		topo_mod_free(mod, dlistp, sizeof (topo_list_t));
 		topo_mod_dprintf(mod, "_topo_init: "
@@ -141,7 +139,7 @@
 _topo_fini(topo_mod_t *mod)
 {
 	topo_list_t *dlistp = topo_mod_getspecific(mod);
-	disk_list_free(mod, dlistp);
+	dev_list_free(mod, dlistp);
 	topo_mod_free(mod, dlistp, sizeof (topo_list_t));
 	topo_mod_unregister(mod);
 	topo_mod_dprintf(mod, "_topo_fini: "
--- a/usr/src/lib/fm/topo/modules/common/disk/disk.h	Sun Apr 11 11:07:03 2010 +0800
+++ b/usr/src/lib/fm/topo/modules/common/disk/disk.h	Sun Apr 11 11:20:12 2010 -0700
@@ -27,7 +27,6 @@
 #define	_DISK_H
 
 #include <fm/topo_mod.h>
-#include <fm/topo_hc.h>
 #include <libdevinfo.h>
 
 #ifdef __cplusplus
@@ -49,11 +48,42 @@
 #define	TOPO_STORAGE_FIRMWARE_REV	"firmware-revision"
 #define	TOPO_STORAGE_CAPACITY		"capacity-in-bytes"
 
+/*
+ * Properties for binding group: The binding group required in platform
+ * specific xml that describes 'bay' nodes containing internal disks.
+ */
+#define	TOPO_PGROUP_BINDING		"binding"
+#define	TOPO_BINDING_OCCUPANT		"occupant-path"
+
+/*
+ * device node information.
+ */
+typedef struct dev_di_node {
+	topo_list_t	ddn_list;	/* list of devices */
+
+	/* the following two fields are always defined */
+	char		*ddn_devid;	/* devid of device */
+	char		*ddn_dpath;	/* path to devinfo (may be vhci) */
+	char		**ddn_ppath;	/* physical path to device (phci) */
+	int		ddn_ppath_count;
+
+	char		*ddn_lpath;	/* logical path (public /dev name) */
+
+	char		*ddn_mfg;	/* misc information about device */
+	char		*ddn_model;
+	char		*ddn_serial;
+	char		*ddn_firm;
+	char		*ddn_cap;
+
+	char		**ddn_target_port;
+	int		ddn_target_port_count;
+} dev_di_node_t;
+
 struct topo_list;
 
 /* Methods shared with the ses module (disk_common.c) */
-extern int disk_list_gather(topo_mod_t *, struct topo_list *);
-extern void disk_list_free(topo_mod_t *, struct topo_list *);
+extern int dev_list_gather(topo_mod_t *, struct topo_list *);
+extern void dev_list_free(topo_mod_t *, struct topo_list *);
 extern int disk_declare_non_enumerated(topo_mod_t *, tnode_t *, tnode_t **);
 extern int disk_declare_path(topo_mod_t *, tnode_t *,
     struct topo_list *, const char *);
--- a/usr/src/lib/fm/topo/modules/common/disk/disk_common.c	Sun Apr 11 11:07:03 2010 +0800
+++ b/usr/src/lib/fm/topo/modules/common/disk/disk_common.c	Sun Apr 11 11:20:12 2010 -0700
@@ -47,39 +47,16 @@
 #include <fm/topo_list.h>
 #include <fm/libdiskstatus.h>
 #include <sys/fm/protocol.h>
+#include <sys/scsi/generic/inquiry.h>
 #include "disk.h"
 
-/*
- * disk node information.
- */
-typedef struct disk_di_node {
-	topo_list_t	ddn_list;	/* list of disks */
-
-	/* the following two fields are always defined */
-	char		*ddn_devid;	/* devid of disk */
-	char		*ddn_dpath;	/* path to devinfo (may be vhci) */
-	char		**ddn_ppath;	/* physical path to device (phci) */
-	int		ddn_ppath_count;
-
-	char		*ddn_lpath;	/* logical path (public /dev name) */
-
-	char		*ddn_mfg;	/* misc information about device */
-	char		*ddn_model;
-	char		*ddn_serial;
-	char		*ddn_firm;
-	char		*ddn_cap;
-
-	char		**ddn_target_port;
-	int		ddn_target_port_count;
-} disk_di_node_t;
-
 /* common callback information for di_walk_node() and di_devlink_walk */
 typedef struct disk_cbdata {
 	topo_mod_t		*dcb_mod;
 	topo_list_t		*dcb_list;
 
 	di_devlink_handle_t	dcb_devhdl;
-	disk_di_node_t		*dcb_dnode;	/* for di_devlink_walk only */
+	dev_di_node_t		*dcb_dnode;	/* for di_devlink_walk only */
 } disk_cbdata_t;
 
 /*
@@ -130,7 +107,7 @@
 };
 
 /*
- * Set the properties of the disk node, from disk_di_node_t data.
+ * Set the properties of the disk node, from dev_di_node_t data.
  * Properties include:
  *	group: protocol	 properties: resource, asru, label, fru
  *	group: authority properties: product-id, chasis-id, server-id
@@ -145,7 +122,7 @@
  */
 static int
 disk_set_props(topo_mod_t *mod, tnode_t *parent,
-    tnode_t *dtn, disk_di_node_t *dnode)
+    tnode_t *dtn, dev_di_node_t *dnode)
 {
 	nvlist_t	*asru = NULL;
 	char		*label = NULL;
@@ -354,7 +331,7 @@
 /* create the disk topo node */
 static int
 disk_tnode_create(topo_mod_t *mod, tnode_t *parent,
-    disk_di_node_t *dnode, const char *name, topo_instance_t i, tnode_t **rval)
+    dev_di_node_t *dnode, const char *name, topo_instance_t i, tnode_t **rval)
 {
 	int		len;
 	nvlist_t	*fmri;
@@ -431,7 +408,7 @@
 }
 
 static int
-disk_declare(topo_mod_t *mod, tnode_t *parent, disk_di_node_t *dnode,
+disk_declare(topo_mod_t *mod, tnode_t *parent, dev_di_node_t *dnode,
     tnode_t **childp)
 {
 	tnode_t		*dtn = NULL;
@@ -464,7 +441,7 @@
 disk_declare_path(topo_mod_t *mod, tnode_t *parent, topo_list_t *listp,
     const char *path)
 {
-	disk_di_node_t		*dnode;
+	dev_di_node_t		*dnode;
 	int i;
 
 	/*
@@ -491,7 +468,7 @@
 disk_declare_addr(topo_mod_t *mod, tnode_t *parent, topo_list_t *listp,
     const char *addr, tnode_t **childp)
 {
-	disk_di_node_t *dnode;
+	dev_di_node_t *dnode;
 	int i;
 
 	/* Check for match using addr. */
@@ -524,13 +501,13 @@
 	return (disk_declare(mod, parent, NULL, childp));
 }
 
-/* di_devlink callback for disk_di_node_add */
+/* di_devlink callback for dev_di_node_add */
 static int
 disk_devlink_callback(di_devlink_t dl, void *arg)
 {
 	disk_cbdata_t	*cbp = (disk_cbdata_t *)arg;
 	topo_mod_t	*mod = cbp->dcb_mod;
-	disk_di_node_t	*dnode = cbp->dcb_dnode;
+	dev_di_node_t	*dnode = cbp->dcb_dnode;
 	const char	*devpath;
 	char		*ctds, *slice;
 
@@ -552,7 +529,7 @@
 }
 
 static void
-disk_di_node_free(topo_mod_t *mod, disk_di_node_t *dnode)
+dev_di_node_free(topo_mod_t *mod, dev_di_node_t *dnode)
 {
 	int i;
 
@@ -578,14 +555,14 @@
 	    dnode->ddn_target_port_count * sizeof (uintptr_t));
 
 	/* free self */
-	topo_mod_free(mod, dnode, sizeof (disk_di_node_t));
+	topo_mod_free(mod, dnode, sizeof (dev_di_node_t));
 }
 
 static int
-disk_di_node_add(di_node_t node, char *devid, disk_cbdata_t *cbp)
+dev_di_node_add(di_node_t node, char *devid, disk_cbdata_t *cbp)
 {
 	topo_mod_t	*mod = cbp->dcb_mod;
-	disk_di_node_t	*dnode;
+	dev_di_node_t	*dnode;
 	di_path_t	pnode;
 	char		*path;
 	int		mlen;
@@ -598,6 +575,7 @@
 	uint_t		dblksize;
 	char		lentry[MAXPATHLEN];
 	int		pathcount, portcount;
+	int		*inq_dtype, itype;
 	int 		ret, i;
 
 	if (devid) {
@@ -610,14 +588,14 @@
 		    dnode != NULL; dnode = topo_list_next(dnode)) {
 			if (dnode->ddn_devid &&
 			    devid_str_compare(dnode->ddn_devid, devid) == 0) {
-				topo_mod_dprintf(mod, "disk_di_node_add: "
+				topo_mod_dprintf(mod, "dev_di_node_add: "
 				    "already there %s\n", devid);
 				return (0);
 			}
 		}
 	}
 
-	if ((dnode = topo_mod_zalloc(mod, sizeof (disk_di_node_t))) == NULL)
+	if ((dnode = topo_mod_zalloc(mod, sizeof (dev_di_node_t))) == NULL)
 		return (-1);
 
 	if (devid) {
@@ -740,24 +718,32 @@
 	}
 
 	/*
-	 * Find the public /dev name by adding a minor name and using
+	 * Find the public /dev name for a disk by adding a minor name and using
 	 * di_devlink interface for reverse translation (use devinfo path).
 	 */
-	mlen = strlen(dnode->ddn_dpath) + strlen(extn) + 1;
-	if ((minorpath = topo_mod_alloc(mod, mlen)) == NULL)
-		goto error;
-	(void) snprintf(minorpath, mlen, "%s%s", dnode->ddn_dpath, extn);
-	cbp->dcb_dnode = dnode;
-	(void) di_devlink_walk(cbp->dcb_devhdl, "^dsk/", minorpath,
-	    DI_PRIMARY_LINK, cbp, disk_devlink_callback);
-	topo_mod_free(mod, minorpath, mlen);
-	if (dnode->ddn_lpath == NULL) {
-		topo_mod_dprintf(mod, "disk_di_node_add: "
-		    "failed to determine logical path");
-		goto error;
+	if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "inquiry-device-type",
+	    &inq_dtype) > 0) {
+		itype = (*inq_dtype) & DTYPE_MASK;
+		if (itype == DTYPE_DIRECT) {
+			mlen = strlen(dnode->ddn_dpath) + strlen(extn) + 1;
+			if ((minorpath = topo_mod_alloc(mod, mlen)) == NULL)
+				goto error;
+			(void) snprintf(minorpath, mlen, "%s%s",
+			    dnode->ddn_dpath, extn);
+			cbp->dcb_dnode = dnode;
+			(void) di_devlink_walk(cbp->dcb_devhdl, "^dsk/",
+			    minorpath, DI_PRIMARY_LINK, cbp,
+			    disk_devlink_callback);
+			topo_mod_free(mod, minorpath, mlen);
+			if (dnode->ddn_lpath == NULL) {
+				topo_mod_dprintf(mod, "dev_di_node_add: "
+				    "failed to determine logical path");
+				goto error;
+			}
+		}
 	}
 
-	/* cache various bits of optional information about the disk */
+	/* cache various bits of optional information about the device. */
 	if (di_prop_lookup_strings(DDI_DEV_T_ANY, node,
 	    INQUIRY_VENDOR_ID, &s) > 0) {
 		if ((dnode->ddn_mfg = disk_trim_whitespace(mod, s)) == NULL)
@@ -796,7 +782,7 @@
 			goto error;
 	}
 
-	topo_mod_dprintf(mod, "disk_di_node_add: "
+	topo_mod_dprintf(mod, "dev_di_node_add: "
 	    "adding %s\n", devid ? dnode->ddn_devid : "NULL devid");
 	topo_mod_dprintf(mod, "                  "
 	    "       %s\n", dnode->ddn_dpath);
@@ -808,13 +794,14 @@
 	return (0);
 
 error:
-	disk_di_node_free(mod, dnode);
+	dev_di_node_free(mod, dnode);
 	return (-1);
 }
 
+
 /* di_walk_node callback for disk_list_gather */
 static int
-disk_walk_di_nodes(di_node_t node, void *arg)
+dev_walk_di_nodes(di_node_t node, void *arg)
 {
 	char			*devidstr = NULL;
 	char			*s;
@@ -832,13 +819,13 @@
 	    DEVID_PROP_NAME, &devidstr);
 
 	/* create/find the devid scsi topology node */
-	(void) disk_di_node_add(node, devidstr, arg);
+	(void) dev_di_node_add(node, devidstr, arg);
 
 	return (DI_WALK_CONTINUE);
 }
 
 int
-disk_list_gather(topo_mod_t *mod, topo_list_t *listp)
+dev_list_gather(topo_mod_t *mod, topo_list_t *listp)
 {
 	di_node_t		devtree;
 	di_devlink_handle_t	devhdl;
@@ -862,7 +849,7 @@
 
 	/* walk the devinfo snapshot looking for disk nodes */
 	(void) di_walk_node(devtree, DI_WALK_CLDFIRST, &dcb,
-	    disk_walk_di_nodes);
+	    dev_walk_di_nodes);
 
 	(void) di_devlink_fini(&devhdl);
 
@@ -870,14 +857,14 @@
 }
 
 void
-disk_list_free(topo_mod_t *mod, topo_list_t *listp)
+dev_list_free(topo_mod_t *mod, topo_list_t *listp)
 {
-	disk_di_node_t	*dnode;
+	dev_di_node_t	*dnode;
 
 	while ((dnode = topo_list_next(listp)) != NULL) {
 		/* order of delete/free is important */
 		topo_list_delete(listp, dnode);
-		disk_di_node_free(mod, dnode);
+		dev_di_node_free(mod, dnode);
 	}
 }
 
--- a/usr/src/lib/fm/topo/modules/common/pcibus/did_props.h	Sun Apr 11 11:07:03 2010 +0800
+++ b/usr/src/lib/fm/topo/modules/common/pcibus/did_props.h	Sun Apr 11 11:20:12 2010 -0700
@@ -20,8 +20,7 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 #ifndef _DID_PROPS_H
@@ -68,6 +67,8 @@
 #define	DI_PHYSPROP	"physical-slot#"
 #define	DI_SLOTPROP	"slot-names"
 #define	DI_AADDRPROP	"assigned-addresses"
+#define	DI_RECEPTACLE_PHYMASK	"receptacle-pm"
+#define	DI_RECEPTACLE_LABEL	"receptacle-label"
 
 extern int did_props_set(tnode_t *, did_t *, txprop_t[], int);
 extern tnode_t *find_predecessor(tnode_t *, char *);
--- a/usr/src/lib/fm/topo/modules/common/pcibus/pcibus.c	Sun Apr 11 11:07:03 2010 +0800
+++ b/usr/src/lib/fm/topo/modules/common/pcibus/pcibus.c	Sun Apr 11 11:20:12 2010 -0700
@@ -428,7 +428,8 @@
 declare_dev_and_fn(topo_mod_t *mod, tnode_t *bus, tnode_t **dev, di_node_t din,
     int board, int bridge, int rc, int devno, int fnno, int depth)
 {
-	int dcnt = 0;
+	int dcnt = 0, rcnt;
+	char *propstr;
 	tnode_t *fn;
 	uint_t class, subclass;
 	uint_t vid, did;
@@ -522,6 +523,28 @@
 				}
 			}
 		}
+	} else if (class == PCI_CLASS_MASS) {
+		di_node_t cn;
+		int niports = 0;
+		extern void pci_iports_instantiate(topo_mod_t *, tnode_t *,
+		    di_node_t, int);
+		extern void pci_receptacle_instantiate(topo_mod_t *, tnode_t *,
+		    di_node_t);
+
+		for (cn = di_child_node(din); cn != DI_NODE_NIL;
+		    cn = di_sibling_node(cn)) {
+			if (strcmp(di_node_name(cn), IPORT) == 0)
+				niports++;
+		}
+		if (niports > 0)
+			pci_iports_instantiate(mod, fn, din, niports);
+
+		if ((rcnt = di_prop_lookup_strings(DDI_DEV_T_ANY, din,
+		    DI_RECEPTACLE_PHYMASK, &propstr)) > 0) {
+			if (topo_node_range_create(mod, fn, RECEPTACLE, 0,
+			    rcnt) >= 0)
+				pci_receptacle_instantiate(mod, fn, din);
+		}
 	}
 }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/fm/topo/modules/common/pcibus/pcibus_hba.c	Sun Apr 11 11:20:12 2010 -0700
@@ -0,0 +1,317 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#include <sys/fm/protocol.h>
+#include <strings.h>
+#include <fm/topo_mod.h>
+#include <sys/scsi/impl/inquiry.h>
+#include <sys/scsi/impl/scsi_sas.h>
+#include <sys/scsi/scsi_address.h>
+#include <did_props.h>
+
+static const topo_pgroup_info_t storage_pgroup =
+	{ TOPO_PGROUP_STORAGE, TOPO_STABILITY_PRIVATE,
+	    TOPO_STABILITY_PRIVATE, 1 };
+
+void
+pci_di_prop_set(tnode_t *tn, di_node_t din, char *dpnm, char *tpnm)
+{
+	int err;
+	char *tmpbuf;
+
+	if (di_prop_lookup_strings(DDI_DEV_T_ANY, din, dpnm, &tmpbuf) == 1)
+		(void) topo_prop_set_string(tn, TOPO_PGROUP_STORAGE, tpnm,
+		    TOPO_PROP_IMMUTABLE, tmpbuf, &err);
+}
+
+void
+pci_pi_prop_set(tnode_t *tn, di_path_t din, char *dpnm, char *tpnm)
+{
+	int err;
+	char *tmpbuf;
+
+	if (di_path_prop_lookup_strings(din, dpnm, &tmpbuf) == 1)
+		(void) topo_prop_set_string(tn, TOPO_PGROUP_STORAGE, tpnm,
+		    TOPO_PROP_IMMUTABLE, tmpbuf, &err);
+}
+
+static void
+pci_scsi_device_create(topo_mod_t *mod, nvlist_t *auth, tnode_t *parent,
+    di_node_t cn, int instance, di_path_t pi)
+{
+	tnode_t *child;
+	nvlist_t *fmri;
+	int e, *val;
+	int64_t *val64;
+
+	fmri = topo_mod_hcfmri(mod, parent, FM_HC_SCHEME_VERSION, SCSI_DEVICE,
+	    instance, NULL, auth, NULL, NULL, NULL);
+	if (fmri == NULL)
+		return;
+	child = topo_node_bind(mod, parent, SCSI_DEVICE, instance, fmri);
+	nvlist_free(fmri);
+	if (child == NULL)
+		return;
+	if (topo_pgroup_create(child, &storage_pgroup, &e) < 0)
+		return;
+	if (pi != NULL) {
+		pci_pi_prop_set(child, pi, SCSI_ADDR_PROP_TARGET_PORT,
+		    TOPO_STORAGE_TARGET_PORT);
+		pci_pi_prop_set(child, pi, SCSI_ADDR_PROP_ATTACHED_PORT,
+		    TOPO_STORAGE_ATTACHED_PORT);
+		pci_pi_prop_set(child, pi, SCSI_ADDR_PROP_TARGET_PORT_PM,
+		    TOPO_STORAGE_TARGET_PORT_PM);
+		pci_pi_prop_set(child, pi, SCSI_ADDR_PROP_ATTACHED_PORT_PM,
+		    TOPO_STORAGE_ATTACHED_PORT_PM);
+		if (di_path_prop_lookup_int64s(pi,
+		    SCSI_ADDR_PROP_LUN64, &val64) == 1)
+			(void) topo_prop_set_int64(child, TOPO_PGROUP_STORAGE,
+			    TOPO_STORAGE_LUN64, TOPO_PROP_IMMUTABLE, *val64,
+			    &e);
+	} else {
+		pci_di_prop_set(child, cn, SCSI_ADDR_PROP_TARGET_PORT,
+		    TOPO_STORAGE_TARGET_PORT);
+		pci_di_prop_set(child, cn, SCSI_ADDR_PROP_ATTACHED_PORT,
+		    TOPO_STORAGE_ATTACHED_PORT);
+		pci_di_prop_set(child, cn, SCSI_ADDR_PROP_TARGET_PORT_PM,
+		    TOPO_STORAGE_TARGET_PORT_PM);
+		pci_di_prop_set(child, cn, SCSI_ADDR_PROP_ATTACHED_PORT_PM,
+		    TOPO_STORAGE_ATTACHED_PORT_PM);
+		if (di_prop_lookup_int64(DDI_DEV_T_ANY, cn,
+		    SCSI_ADDR_PROP_LUN64, &val64) == 1)
+			(void) topo_prop_set_int64(child, TOPO_PGROUP_STORAGE,
+			    TOPO_STORAGE_LUN64, TOPO_PROP_IMMUTABLE, *val64,
+			    &e);
+	}
+	pci_di_prop_set(child, cn, DEVID_PROP_NAME, TOPO_STORAGE_DEVID);
+	pci_di_prop_set(child, cn, INQUIRY_VENDOR_ID,
+	    TOPO_STORAGE_MANUFACTURER);
+	pci_di_prop_set(child, cn, INQUIRY_PRODUCT_ID, TOPO_STORAGE_MODEL);
+	pci_di_prop_set(child, cn, INQUIRY_REVISION_ID,
+	    TOPO_STORAGE_FIRMWARE_REV);
+	if (di_prop_lookup_ints(DDI_DEV_T_ANY, cn,
+	    INQUIRY_DEVICE_TYPE, &val) == 1)
+		(void) topo_prop_set_int32(child, TOPO_PGROUP_STORAGE,
+		    TOPO_STORAGE_DEVICE_TYPE, TOPO_PROP_IMMUTABLE, *val, &e);
+}
+
+static void
+pci_smp_device_create(topo_mod_t *mod, nvlist_t *auth, tnode_t *parent,
+    di_node_t cn, int instance)
+{
+	tnode_t *child;
+	nvlist_t *fmri;
+	int e;
+
+	fmri = topo_mod_hcfmri(mod, parent, FM_HC_SCHEME_VERSION, SMP_DEVICE,
+	    instance, NULL, auth, NULL, NULL, NULL);
+	if (fmri == NULL)
+		return;
+	child = topo_node_bind(mod, parent, SMP_DEVICE, instance, fmri);
+	nvlist_free(fmri);
+	if (child == NULL)
+		return;
+	if (topo_pgroup_create(child, &storage_pgroup, &e) < 0)
+		return;
+	pci_di_prop_set(child, cn, SCSI_ADDR_PROP_TARGET_PORT,
+	    TOPO_STORAGE_TARGET_PORT);
+	pci_di_prop_set(child, cn, SCSI_ADDR_PROP_ATTACHED_PORT,
+	    TOPO_STORAGE_ATTACHED_PORT);
+	pci_di_prop_set(child, cn, SCSI_ADDR_PROP_TARGET_PORT_PM,
+	    TOPO_STORAGE_TARGET_PORT_PM);
+	pci_di_prop_set(child, cn, SCSI_ADDR_PROP_ATTACHED_PORT_PM,
+	    TOPO_STORAGE_ATTACHED_PORT_PM);
+	pci_di_prop_set(child, cn, DEVID_PROP_NAME, TOPO_STORAGE_DEVID);
+	pci_di_prop_set(child, cn, INQUIRY_VENDOR_ID,
+	    TOPO_STORAGE_MANUFACTURER);
+	pci_di_prop_set(child, cn, INQUIRY_PRODUCT_ID, TOPO_STORAGE_MODEL);
+	pci_di_prop_set(child, cn, INQUIRY_REVISION_ID,
+	    TOPO_STORAGE_FIRMWARE_REV);
+}
+
+static tnode_t *
+pci_iport_device_create(topo_mod_t *mod, nvlist_t *auth, tnode_t *parent,
+    di_node_t cn, int instance)
+{
+	tnode_t *child;
+	nvlist_t *fmri;
+	int e;
+
+	fmri = topo_mod_hcfmri(mod, parent, FM_HC_SCHEME_VERSION, IPORT,
+	    instance, NULL, auth, NULL, NULL, NULL);
+	if (fmri == NULL)
+		return (NULL);
+	child = topo_node_bind(mod, parent, IPORT, instance, fmri);
+	nvlist_free(fmri);
+	if (child == NULL)
+		return (NULL);
+	if (topo_pgroup_create(child, &storage_pgroup, &e) < 0)
+		return (child);
+	pci_di_prop_set(child, cn, SCSI_ADDR_PROP_INITIATOR_PORT,
+	    TOPO_STORAGE_INITIATOR_PORT);
+	(void) topo_prop_set_string(child, TOPO_PGROUP_STORAGE,
+	    TOPO_STORAGE_INITIATOR_PORT_PM, TOPO_PROP_IMMUTABLE,
+	    di_bus_addr(cn), &e);
+	return (child);
+}
+
+void
+pci_iports_instantiate(topo_mod_t *mod, tnode_t *parent, di_node_t pn,
+    int niports)
+{
+	di_node_t cn, smp, sd;
+	di_path_t pi;
+	tnode_t *iport;
+	int i, j;
+	nvlist_t *auth;
+
+	if (topo_node_range_create(mod, parent, IPORT, 0, niports) < 0)
+		return;
+	auth = topo_mod_auth(mod, parent);
+	for (i = 0, cn = di_child_node(pn); cn != DI_NODE_NIL;
+	    cn = di_sibling_node(cn)) {
+		/*
+		 * First create any iport nodes.
+		 */
+		if (strcmp(di_node_name(cn), "iport") != 0)
+			continue;
+		iport = pci_iport_device_create(mod, auth, parent, cn, i++);
+		if (iport == NULL)
+			continue;
+
+		/*
+		 * Now create any scsi-device nodes.
+		 */
+		for (j = 0, sd = di_child_node(cn); sd != DI_NODE_NIL;
+		    sd = di_sibling_node(sd))
+			if (strcmp(di_node_name(sd), "smp") != 0)
+				j++;
+		for (pi = di_path_phci_next_path(cn, DI_PATH_NIL);
+		    pi != DI_PATH_NIL; pi = di_path_phci_next_path(cn, pi))
+			if (strcmp(di_node_name(di_path_client_node(pi)),
+			    "smp") != 0)
+				j++;
+		if (topo_node_range_create(mod, iport, SCSI_DEVICE, 0, j) < 0)
+			continue;
+		for (j = 0, sd = di_child_node(cn); sd != DI_NODE_NIL;
+		    sd = di_sibling_node(sd))
+			if (strcmp(di_node_name(sd), "smp") != 0)
+				pci_scsi_device_create(mod, auth, iport, sd,
+				    j++, NULL);
+		for (pi = di_path_phci_next_path(cn, DI_PATH_NIL);
+		    pi != DI_PATH_NIL; pi = di_path_phci_next_path(cn, pi))
+			if (strcmp(di_node_name(di_path_client_node(pi)),
+			    "smp") != 0)
+				pci_scsi_device_create(mod, auth, iport,
+				    di_path_client_node(pi),  j++, pi);
+
+		/*
+		 * Now create any smp-device nodes.
+		 */
+		for (j = 0, smp = di_child_node(cn); smp != DI_NODE_NIL;
+		    smp = di_sibling_node(smp))
+			if (strcmp(di_node_name(smp), "smp") == 0)
+				j++;
+		if (topo_node_range_create(mod, iport, SMP_DEVICE, 0, j) < 0)
+			continue;
+		for (j = 0, smp = di_child_node(cn); smp != DI_NODE_NIL;
+		    smp = di_sibling_node(smp))
+			if (strcmp(di_node_name(smp), "smp") == 0)
+				pci_smp_device_create(mod, auth, iport, smp,
+				    j++);
+	}
+	nvlist_free(auth);
+}
+
+void
+pci_receptacle_instantiate(topo_mod_t *mod, tnode_t *parent, di_node_t pnode)
+{
+	int err, i, rcnt, lcnt;
+	char *propstrpm, *propstrlabel, *pm, *label;
+	nvlist_t *fmri, *auth;
+	tnode_t	*recep;
+
+	rcnt = di_prop_lookup_strings(DDI_DEV_T_ANY, pnode,
+	    DI_RECEPTACLE_PHYMASK, &propstrpm);
+	if ((lcnt = di_prop_lookup_strings(DDI_DEV_T_ANY, pnode,
+	    DI_RECEPTACLE_LABEL, &propstrlabel)) <= 0) {
+		topo_mod_dprintf(mod,
+		    "pci_receptacle_instanciate: rececptacle label not "
+		    "found for the pci function node.\n");
+		return;
+	}
+
+	if (rcnt != lcnt) {
+		topo_mod_dprintf(mod,
+		    "pci_receptacle_instantiate: rececptacle label count %d "
+		    "doesn match with phy mask count %d\n", lcnt, rcnt);
+	}
+
+	label = propstrlabel;
+	pm = propstrpm;
+	auth = topo_mod_auth(mod, parent);
+	for (i = 0; i < rcnt; i++) {
+		fmri = topo_mod_hcfmri(mod, parent, FM_HC_SCHEME_VERSION,
+		    RECEPTACLE, i, NULL, auth, NULL, NULL, NULL);
+		if (fmri == NULL) {
+			topo_mod_dprintf(mod, "topo_mod_hcfmri() failed: %s",
+			    topo_mod_errmsg(mod));
+			continue;
+		}
+		recep = topo_node_bind(mod, parent, RECEPTACLE, i, fmri);
+		nvlist_free(fmri);
+		if (recep == NULL) {
+			topo_mod_dprintf(mod, "topo_node_bind() failed: %s",
+			    topo_mod_errmsg(mod));
+			continue;
+		}
+
+		if (label) {
+			if (topo_node_label_set(recep, label, &err) < 0) {
+				topo_mod_dprintf(mod,
+				    "topo_receptacle_instantiate: "
+				    "topo_node_label_set error(%s)\n",
+				    topo_strerror(err));
+			}
+			if (i < lcnt) {
+				label = label + strlen(label) + 1;
+			} else {
+				label = NULL;
+			}
+		}
+
+		if (topo_pgroup_create(recep, &storage_pgroup, &err) < 0) {
+			topo_mod_dprintf(mod, "ses_set_expander_props: "
+			    "create storage error %s\n", topo_strerror(err));
+			continue;
+		}
+		(void) topo_prop_set_string(recep, TOPO_PGROUP_STORAGE,
+		    TOPO_STORAGE_SAS_PHY_MASK,
+		    TOPO_PROP_IMMUTABLE, pm, &err);
+		pm = pm + strlen(pm) + 1;
+	}
+
+	nvlist_free(auth);
+}
--- a/usr/src/lib/fm/topo/modules/common/ses/ses.c	Sun Apr 11 11:07:03 2010 +0800
+++ b/usr/src/lib/fm/topo/modules/common/ses/ses.c	Sun Apr 11 11:20:12 2010 -0700
@@ -30,17 +30,22 @@
 #include <inttypes.h>
 #include <pthread.h>
 #include <strings.h>
+#include <string.h>
 #include <unistd.h>
 #include <sys/dkio.h>
 #include <sys/fm/protocol.h>
 #include <sys/libdevid.h>
 #include <sys/scsi/scsi_types.h>
+#include <sys/byteorder.h>
 
 #include "disk.h"
 #include "ses.h"
 
 #define	SES_VERSION	1
 
+#define	SES_STARTING_SUBCHASSIS 256	/* valid subchassis IDs are uint8_t */
+#define	NO_SUBCHASSIS	((uint64_t)-1)
+
 static int ses_snap_freq = 250;		/* in milliseconds */
 
 #define	SES_STATUS_UNAVAIL(s)	\
@@ -74,17 +79,17 @@
 	topo_list_t		sec_nodes;
 	topo_list_t		sec_targets;
 	const char		*sec_csn;
-	const char		*sec_lid;
 	ses_node_t		*sec_enclosure;
 	ses_enum_target_t	*sec_target;
 	topo_instance_t		sec_instance;
 	topo_instance_t		sec_scinstance;
+	topo_instance_t		sec_maxinstance;
 	boolean_t		sec_hasdev;
 	boolean_t		sec_internal;
 } ses_enum_chassis_t;
 
 typedef struct ses_enum_data {
-	topo_list_t		sed_disks;
+	topo_list_t		sed_devs;
 	topo_list_t		sed_chassis;
 	ses_enum_chassis_t	*sed_current;
 	ses_enum_target_t	*sed_target;
@@ -94,6 +99,55 @@
 	topo_instance_t		sed_instance;
 } ses_enum_data_t;
 
+typedef struct sas_connector_phy_data {
+	uint64_t    index;
+	uint64_t    phy_mask;
+} sas_connector_phy_data_t;
+
+typedef struct sas_connector_type {
+	uint64_t    type;
+	char	    *name;
+} sas_connector_type_t;
+
+static const sas_connector_type_t sas_connector_type_list[] = {
+	{   0x0, "Information unknown"  },
+	{   0x1, "External SAS 4x receptacle (see SAS-2 and SFF-8470)"	},
+	{   0x2, "Exteranl Mini SAS 4x receptacle (see SAS-2 and SFF-8088)" },
+	{   0xF, "Vendor-specific external connector"	},
+	{   0x10, "Internal wide SAS 4i plug (see SAS-2 and SFF-8484)"	},
+	{   0x11,
+	"Internal wide Mini SAS 4i receptacle (see SAS-2 and SFF-8087)"	},
+	{   0x20, "Internal SAS Drive receptacle (see SAS-2 and SFF-8482)"  },
+	{   0x21, "Internal SATA host plug (see SAS-2 and SATA-2)"  },
+	{   0x22, "Internal SAS Drive plug (see SAS-2 and SFF-8482)"	},
+	{   0x23, "Internal SATA device plug (see SAS-2 and SATA-2)"	},
+	{   0x2F, "Internal SAS virtual connector"  },
+	{   0x3F, "Vendor-specific internal connector"	},
+	{   0x70, "Other Vendor-specific connector"	},
+	{   0x71, "Other Vendor-specific connector"	},
+	{   0x72, "Other Vendor-specific connector"	},
+	{   0x73, "Other Vendor-specific connector"	},
+	{   0x74, "Other Vendor-specific connector"	},
+	{   0x75, "Other Vendor-specific connector"	},
+	{   0x76, "Other Vendor-specific connector"	},
+	{   0x77, "Other Vendor-specific connector"	},
+	{   0x78, "Other Vendor-specific connector"	},
+	{   0x79, "Other Vendor-specific connector"	},
+	{   0x7A, "Other Vendor-specific connector"	},
+	{   0x7B, "Other Vendor-specific connector"	},
+	{   0x7C, "Other Vendor-specific connector"	},
+	{   0x7D, "Other Vendor-specific connector"	},
+	{   0x7E, "Other Vendor-specific connector"	},
+	{   0x7F, "Other Vendor-specific connector"	},
+	{   0x80, "Not Defined"	}
+};
+
+#define	SAS_CONNECTOR_TYPE_CODE_NOT_DEFINED  0x80
+#define	SAS_CONNECTOR_TYPE_NOT_DEFINED \
+	"Connector type not definedi by SES-2 standard"
+#define	SAS_CONNECTOR_TYPE_RESERVED \
+	"Connector type reserved by SES-2 standard"
+
 typedef enum {
 	SES_NEW_CHASSIS		= 0x1,
 	SES_NEW_SUBCHASSIS	= 0x2,
@@ -101,6 +155,20 @@
 	SES_DUP_SUBCHASSIS	= 0x8
 } ses_chassis_type_e;
 
+static const topo_pgroup_info_t io_pgroup = {
+	TOPO_PGROUP_IO,
+	TOPO_STABILITY_PRIVATE,
+	TOPO_STABILITY_PRIVATE,
+	1
+};
+
+static const topo_pgroup_info_t storage_pgroup = {
+	TOPO_PGROUP_STORAGE,
+	TOPO_STABILITY_PRIVATE,
+	TOPO_STABILITY_PRIVATE,
+	1
+};
+
 static int ses_present(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *,
     nvlist_t **);
 static int ses_contains(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *,
@@ -180,7 +248,7 @@
 	}
 
 	if (pcp == NULL) {
-		disk_list_free(mod, &sdp->sed_disks);
+		dev_list_free(mod, &sdp->sed_devs);
 		topo_mod_free(mod, sdp, sizeof (ses_enum_data_t));
 	}
 }
@@ -401,13 +469,15 @@
 }
 
 /*
- * Sets standard properties for a ses node (enclosure or bay).  This includes
- * setting the FRU to be the same as the resource, as well as setting the
- * authority information.
+ * Sets standard properties for a ses node (enclosure, bay, controller
+ * or expander).
+ * This includes setting the FRU, as well as setting the
+ * authority information.  When  the fru topo node(frutn) is not NULL
+ * its resouce should be used as FRU.
  */
 static int
-ses_set_standard_props(topo_mod_t *mod, tnode_t *tn, nvlist_t *auth,
-    uint64_t nodeid, const char *path)
+ses_set_standard_props(topo_mod_t *mod, tnode_t *frutn, tnode_t *tn,
+    nvlist_t *auth, uint64_t nodeid, const char *path)
 {
 	int err;
 	char *product, *chassis;
@@ -440,11 +510,20 @@
 	/*
 	 * Copy the resource and set that as the FRU.
 	 */
-	if (topo_node_resource(tn, &fmri, &err) != 0) {
-		topo_mod_dprintf(mod,
-		    "topo_node_resource() failed : %s\n",
-		    topo_strerror(err));
-		return (topo_mod_seterrno(mod, err));
+	if (frutn != NULL) {
+		if (topo_node_resource(frutn, &fmri, &err) != 0) {
+			topo_mod_dprintf(mod,
+			    "topo_node_resource() failed : %s\n",
+			    topo_strerror(err));
+			return (topo_mod_seterrno(mod, err));
+		}
+	} else {
+		if (topo_node_resource(tn, &fmri, &err) != 0) {
+			topo_mod_dprintf(mod,
+			    "topo_node_resource() failed : %s\n",
+			    topo_strerror(err));
+			return (topo_mod_seterrno(mod, err));
+		}
 	}
 
 	if (topo_node_fru_set(tn, fmri, 0, &err) != 0) {
@@ -518,7 +597,8 @@
 	if (nvlist_lookup_uint64(props, SES_PROP_STATUS_CODE, &status) != 0)
 		return (0);
 
-	if (status != SES_ESC_OK &&
+	if (status != SES_ESC_UNSUPPORTED &&
+	    status != SES_ESC_OK &&
 	    status != SES_ESC_CRITICAL &&
 	    status != SES_ESC_NONCRITICAL &&
 	    status != SES_ESC_UNRECOVERABLE &&
@@ -553,7 +633,7 @@
 	err = 0;
 
 	for (s = 0; s < nsas; s++) {
-		ret = disk_declare_addr(mod, pnode, &sdp->sed_disks, paths[s],
+		ret = disk_declare_addr(mod, pnode, &sdp->sed_devs, paths[s],
 		    &child);
 		if (ret == 0) {
 			break;
@@ -675,11 +755,11 @@
 }
 
 /*
- * Callback to create a basic node (bay, psu, fan, or controller).
+ * Callback to create a basic node (bay, psu, fan, or controller and expander).
  */
 static int
 ses_create_generic(ses_enum_data_t *sdp, ses_enum_node_t *snp,
-    tnode_t *pnode, const char *nodename, const char *labelname)
+    tnode_t *pnode, const char *nodename, const char *labelname, tnode_t **node)
 {
 	ses_node_t *np = snp->sen_node;
 	ses_node_t *parent;
@@ -687,7 +767,7 @@
 	topo_mod_t *mod = sdp->sed_mod;
 	nvlist_t *props, *aprops;
 	nvlist_t *auth = NULL, *fmri = NULL;
-	tnode_t *tn;
+	tnode_t *tn = NULL, *frutn = NULL;
 	char label[128];
 	int err;
 	char *part = NULL, *serial = NULL, *revision = NULL;
@@ -758,8 +838,8 @@
 		parent = ses_node_parent(np);
 		aprops = ses_node_props(parent);
 		if (nvlist_lookup_string(aprops, SES_PROP_CLASS_DESCRIPTION,
-		    &desc) == 0 && desc[0] != '\0')
-			labelname = desc;
+		    &desc) != 0 || desc[0] == '\0')
+			desc = (char *)labelname;
 		(void) snprintf(label, sizeof (label), "%s %llu", desc,
 		    instance);
 		desc = label;
@@ -768,11 +848,21 @@
 	if (topo_node_label_set(tn, desc, &err) != 0)
 		goto error;
 
-	if (ses_set_standard_props(mod, tn, NULL, ses_node_id(np),
+	/*
+	 * For an expander node, set the FRU to its parent(controller).
+	 * For a connector node, set the FRU to its grand parent(controller).
+	 */
+	if (strcmp(nodename, SASEXPANDER) == 0) {
+		frutn = pnode;
+	} else if (strcmp(nodename, RECEPTACLE) == 0) {
+		frutn = topo_node_parent(pnode);
+	}
+
+	if (ses_set_standard_props(mod, frutn, tn, NULL, ses_node_id(np),
 	    snp->sen_target->set_devpath) != 0)
 		goto error;
 
-	if (strcmp(nodename, "bay") == 0) {
+	if (strcmp(nodename, BAY) == 0) {
 		if (ses_add_bay_props(mod, tn, snp) != 0)
 			goto error;
 
@@ -785,11 +875,15 @@
 			    topo_mod_errmsg(mod));
 			goto error;
 		}
-	} else {
+	} else if ((strcmp(nodename, FAN) == 0) ||
+	    (strcmp(nodename, PSU) == 0) ||
+	    (strcmp(nodename, CONTROLLER) == 0)) {
 		/*
 		 * Only fan, psu, and controller nodes have a 'present' method.
 		 * Bay nodes are always present, and disk nodes are present by
-		 * virtue of being enumerated.
+		 * virtue of being enumerated and SAS expander nodes and
+		 * SAS connector nodes are also always present once
+		 * the parent controller is found.
 		 */
 		if (topo_method_register(mod, tn, ses_component_methods) != 0) {
 			topo_mod_dprintf(mod,
@@ -805,6 +899,189 @@
 
 	nvlist_free(auth);
 	nvlist_free(fmri);
+	if (node != NULL) *node = tn;
+	return (0);
+
+error:
+	nvlist_free(auth);
+	nvlist_free(fmri);
+	return (-1);
+}
+
+/*
+ * Create SAS expander specific props.
+ */
+/*ARGSUSED*/
+static int
+ses_set_expander_props(ses_enum_data_t *sdp, ses_enum_node_t *snp,
+    tnode_t *ptnode, tnode_t *tnode, int *phycount, int64_t *connlist)
+{
+	ses_node_t *np = snp->sen_node;
+	topo_mod_t *mod = sdp->sed_mod;
+	nvlist_t *auth = NULL, *fmri = NULL;
+	nvlist_t *props, **phylist;
+	int err, i;
+	uint_t pcount;
+	uint64_t sasaddr, connidx;
+	char sasaddr_str[17];
+	boolean_t found = B_FALSE;
+	dev_di_node_t *dnode;
+
+	props = ses_node_props(np);
+
+	/*
+	 * the uninstalled expander is not enumerated by checking
+	 * the element status code.  No present present' method provided.
+	 */
+	/*
+	 * Get the Expander SAS address.  It should exist.
+	 */
+	if (nvlist_lookup_uint64(props, SES_EXP_PROP_SAS_ADDR,
+	    &sasaddr) != 0) {
+		topo_mod_dprintf(mod,
+		    "Failed to get prop %s.", SES_EXP_PROP_SAS_ADDR);
+		goto error;
+	}
+
+	(void) sprintf(sasaddr_str, "%llx", sasaddr);
+
+	/* search matching dev_di_node. */
+	for (dnode = topo_list_next(&sdp->sed_devs); dnode != NULL;
+	    dnode = topo_list_next(dnode)) {
+		if (strstr(dnode->ddn_dpath, sasaddr_str) != NULL) {
+			found = B_TRUE;
+			break;
+		}
+	}
+
+	if (!found) {
+		topo_mod_dprintf(mod,
+		    "ses_set_expander_props: Failed to find matching "
+		    "devinfo node for Exapnder SAS address %s",
+		    SES_EXP_PROP_SAS_ADDR);
+		/* continue on to get storage group props. */
+	} else {
+		/* create/set the devfs-path and devid in the io group */
+		if (topo_pgroup_create(tnode, &io_pgroup, &err) != 0) {
+			topo_mod_dprintf(mod, "ses_set_expander_props: "
+			    "create io error %s\n", topo_strerror(err));
+			goto error;
+		} else {
+			if (topo_prop_set_string(tnode, TOPO_PGROUP_IO,
+			    TOPO_IO_DEV_PATH, TOPO_PROP_IMMUTABLE,
+			    dnode->ddn_dpath, &err) != 0) {
+				topo_mod_dprintf(mod, "ses_set_expander_props: "
+				    "set dev error %s\n", topo_strerror(err));
+			}
+			if (topo_prop_set_string(tnode, TOPO_PGROUP_IO,
+			    TOPO_IO_DEVID, TOPO_PROP_IMMUTABLE,
+			    dnode->ddn_devid, &err) != 0) {
+				topo_mod_dprintf(mod, "ses_set_expander_props: "
+				    "set devid error %s\n", topo_strerror(err));
+			}
+			if (dnode->ddn_ppath_count != 0 &&
+			    topo_prop_set_string_array(tnode, TOPO_PGROUP_IO,
+			    TOPO_IO_PHYS_PATH, TOPO_PROP_IMMUTABLE,
+			    (const char **)dnode->ddn_ppath,
+			    dnode->ddn_ppath_count, &err) != 0) {
+				topo_mod_dprintf(mod, "ses_set_expander_props: "
+				    "set phys-path error %s\n",
+				    topo_strerror(err));
+			}
+		}
+	}
+
+	/* create the storage group */
+	if (topo_pgroup_create(tnode, &storage_pgroup, &err) != 0) {
+		topo_mod_dprintf(mod, "ses_set_expander_props: "
+		    "create storage error %s\n", topo_strerror(err));
+		goto error;
+	} else {
+		/* set the SAS address prop of the expander. */
+		if (topo_prop_set_string(tnode, TOPO_PGROUP_STORAGE,
+		    TOPO_PROP_SAS_ADDR, TOPO_PROP_IMMUTABLE, sasaddr_str,
+		    &err) != 0) {
+			topo_mod_dprintf(mod, "ses_set_expander_props: "
+			    "set %S error %s\n", TOPO_PROP_SAS_ADDR,
+			    topo_strerror(err));
+		}
+
+		/* Get the phy information for the expander */
+		if (nvlist_lookup_nvlist_array(props, SES_SAS_PROP_PHYS,
+		    &phylist, &pcount) != 0) {
+			topo_mod_dprintf(mod,
+			    "Failed to get prop %s.", SES_SAS_PROP_PHYS);
+		} else {
+			/*
+			 * For each phy, get the connector element index and
+			 * stores into connector element index array.
+			 */
+			*phycount = pcount;
+			for (i = 0; i < pcount; i++) {
+				if (nvlist_lookup_uint64(phylist[i],
+				    SES_PROP_CE_IDX, &connidx) == 0) {
+					if (connidx != 0xff) {
+						connlist[i] = connidx;
+					} else {
+						connlist[i] = -1;
+					}
+				} else {
+					/* Fail to get the index. set to -1. */
+					connlist[i] = -1;
+				}
+			}
+
+			/* set the phy count prop of the expander. */
+			if (topo_prop_set_uint64(tnode, TOPO_PGROUP_STORAGE,
+			    TOPO_PROP_PHY_COUNT, TOPO_PROP_IMMUTABLE, pcount,
+			    &err) != 0) {
+				topo_mod_dprintf(mod, "ses_set_expander_props: "
+				    "set %S error %s\n", TOPO_PROP_PHY_COUNT,
+				    topo_strerror(err));
+			}
+
+			/*
+			 * set the connector element index of
+			 * the expander phys.
+			 */
+		}
+
+		/* populate other misc storage group properties */
+		if (found) {
+			if (dnode->ddn_mfg && (topo_prop_set_string(tnode,
+			    TOPO_PGROUP_STORAGE, TOPO_STORAGE_MANUFACTURER,
+			    TOPO_PROP_IMMUTABLE, dnode->ddn_mfg, &err) != 0)) {
+				topo_mod_dprintf(mod, "ses_set_expander_props: "
+				    "set mfg error %s\n", topo_strerror(err));
+			}
+
+			if (dnode->ddn_model && (topo_prop_set_string(tnode,
+			    TOPO_PGROUP_STORAGE, TOPO_STORAGE_MODEL,
+			    TOPO_PROP_IMMUTABLE,
+			    dnode->ddn_model, &err) != 0)) {
+				topo_mod_dprintf(mod, "ses_set_expander_props: "
+				    "set model error %s\n", topo_strerror(err));
+			}
+
+			if (dnode->ddn_serial && (topo_prop_set_string(tnode,
+			    TOPO_PGROUP_STORAGE, TOPO_STORAGE_SERIAL_NUM,
+			    TOPO_PROP_IMMUTABLE,
+			    dnode->ddn_serial, &err) != 0)) {
+				topo_mod_dprintf(mod, "ses_set_expander_props: "
+				    "set serial error %s\n",
+				    topo_strerror(err));
+			}
+
+			if (dnode->ddn_firm && (topo_prop_set_string(tnode,
+			    TOPO_PGROUP_STORAGE,
+			    TOPO_STORAGE_FIRMWARE_REV, TOPO_PROP_IMMUTABLE,
+			    dnode->ddn_firm, &err) != 0)) {
+				topo_mod_dprintf(mod, "ses_set_expander_props: "
+				    "set firm error %s\n", topo_strerror(err));
+			}
+		}
+	}
+
 	return (0);
 
 error:
@@ -814,6 +1091,374 @@
 }
 
 /*
+ * Create SAS expander specific props.
+ */
+/*ARGSUSED*/
+static int
+ses_set_connector_props(ses_enum_data_t *sdp, ses_enum_node_t *snp,
+    tnode_t *tnode, int64_t phy_mask)
+{
+	ses_node_t *np = snp->sen_node;
+	topo_mod_t *mod = sdp->sed_mod;
+	nvlist_t *props;
+	int err, i;
+	uint64_t conntype;
+	char phymask_str[17], *conntype_str;
+	boolean_t   found;
+
+	props = ses_node_props(np);
+
+	/*
+	 * convert phy mask to string.
+	 */
+	(void) snprintf(phymask_str, 17, "%llx", phy_mask);
+
+	/* create the storage group */
+	if (topo_pgroup_create(tnode, &storage_pgroup, &err) != 0) {
+		topo_mod_dprintf(mod, "ses_set_expander_props: "
+		    "create storage error %s\n", topo_strerror(err));
+		return (-1);
+	} else {
+		/* set the SAS address prop of the expander. */
+		if (topo_prop_set_string(tnode, TOPO_PGROUP_STORAGE,
+		    TOPO_STORAGE_SAS_PHY_MASK, TOPO_PROP_IMMUTABLE,
+		    phymask_str, &err) != 0) {
+			topo_mod_dprintf(mod, "ses_set_expander_props: "
+			    "set %S error %s\n", TOPO_STORAGE_SAS_PHY_MASK,
+			    topo_strerror(err));
+		}
+
+		/* Get the connector type information for the expander */
+		if (nvlist_lookup_uint64(props,
+		    SES_SC_PROP_CONNECTOR_TYPE, &conntype) != 0) {
+			topo_mod_dprintf(mod, "Failed to get prop %s.",
+			    TOPO_STORAGE_SAS_PHY_MASK);
+		} else {
+			found = B_FALSE;
+			for (i = 0; ; i++) {
+				if (sas_connector_type_list[i].type ==
+				    SAS_CONNECTOR_TYPE_CODE_NOT_DEFINED) {
+					break;
+				}
+				if (sas_connector_type_list[i].type ==
+				    conntype) {
+					conntype_str =
+					    sas_connector_type_list[i].name;
+					found = B_TRUE;
+					break;
+				}
+			}
+
+			if (!found) {
+				if (conntype <
+				    SAS_CONNECTOR_TYPE_CODE_NOT_DEFINED) {
+					conntype_str =
+					    SAS_CONNECTOR_TYPE_RESERVED;
+				} else {
+					conntype_str =
+					    SAS_CONNECTOR_TYPE_NOT_DEFINED;
+				}
+			}
+
+			/* set the phy count prop of the expander. */
+			if (topo_prop_set_string(tnode, TOPO_PGROUP_STORAGE,
+			    TOPO_STORAGE_SAS_CONNECTOR_TYPE,
+			    TOPO_PROP_IMMUTABLE, conntype_str, &err) != 0) {
+				topo_mod_dprintf(mod, "ses_set_expander_props: "
+				    "set %S error %s\n", TOPO_PROP_PHY_COUNT,
+				    topo_strerror(err));
+			}
+		}
+	}
+
+	return (0);
+}
+
+/*
+ * Instantiate SAS expander nodes for a given ESC Electronics node(controller)
+ * nodes.
+ */
+/*ARGSUSED*/
+static int
+ses_create_esc_sasspecific(ses_enum_data_t *sdp, ses_enum_node_t *snp,
+    tnode_t *pnode, ses_enum_chassis_t *cp,
+    boolean_t dorange)
+{
+	topo_mod_t *mod = sdp->sed_mod;
+	tnode_t	*exptn, *contn;
+	boolean_t found;
+	sas_connector_phy_data_t connectors[64] = {NULL};
+	uint64_t max;
+	ses_enum_node_t *ctlsnp, *xsnp, *consnp;
+	ses_node_t *np = snp->sen_node;
+	nvlist_t *props, *psprops;
+	uint64_t index, psindex, conindex, psstatus, i, j, count;
+	int64_t cidxlist[256] = {NULL};
+	int phycount;
+
+	props = ses_node_props(np);
+
+	if (nvlist_lookup_uint64(props, SES_PROP_ELEMENT_ONLY_INDEX,
+	    &index) != 0)
+		return (-1);
+
+	/*
+	 * For SES constroller node, check to see if there are
+	 * associated SAS expanders.
+	 */
+	found = B_FALSE;
+	max = 0;
+	for (ctlsnp = topo_list_next(&cp->sec_nodes); ctlsnp != NULL;
+	    ctlsnp = topo_list_next(ctlsnp)) {
+		if (ctlsnp->sen_type == SES_ET_SAS_EXPANDER) {
+			found = B_TRUE;
+			if (ctlsnp->sen_instance > max)
+				max = ctlsnp->sen_instance;
+		}
+	}
+
+	/*
+	 * No SAS expander found notthing to process.
+	 */
+	if (!found)
+		return (0);
+
+	topo_mod_dprintf(mod, "%s Controller %d: creating "
+	    "%llu %s nodes", cp->sec_csn, index, max + 1, SASEXPANDER);
+
+	/*
+	 * The max number represent the number of elements
+	 * deducted from the highest SES_PROP_ELEMENT_CLASS_INDEX
+	 * of SET_ET_SAS_EXPANDER type element.
+	 *
+	 * There may be multiple ESC Electronics element(controllers)
+	 * within JBOD(typicall two for redundancy) and SAS expander
+	 * elements are associated with only one of them.  We are
+	 * still creating the range based max number here.
+	 * That will cover the case that all expanders are associated
+	 * with one SES controller.
+	 */
+	if (dorange && topo_node_range_create(mod, pnode,
+	    SASEXPANDER, 0, max) != 0) {
+		topo_mod_dprintf(mod,
+		    "topo_node_create_range() failed: %s",
+		    topo_mod_errmsg(mod));
+		return (-1);
+	}
+
+	/*
+	 * Search exapnders with the parent index matching with
+	 * ESC Electronics element index.
+	 * Note the index used here is a global index across
+	 * SES elements.
+	 */
+	for (xsnp = topo_list_next(&cp->sec_nodes); xsnp != NULL;
+	    xsnp = topo_list_next(xsnp)) {
+		if (xsnp->sen_type == SES_ET_SAS_EXPANDER) {
+			/*
+			 * get the parent ESC controller.
+			 */
+			psprops = ses_node_props(xsnp->sen_node);
+			if (nvlist_lookup_uint64(psprops,
+			    SES_PROP_STATUS_CODE, &psstatus) == 0) {
+				if (psstatus == SES_ESC_NOT_INSTALLED) {
+					/*
+					 * Not installed.
+					 * Don't create a ndoe.
+					 */
+					continue;
+				}
+			} else {
+				/*
+				 * The element should have status code.
+				 * If not there is no way to find
+				 * out if the expander element exist or
+				 * not.
+				 */
+				continue;
+			}
+
+			/* Get the physical parent index to compare. */
+			if (nvlist_lookup_uint64(psprops,
+			    LIBSES_PROP_PHYS_PARENT, &psindex) == 0) {
+				if (index == psindex) {
+		/* indentation moved forward */
+		/*
+		 * Handle basic node information of SAS expander
+		 * element - binding to parent node and
+		 * allocating FMRI...
+		 */
+		if (ses_create_generic(sdp, xsnp, pnode, SASEXPANDER,
+		    "SAS-EXPANDER", &exptn) != 0)
+			continue;
+		/*
+		 * Now handle SAS expander unique portion of node creation.
+		 * The max nubmer of the phy count is 256 since SES-2
+		 * defines as 1 byte field.  The cidxlist has the same
+		 * number of elements.
+		 *
+		 * We use size 64 array to store the connectors.
+		 * Typically a connectors associated with 4 phys so that
+		 * matches with the max number of connecters associated
+		 * with an expander.
+		 * The phy count goes up to 38 for Sun supported
+		 * JBOD.
+		 */
+		memset(cidxlist, 0, sizeof (int64_t) * 64);
+		if (ses_set_expander_props(sdp, xsnp, pnode, exptn, &phycount,
+		    cidxlist) != 0) {
+			/*
+			 * error on getting specific prop failed.
+			 * continue on.  Note that the node is
+			 * left bound.
+			 */
+			continue;
+		}
+
+		/*
+		 * count represetns the number of connectors discovered so far.
+		 */
+		count = 0;
+		memset(connectors, 0, sizeof (sas_connector_phy_data_t) * 64);
+		for (i = 0; i < phycount; i++) {
+			if (cidxlist[i] != -1) {
+				/* connector index is valid. */
+				for (j = 0; j < count; j++) {
+					if (connectors[j].index ==
+					    cidxlist[i]) {
+						/*
+						 * Just update phy mask.
+						 * The postion for connector
+						 * index lists(cidxlist index)
+						 * is set.
+						 */
+						connectors[j].phy_mask =
+						    connectors[j].phy_mask |
+						    (1ULL << i);
+						break;
+					}
+				}
+				/*
+				 * If j and count matche a  new connector
+				 * index is found.
+				 */
+				if (j == count) {
+					/* add a new index and phy mask. */
+					connectors[count].index = cidxlist[i];
+					connectors[count].phy_mask =
+					    connectors[count].phy_mask |
+					    (1ULL << i);
+					count++;
+				}
+			}
+		}
+
+		/*
+		 * create range for the connector nodes.
+		 * The class index of the ses connector element
+		 * is set as the instance nubmer for the node.
+		 * Even though one expander may not have all connectors
+		 * are associated with we are creating the range with
+		 * max possible instance number.
+		 */
+		found = B_FALSE;
+		max = 0;
+		for (consnp = topo_list_next(&cp->sec_nodes);
+		    consnp != NULL; consnp = topo_list_next(consnp)) {
+			if (consnp->sen_type == SES_ET_SAS_CONNECTOR) {
+				psprops = ses_node_props(consnp->sen_node);
+				found = B_TRUE;
+				if (consnp->sen_instance > max)
+					max = consnp->sen_instance;
+			}
+		}
+
+		/*
+		 * No SAS connector found nothing to process.
+		 */
+		if (!found)
+			return (0);
+
+		if (dorange && topo_node_range_create(mod, exptn,
+		    RECEPTACLE, 0, max) != 0) {
+			topo_mod_dprintf(mod,
+			    "topo_node_create_range() failed: %s",
+			    topo_mod_errmsg(mod));
+			return (-1);
+		}
+
+		/* search matching connector element using the index. */
+		for (i = 0; i < count; i++) {
+			found = B_FALSE;
+			for (consnp = topo_list_next(&cp->sec_nodes);
+			    consnp != NULL; consnp = topo_list_next(consnp)) {
+				if (consnp->sen_type == SES_ET_SAS_CONNECTOR) {
+					psprops = ses_node_props(
+					    consnp->sen_node);
+					/*
+					 * Get the physical parent index to
+					 * compare.
+					 * The connector elements are children
+					 * of ESC Electronics element even
+					 * though we enumerate them under
+					 * an expander in libtopo.
+					 */
+					if (nvlist_lookup_uint64(psprops,
+					    SES_PROP_ELEMENT_ONLY_INDEX,
+					    &conindex) == 0) {
+						if (conindex ==
+						    connectors[i].index) {
+							found = B_TRUE;
+							break;
+						}
+					}
+				}
+			}
+
+			/* now create a libtopo node. */
+			if (found) {
+				/* Create generic props. */
+				if (ses_create_generic(sdp, consnp, exptn,
+				    RECEPTACLE, "RECEPTACLE", &contn) !=
+				    0) {
+					continue;
+				}
+				/* Create connector specific props. */
+				if (ses_set_connector_props(sdp, consnp,
+				    contn, connectors[i].phy_mask) != 0) {
+					continue;
+				}
+			}
+		}
+		/* end indentation change */
+				}
+			}
+		}
+	}
+
+	return (0);
+}
+
+/*
+ * Instantiate any protocol specific portion of a node.
+ */
+/*ARGSUSED*/
+static int
+ses_create_protocol_specific(ses_enum_data_t *sdp, ses_enum_node_t *snp,
+    tnode_t *pnode, uint64_t type, ses_enum_chassis_t *cp,
+    boolean_t dorange)
+{
+
+	if (type == SES_ET_ESC_ELECTRONICS) {
+		/* create SAS specific children(expanders and connectors. */
+		return (ses_create_esc_sasspecific(sdp, snp, pnode, cp,
+		    dorange));
+	}
+
+	return (0);
+}
+
+/*
  * Instantiate any children of a given type.
  */
 static int
@@ -825,6 +1470,7 @@
 	boolean_t found;
 	uint64_t max;
 	ses_enum_node_t *snp;
+	tnode_t	*tn;
 
 	/*
 	 * First go through and count how many matching nodes we have.
@@ -864,8 +1510,22 @@
 	    snp = topo_list_next(snp)) {
 		if (snp->sen_type == type) {
 			if (ses_create_generic(sdp, snp, pnode,
-			    nodename, defaultlabel) != 0)
+			    nodename, defaultlabel, &tn) != 0)
 				return (-1);
+			/*
+			 * For some SES element there may be protocol specific
+			 * information to process.   Here we are processing
+			 * the association between enclosure controller and
+			 * SAS expanders.
+			 */
+			if (type == SES_ET_ESC_ELECTRONICS) {
+				/* create SAS expander node */
+				if (ses_create_protocol_specific(sdp, snp,
+				    tn, type, cp, dorange) != 0) {
+					return (-1);
+				}
+			}
+
 		}
 	}
 
@@ -883,7 +1543,6 @@
 	tnode_t *tn;
 	nvlist_t *props;
 	nvlist_t *auth = NULL, *fmri = NULL;
-	char *part = NULL, *revision = NULL;
 	uint64_t instance = scp->sec_instance;
 	char *desc;
 	char label[128];
@@ -905,8 +1564,8 @@
 	 * piece of code will need to be updated via an RFE.
 	 */
 	if ((fmri = topo_mod_hcfmri(mod, pnode, FM_HC_SCHEME_VERSION,
-	    SUBCHASSIS, (topo_instance_t)instance, NULL, auth, part, revision,
-	    scp->sec_lid)) == NULL) {
+	    SUBCHASSIS, (topo_instance_t)instance, NULL, auth, NULL, NULL,
+	    NULL)) == NULL) {
 		topo_mod_dprintf(mod, "topo_mod_hcfmri() failed: %s",
 		    topo_mod_errmsg(mod));
 		goto error;
@@ -944,11 +1603,25 @@
 	if (topo_node_label_set(tn, desc, &err) != 0)
 		goto error;
 
-	if (ses_set_standard_props(mod, tn, NULL,
+	if (ses_set_standard_props(mod, NULL, tn, NULL,
 	    ses_node_id(scp->sec_enclosure), scp->sec_target->set_devpath) != 0)
 		goto error;
 
 	/*
+	 * Set the 'chassis-type' property for this subchassis.  This is either
+	 * 'ses-class-description' or 'subchassis'.
+	 */
+	if (nvlist_lookup_string(props, SES_PROP_CLASS_DESCRIPTION, &desc) != 0)
+		desc = "subchassis";
+
+	if (topo_prop_set_string(tn, TOPO_PGROUP_SES,
+	    TOPO_PROP_CHASSIS_TYPE, TOPO_PROP_IMMUTABLE, desc, &err) != 0) {
+		topo_mod_dprintf(mod, "failed to create property %s: %s\n",
+		    TOPO_PROP_CHASSIS_TYPE, topo_strerror(err));
+		goto error;
+	}
+
+	/*
 	 * For enclosures, we want to include all possible targets (for upgrade
 	 * purposes).
 	 */
@@ -1115,7 +1788,7 @@
 		goto error;
 	}
 
-	if (ses_set_standard_props(mod, tn, auth,
+	if (ses_set_standard_props(mod, NULL, tn, auth,
 	    ses_node_id(cp->sec_enclosure), cp->sec_target->set_devpath) != 0)
 		goto error;
 
@@ -1145,7 +1818,9 @@
 	}
 
 	/*
-	 * Create the nodes for power supplies, fans, and devices.
+	 * Create the nodes for power supplies, fans, controllers and devices.
+	 * Note that SAS exopander nodes and connector nodes are handled
+	 * through protocol specific processing of controllers.
 	 */
 	if (ses_create_children(sdp, tn, SES_ET_POWER_SUPPLY,
 	    PSU, "PSU", cp, B_TRUE) != 0 ||
@@ -1159,9 +1834,9 @@
 	    BAY, "BAY", cp, B_TRUE) != 0)
 		goto error;
 
-	if (cp->sec_scinstance > 0 &&
-	    topo_node_range_create(mod, tn, SUBCHASSIS, 0,
-	    cp->sec_scinstance - 1) != 0) {
+	if (cp->sec_maxinstance >= 0 &&
+	    (topo_node_range_create(mod, tn, SUBCHASSIS, 0,
+	    cp->sec_maxinstance) != 0)) {
 		topo_mod_dprintf(mod, "topo_node_create_range() failed: %s",
 		    topo_mod_errmsg(mod));
 		goto error;
@@ -1174,8 +1849,9 @@
 			goto error;
 
 		topo_mod_dprintf(mod, "created Subchassis node with "
-		    "LID (%s)\n  and target (%s) under Chassis with CSN (%s)",
-		    scp->sec_lid, scp->sec_target->set_devpath, cp->sec_csn);
+		    "instance %u\nand target (%s) under Chassis with CSN %s",
+		    scp->sec_instance, scp->sec_target->set_devpath,
+		    cp->sec_csn);
 
 		sc_count++;
 	}
@@ -1238,21 +1914,22 @@
 static int
 ses_init_chassis(topo_mod_t *mod, ses_enum_data_t *sdp, ses_enum_chassis_t *pcp,
     ses_enum_chassis_t *cp, ses_node_t *np, nvlist_t *props,
-    char *lid, ses_chassis_type_e flags)
+    uint64_t subchassis, ses_chassis_type_e flags)
 {
 	boolean_t internal, ident;
 
 	assert((flags & (SES_NEW_CHASSIS | SES_NEW_SUBCHASSIS |
 	    SES_DUP_CHASSIS | SES_DUP_SUBCHASSIS)) != 0);
 
-	assert((cp != NULL) && (np != NULL) && (props != NULL) &&
-	    (lid != NULL));
+	assert(cp != NULL);
+	assert(np != NULL);
+	assert(props != NULL);
 
 	if (flags & (SES_NEW_SUBCHASSIS | SES_DUP_SUBCHASSIS))
 		assert(pcp != NULL);
 
-	topo_mod_dprintf(mod, "ses_init_chassis: %s: lid(%s), flags (%d)",
-	    sdp->sed_name, lid, flags);
+	topo_mod_dprintf(mod, "ses_init_chassis: %s: index %llu, flags (%d)",
+	    sdp->sed_name, subchassis, flags);
 
 	if (flags & (SES_NEW_CHASSIS | SES_NEW_SUBCHASSIS)) {
 
@@ -1261,15 +1938,22 @@
 		    LIBSES_EN_PROP_INTERNAL, &internal) == 0)
 			cp->sec_internal = internal;
 
-		cp->sec_lid = lid;
 		cp->sec_enclosure = np;
 		cp->sec_target = sdp->sed_target;
 
 		if (flags & SES_NEW_CHASSIS) {
-			cp->sec_instance = sdp->sed_instance++;
+			if (!cp->sec_internal)
+				cp->sec_instance = sdp->sed_instance++;
 			topo_list_append(&sdp->sed_chassis, cp);
 		} else {
-			cp->sec_instance = pcp->sec_scinstance++;
+			if (subchassis != NO_SUBCHASSIS)
+				cp->sec_instance = subchassis;
+			else
+				cp->sec_instance = pcp->sec_scinstance++;
+
+			if (cp->sec_instance > pcp->sec_maxinstance)
+				pcp->sec_maxinstance = cp->sec_instance;
+
 			topo_list_append(&pcp->sec_subchassis, cp);
 		}
 
@@ -1307,8 +1991,7 @@
 	uint64_t instance, type;
 	uint64_t prevstatus, status;
 	boolean_t report;
-	boolean_t have_subchassis = B_TRUE;
-	char *lid;
+	uint64_t subchassis = NO_SUBCHASSIS;
 
 	if (ses_node_type(np) == SES_NODE_ENCLOSURE) {
 		/*
@@ -1328,14 +2011,12 @@
 		    &csn) != 0)
 			return (SES_WALK_ACTION_TERMINATE);
 
-		if (nvlist_lookup_string(props, LIBSES_EN_PROP_SUBCHASSIS_ID,
-		    &lid) != 0) {
-			have_subchassis = B_FALSE;
-			lid = "";
-		}
+		(void) nvlist_lookup_uint64(props, LIBSES_EN_PROP_SUBCHASSIS_ID,
+		    &subchassis);
 
 		topo_mod_dprintf(mod, "ses_enum_gather: Enclosure Node (%s) "
-		    "CSN (%s), LID (%s)", sdp->sed_name, csn, lid);
+		    "CSN (%s), subchassis (%llu)", sdp->sed_name, csn,
+		    subchassis);
 
 		/*
 		 * We need to determine whether this enclosure node
@@ -1376,24 +2057,26 @@
 			    sizeof (ses_enum_chassis_t))) == NULL)
 				goto error;
 
+			cp->sec_scinstance = SES_STARTING_SUBCHASSIS;
+			cp->sec_maxinstance = -1;
 			cp->sec_csn = csn;
 
-			if (!have_subchassis || strcmp(csn, lid) == 0) {
+			if (subchassis == NO_SUBCHASSIS) {
 				/* 1.1 This is a new chassis */
 
 				topo_mod_dprintf(mod, "%s: Initialize new "
-				    "chassis with CSN (%s) and LID (%s)",
-				    sdp->sed_name, csn, lid);
+				    "chassis with CSN %s", sdp->sed_name, csn);
 
 				if (ses_init_chassis(mod, sdp, NULL, cp,
-				    np, props, lid, SES_NEW_CHASSIS) < 0)
+				    np, props, NO_SUBCHASSIS,
+				    SES_NEW_CHASSIS) < 0)
 					goto error;
 			} else {
 				/* 1.2 This is a new subchassis */
 
 				topo_mod_dprintf(mod, "%s: Initialize new "
-				    "subchassis with CSN (%s) and LID (%s)",
-				    sdp->sed_name, csn, lid);
+				    "subchassis with CSN %s and index %llu",
+				    sdp->sed_name, csn, subchassis);
 
 				if ((scp = topo_mod_zalloc(mod,
 				    sizeof (ses_enum_chassis_t))) == NULL)
@@ -1401,39 +2084,41 @@
 
 				scp->sec_csn = csn;
 
-				if (ses_init_chassis(mod, sdp, cp, scp,
-				    np, props, lid, SES_NEW_SUBCHASSIS) < 0)
+				if (ses_init_chassis(mod, sdp, cp, scp, np,
+				    props, subchassis, SES_NEW_SUBCHASSIS) < 0)
 					goto error;
 			}
 		} else {
-			/* 2. We have a chassis with this CSN */
-
-			if (!have_subchassis || strcmp(csn, lid) == 0) {
-				/* This is a chassis */
-
-				if (!have_subchassis ||
-				    strlen(cp->sec_lid) > 0) {
+			/*
+			 * We have a chassis or subchassis with this CSN.  If
+			 * it's a chassis, we must check to see whether it is
+			 * a placeholder previously created because we found a
+			 * subchassis with this CSN.  We will know that because
+			 * the sec_target value will not be set; it is set only
+			 * in ses_init_chassis().  In that case, initialise it
+			 * as a new chassis; otherwise, it's a duplicate and we
+			 * need to append only.
+			 */
+			if (subchassis == NO_SUBCHASSIS) {
+				if (cp->sec_target != NULL) {
 					/* 2.1 This is a duplicate chassis */
 
 					topo_mod_dprintf(mod, "%s: Append "
-					    "duplicate chassis with CSN (%s) "
-					    "and LID (%s)",
-					    sdp->sed_name, csn, lid);
+					    "duplicate chassis with CSN (%s)",
+					    sdp->sed_name, csn);
 
 					if (ses_init_chassis(mod, sdp, NULL, cp,
-					    np, props, lid,
+					    np, props, NO_SUBCHASSIS,
 					    SES_DUP_CHASSIS) < 0)
 						goto error;
 				} else {
-					/* 2.2 Init the placeholder chassis */
-
+					/* Placeholder chassis - init it up */
 					topo_mod_dprintf(mod, "%s: Initialize"
-					    "placeholder chassis with CSN (%s) "
-					    "and LID (%s)",
-					    sdp->sed_name, csn, lid);
+					    "placeholder chassis with CSN %s",
+					    sdp->sed_name, csn);
 
-					if (ses_init_chassis(mod, sdp, NULL, cp,
-					    np, props, lid,
+					if (ses_init_chassis(mod, sdp, NULL,
+					    cp, np, props, NO_SUBCHASSIS,
 					    SES_NEW_CHASSIS) < 0)
 						goto error;
 
@@ -1443,7 +2128,7 @@
 
 				for (scp = topo_list_next(&cp->sec_subchassis);
 				    scp != NULL; scp = topo_list_next(scp))
-					if (strcmp(scp->sec_lid, lid) == 0)
+					if (scp->sec_instance == subchassis)
 						break;
 
 				if (scp == NULL) {
@@ -1452,7 +2137,7 @@
 					topo_mod_dprintf(mod, "%s: Initialize "
 					    "new subchassis with CSN (%s) "
 					    "and LID (%s)",
-					    sdp->sed_name, csn, lid);
+					    sdp->sed_name, csn);
 
 					if ((scp = topo_mod_zalloc(mod,
 					    sizeof (ses_enum_chassis_t)))
@@ -1462,7 +2147,7 @@
 					scp->sec_csn = csn;
 
 					if (ses_init_chassis(mod, sdp, cp, scp,
-					    np, props, lid,
+					    np, props, subchassis,
 					    SES_NEW_SUBCHASSIS) < 0)
 						goto error;
 				} else {
@@ -1470,11 +2155,10 @@
 
 					topo_mod_dprintf(mod, "%s: Append "
 					    "duplicate subchassis with "
-					    "CSN (%s) and LID (%s)",
-					    sdp->sed_name, csn, lid);
+					    "CSN (%s)", sdp->sed_name, csn);
 
 					if (ses_init_chassis(mod, sdp, cp, scp,
-					    np, props, lid,
+					    np, props, subchassis,
 					    SES_DUP_SUBCHASSIS) < 0)
 						goto error;
 				}
@@ -1498,7 +2182,9 @@
 		    type != SES_ET_ARRAY_DEVICE &&
 		    type != SES_ET_COOLING &&
 		    type != SES_ET_POWER_SUPPLY &&
-		    type != SES_ET_ESC_ELECTRONICS)
+		    type != SES_ET_ESC_ELECTRONICS &&
+		    type != SES_ET_SAS_EXPANDER &&
+		    type != SES_ET_SAS_CONNECTOR)
 			return (SES_WALK_ACTION_CONTINUE);
 
 		/*
@@ -1714,7 +2400,7 @@
 		data->sed_mod = mod;
 		topo_mod_setspecific(mod, data);
 
-		if (disk_list_gather(mod, &data->sed_disks) != 0)
+		if (dev_list_gather(mod, &data->sed_devs) != 0)
 			goto error;
 
 		/*
--- a/usr/src/lib/fm/topo/modules/common/ses/ses.h	Sun Apr 11 11:07:03 2010 +0800
+++ b/usr/src/lib/fm/topo/modules/common/ses/ses.h	Sun Apr 11 11:20:12 2010 -0700
@@ -20,8 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 #ifndef	_SES_H
@@ -60,8 +59,12 @@
 #define	TOPO_PGROUP_SES		"ses"
 #define	TOPO_PROP_NODE_ID	"node-id"
 #define	TOPO_PROP_TARGET_PATH	"target-path"
+#define	TOPO_PROP_PATHS		"paths"
 #define	TOPO_PROP_SAS_ADDR	"sas-address"
-#define	TOPO_PROP_PATHS		"paths"
+#define	TOPO_PROP_PHY_COUNT	"phy-count"
+#define	TOPO_PROP_CHASSIS_TYPE	"chassis-type"
+#define	TOPO_PROP_SAS_PHY_MASK	"phy-mask"
+#define	TOPO_PROP_SAS_CONNECTOR_TYPE	"sas-connector-type"
 
 #ifndef	NDEBUG
 #define	verify(x)	assert(x)
--- a/usr/src/lib/fm/topo/modules/i86pc/pcibus/Makefile	Sun Apr 11 11:07:03 2010 +0800
+++ b/usr/src/lib/fm/topo/modules/i86pc/pcibus/Makefile	Sun Apr 11 11:20:12 2010 -0700
@@ -29,7 +29,7 @@
 UTILDIR = ../../common/pcibus
 HBDIR = ../../common/hostbridge
 UTILSRCS = did.c did_hash.c did_props.c util.c
-PCISRCS = pcibus.c pcibus_labels.c
+PCISRCS = pcibus.c pcibus_labels.c pcibus_hba.c
 
 MODULESRCS = $(UTILSRCS) $(PCISRCS) pci_i86pc.c
 
--- a/usr/src/lib/fm/topo/modules/sun4/pcibus/Makefile.pci	Sun Apr 11 11:07:03 2010 +0800
+++ b/usr/src/lib/fm/topo/modules/sun4/pcibus/Makefile.pci	Sun Apr 11 11:20:12 2010 -0700
@@ -29,7 +29,7 @@
 UTILDIR = ../../common/pcibus
 HBDIR = ../../common/hostbridge
 UTILSRCS = did.c did_hash.c did_props.c util.c
-PCISRCS = pcibus.c pcibus_labels.c pci_sun4.c
+PCISRCS = pcibus.c pcibus_labels.c pci_sun4.c pcibus_hba.c
 
 MODULESRCS = $(PCISRCS) $(UTILSRCS) pci_$(ARCH).c
 
--- a/usr/src/lib/libfru/libfruraw/fruraw.c	Sun Apr 11 11:07:03 2010 +0800
+++ b/usr/src/lib/libfru/libfruraw/fruraw.c	Sun Apr 11 11:20:12 2010 -0700
@@ -20,8 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 #include <stdio.h>
@@ -551,8 +550,9 @@
 		for (each_seg = 0; each_seg < num_segment; each_seg++) {
 			if (segs[each_seg].handle == node) {
 				segs[each_seg].name[FRU_SEGNAMELEN] = '\0';
-				*name = segs[each_seg].name;
+				*name = strdup(segs[each_seg].name);
 				free(sects);
+				free(segs);
 				return (FRU_SUCCESS);
 			}
 		}
--- a/usr/src/lib/libfru/libfruraw/raw_access.c	Sun Apr 11 11:07:03 2010 +0800
+++ b/usr/src/lib/libfru/libfruraw/raw_access.c	Sun Apr 11 11:20:12 2010 -0700
@@ -20,8 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 #include <stdio.h>
@@ -1197,12 +1196,10 @@
 			}
 		}
 
-		free(sec_hash_obj->u.sec_obj); /* free section hash object */
-
 		prev_hash = sec_hash_obj;
-
 		sec_hash_obj = sec_hash_obj->u.sec_obj->next;
 
+		free(prev_hash->u.sec_obj); /* free section hash object */
 		free(prev_hash); /* free section hash */
 	}
 
--- a/usr/src/lib/libfru/libnvfru/nvfru.c	Sun Apr 11 11:07:03 2010 +0800
+++ b/usr/src/lib/libfru/libnvfru/nvfru.c	Sun Apr 11 11:20:12 2010 -0700
@@ -20,8 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 #include <stdio.h>
@@ -188,7 +187,7 @@
 			return;
 		for (i = head, n = 0, data += sizeof (uint32_t); n < num;
 		    i = ((i + 1) % def->iterationCount), n++) {
-			if (nvlist_alloc(&nv_elems[n], 0, 0) != 0)
+			if (nvlist_alloc(&nv_elems[n], NV_UNIQUE_NAME, 0) != 0)
 				return;
 			(void) snprintf(num_str, sizeof (num_str), "%d", n);
 			convert_element((data + i*iterlen), &newdef, num_str,
@@ -201,7 +200,7 @@
 		nvlist_t *nv_record;
 
 		if (!from_iter) {
-			if (nvlist_alloc(&nv_record, 0, 0) != 0) {
+			if (nvlist_alloc(&nv_record, NV_UNIQUE_NAME, 0) != 0) {
 				return;
 			}
 		} else {
@@ -323,7 +322,7 @@
 	}
 
 	/* create a new nvlist for each segment */
-	ret = nvlist_alloc(&nv_segment, 0, 0);
+	ret = nvlist_alloc(&nv_segment, NV_UNIQUE_NAME, 0);
 	if (ret) {
 		free(name);
 		return (FRU_FAILURE);
@@ -361,7 +360,7 @@
 		return (-1);
 	}
 
-	err = nvlist_alloc(&nv, 0, 0);
+	err = nvlist_alloc(&nv, NV_UNIQUE_NAME, 0);
 	if (err) {
 		return (err);
 	}
--- a/usr/src/lib/scsi/Makefile	Sun Apr 11 11:07:03 2010 +0800
+++ b/usr/src/lib/scsi/Makefile	Sun Apr 11 11:20:12 2010 -0700
@@ -20,14 +20,13 @@
 #
 
 #
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
+# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
 #
-# ident	"%Z%%M%	%I%	%E% SMI"
 
 SUBDIRS = \
 	libscsi	\
 	libses \
+	libsmp \
 	plugins
 
 .KEEP_STATE:
@@ -36,6 +35,6 @@
 
 libses: libscsi
 
-plugins: libscsi libses
+plugins: libscsi libses libsmp
 
 include Makefile.subdirs
--- a/usr/src/lib/scsi/Makefile.rootdirs	Sun Apr 11 11:07:03 2010 +0800
+++ b/usr/src/lib/scsi/Makefile.rootdirs	Sun Apr 11 11:20:12 2010 -0700
@@ -19,10 +19,8 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
+# Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
 #
-# ident	"%Z%%M%	%I%	%E% SMI"
 
 #
 # Define the transitive set of rules to create a common module's install dir
@@ -56,6 +54,27 @@
 $(ROOTPLUGINLIBDIR)/ses/vendor/$(MACH64): $(ROOTPLUGINLIBDIR)/ses/vendor
 	$(INS.dir)
 
+$(ROOTPLUGINLIBDIR)/smp: $(ROOTPLUGINLIBDIR)
+	$(INS.dir)
+
+$(ROOTPLUGINLIBDIR)/smp/engine: $(ROOTPLUGINLIBDIR)/smp
+	$(INS.dir)
+
+$(ROOTPLUGINLIBDIR)/smp/engine/$(MACH64): $(ROOTPLUGINLIBDIR)/smp/engine
+	$(INS.dir)
+
+$(ROOTPLUGINLIBDIR)/smp/framework: $(ROOTPLUGINLIBDIR)/smp
+	$(INS.dir)
+
+$(ROOTPLUGINLIBDIR)/smp/framework/$(MACH64): $(ROOTPLUGINLIBDIR)/smp/framework
+	$(INS.dir)
+
+$(ROOTPLUGINLIBDIR)/smp/vendor: $(ROOTPLUGINLIBDIR)/smp
+	$(INS.dir)
+
+$(ROOTPLUGINLIBDIR)/smp/vendor/$(MACH64): $(ROOTPLUGINLIBDIR)/smp/vendor
+	$(INS.dir)
+
 $(ROOTPLUGINHDRDIR):
 	$(INS.dir)
 
@@ -67,3 +86,16 @@
 
 $(ROOTPLUGINHDRDIR)/ses/vendor: $(ROOTPLUGINHDRDIR)/ses
 	$(INS.dir)
+
+$(ROOTPLUGINHDRDIR)/smp: $(ROOTPLUGINHDRDIR)
+	$(INS.dir)
+
+$(ROOTPLUGINHDRDIR)/smp/engine: $(ROOTPLUGINHDRDIR)/smp
+	$(INS.dir)
+
+$(ROOTPLUGINHDRDIR)/smp/framework: $(ROOTPLUGINHDRDIR)/smp
+	$(INS.dir)
+
+$(ROOTPLUGINHDRDIR)/smp/vendor: $(ROOTPLUGINHDRDIR)/smp
+	$(INS.dir)
+
--- a/usr/src/lib/scsi/libscsi/common/libscsi.h	Sun Apr 11 11:07:03 2010 +0800
+++ b/usr/src/lib/scsi/libscsi/common/libscsi.h	Sun Apr 11 11:20:12 2010 -0700
@@ -20,15 +20,12 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 #ifndef	_LIBSCSI_H
 #define	_LIBSCSI_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #ifdef	__cplusplus
 extern "C" {
 #endif
@@ -95,9 +92,6 @@
 struct libscsi_action;
 typedef struct libscsi_action libscsi_action_t;
 
-struct libscsi_result;
-typedef struct libscsi_result libscsi_result_t;
-
 typedef struct libscsi_engine_ops {
 	void *(*lseo_open)(libscsi_hdl_t *, const void *);
 	void (*lseo_close)(libscsi_hdl_t *, void *);
--- a/usr/src/lib/scsi/libscsi/common/scsi_engine.c	Sun Apr 11 11:07:03 2010 +0800
+++ b/usr/src/lib/scsi/libscsi/common/scsi_engine.c	Sun Apr 11 11:20:12 2010 -0700
@@ -20,12 +20,9 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <sys/types.h>
 #include <sys/isa_defs.h>
 #include <sys/systeminfo.h>
@@ -73,8 +70,8 @@
 	isa[0] = '\0';
 #endif
 
-	for (p = engine_path, q = strchr(p, ':'); p != NULL; p = q) {
-		if (q != NULL) {
+	for (p = engine_path; p != NULL; p = q) {
+		if ((q = strchr(p, ':')) != NULL) {
 			ptrdiff_t len = q - p;
 			(void) strncpy(engine_dir, p, len);
 			engine_dir[len] = '\0';
--- a/usr/src/lib/scsi/libscsi/common/scsi_subr.c	Sun Apr 11 11:07:03 2010 +0800
+++ b/usr/src/lib/scsi/libscsi/common/scsi_subr.c	Sun Apr 11 11:20:12 2010 -0700
@@ -20,12 +20,9 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <sys/types.h>
 #include <sys/scsi/generic/commands.h>
 #include <sys/scsi/impl/spc3_types.h>
@@ -300,12 +297,13 @@
 
 	if ((ap = libscsi_action_alloc(hp, SPC3_CMD_INQUIRY,
 	    LIBSCSI_AF_READ | LIBSCSI_AF_SILENT | LIBSCSI_AF_DIAGNOSE, &data,
-	    sizeof (data))) == NULL)
+	    offsetof(spc3_inquiry_data_t, id_vs_36[0]))) == NULL)
 		return (-1);
 
 	cp = (spc3_inquiry_cdb_t *)libscsi_action_get_cdb(ap);
 
-	SCSI_WRITE16(&cp->ic_allocation_length, sizeof (data));
+	SCSI_WRITE16(&cp->ic_allocation_length,
+	    offsetof(spc3_inquiry_data_t, id_vs_36[0]));
 
 	if (libscsi_exec(ap, tp) != 0 ||
 	    libscsi_action_get_status(ap) != 0) {
--- a/usr/src/lib/scsi/libses/Makefile.defs	Sun Apr 11 11:07:03 2010 +0800
+++ b/usr/src/lib/scsi/libses/Makefile.defs	Sun Apr 11 11:20:12 2010 -0700
@@ -20,10 +20,8 @@
 #
 
 #
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
+# Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
 #
-# ident	"%Z%%M%	%I%	%E% SMI"
 
 SRCS = $(OBJECTS:%.o=../common/%.c)
 C99MODE = $(C99_ENABLE)
@@ -43,6 +41,7 @@
 LDLIBS += \
 	-lnvpair \
 	-lscsi \
+	-lumem \
 	-lc
 
 LIBS =		$(DYNLIB) $(LINTLIB)
--- a/usr/src/lib/scsi/libses/common/libses_plugin.h	Sun Apr 11 11:07:03 2010 +0800
+++ b/usr/src/lib/scsi/libses/common/libses_plugin.h	Sun Apr 11 11:20:12 2010 -0700
@@ -20,15 +20,12 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 #ifndef	_LIBSES_PLUGIN_H
 #define	_LIBSES_PLUGIN_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #ifdef	__cplusplus
 extern "C" {
 #endif
@@ -47,6 +44,13 @@
 	SES_PAGE_CTL
 } ses_pagetype_t;
 
+typedef enum ses_page_req {
+	SES_REQ_OPTIONAL,
+	SES_REQ_MANDATORY_ALL,
+	SES_REQ_MANDATORY_STANDARD,
+	SES_REQ_OPTIONAL_STANDARD
+} ses_page_req_t;
+
 typedef struct ses_pagedesc {
 	int		spd_pagenum;
 	size_t		(*spd_ctl_len)(uint_t, int, size_t);
@@ -55,6 +59,7 @@
 	void		*(*spd_index)(ses_plugin_t *, ses_node_t *,
 	    void *, size_t, size_t *);
 	int		spd_gcoff;
+	ses_page_req_t	spd_req;
 } ses_pagedesc_t;
 
 typedef struct ses_plugin_config {
--- a/usr/src/lib/scsi/libses/common/ses_node.c	Sun Apr 11 11:07:03 2010 +0800
+++ b/usr/src/lib/scsi/libses/common/ses_node.c	Sun Apr 11 11:20:12 2010 -0700
@@ -20,12 +20,9 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <scsi/libses.h>
 #include "ses_impl.h"
 
@@ -145,7 +142,7 @@
 	off_t toff;
 	char *tp, *text;
 	int err;
-	uint64_t idx;
+	uint64_t idx, eidx;
 
 	pp = ses_snap_find_page(sp, SES2_DIAGPAGE_CONFIG, B_FALSE);
 	if (pp == NULL)
@@ -221,7 +218,7 @@
 
 	tp = (char *)(ftip + n_etds);
 
-	for (i = 0, toff = 0, idx = 0; i < n_etds; i++) {
+	for (i = 0, toff = 0, idx = eidx = 0; i < n_etds; i++) {
 		tip = ftip + i;
 
 		if (!SES_WITHIN_PAGE_STRUCT(tip, pp->ssp_page, pp->ssp_len))
@@ -231,6 +228,7 @@
 		    tip->sthi_subenclosure_id);
 		if (pnp == NULL) {
 			idx += tip->sthi_max_elements + 1;
+			eidx += tip->sthi_max_elements;
 			toff += tip->sthi_text_len;
 			continue;
 		}
@@ -243,6 +241,8 @@
 			} else {
 				SES_NV_ADD(uint64, err, pnp->sn_props,
 				    SES_PROP_ELEMENT_INDEX, idx + 1);
+				SES_NV_ADD(uint64, err, pnp->sn_props,
+				    SES_PROP_ELEMENT_ONLY_INDEX, eidx);
 				pnp->sn_rootidx = idx + 1;
 			}
 
@@ -261,6 +261,7 @@
 				return (-1);
 
 			idx += tip->sthi_max_elements + 1;
+			eidx += tip->sthi_max_elements;
 			continue;
 		}
 
@@ -303,10 +304,14 @@
 			SES_NV_ADD(uint64, err, cnp->sn_props,
 			    SES_PROP_ELEMENT_INDEX, np->sn_rootidx + j + 1);
 			SES_NV_ADD(uint64, err, cnp->sn_props,
+			    SES_PROP_ELEMENT_ONLY_INDEX, eidx + j);
+			SES_NV_ADD(uint64, err, cnp->sn_props,
 			    SES_PROP_ELEMENT_CLASS_INDEX, j);
 			SES_NV_ADD(uint64, err, cnp->sn_props,
 			    SES_PROP_ELEMENT_TYPE, tip->sthi_element_type);
 		}
+
+		eidx += tip->sthi_max_elements;
 	}
 
 	np->sn_snapshot->ss_n_elem = idx;
--- a/usr/src/lib/scsi/libses/common/ses_plugin.c	Sun Apr 11 11:07:03 2010 +0800
+++ b/usr/src/lib/scsi/libses/common/ses_plugin.c	Sun Apr 11 11:20:12 2010 -0700
@@ -20,12 +20,9 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <scsi/libses.h>
 #include "ses_impl.h"
 
@@ -358,8 +355,8 @@
 		pluginpath = LIBSES_DEFAULT_PLUGINDIR;
 	ses_plugin_dlclose = (getenv("SES_NODLCLOSE") == NULL);
 
-	for (p = pluginpath, q = strchr(p, ':'); p != NULL; p = q) {
-		if (q != NULL) {
+	for (p = pluginpath; p != NULL; p = q) {
+		if ((q = strchr(p, ':')) != NULL) {
 			ptrdiff_t len = q - p;
 			(void) strncpy(pluginroot, p, len);
 			pluginroot[len] = '\0';
@@ -376,7 +373,7 @@
 		if (pluginroot[0] != '/')
 			continue;
 
-		if (ses_plugin_load_dir(tp, pluginpath) != 0)
+		if (ses_plugin_load_dir(tp, pluginroot) != 0)
 			return (-1);
 	}
 
--- a/usr/src/lib/scsi/libses/common/ses_snap.c	Sun Apr 11 11:07:03 2010 +0800
+++ b/usr/src/lib/scsi/libses/common/ses_snap.c	Sun Apr 11 11:20:12 2010 -0700
@@ -20,12 +20,9 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <scsi/libses.h>
 #include "ses_impl.h"
 
@@ -158,7 +155,7 @@
 	ASSERT(dp != NULL);
 
 	len = dp->spd_ctl_len(sp->ss_n_elem, page, dlen);
-	if (pp->ssp_alloc < dlen && grow_snap_page(pp, len) != 0)
+	if (pp->ssp_alloc < len && grow_snap_page(pp, len) != 0)
 		return (NULL);
 	pp->ssp_len = len;
 	bzero(pp->ssp_page, len);
@@ -239,7 +236,7 @@
 	ASSERT(buf == pp->ssp_page);
 	ASSERT(alloc == pp->ssp_alloc);
 
-	if (pp->ssp_len == pp->ssp_alloc && pp->ssp_alloc < UINT16_MAX) {
+	if (pp->ssp_alloc - pp->ssp_len < 0x80 && pp->ssp_alloc < UINT16_MAX) {
 		bzero(pp->ssp_page, pp->ssp_len);
 		pp->ssp_len = 0;
 		if (grow_snap_page(pp, 0) != 0)
@@ -247,6 +244,13 @@
 		goto again;
 	}
 
+	if (pp->ssp_len < offsetof(spc3_diag_page_impl_t, sdpi_data)) {
+		bzero(pp->ssp_page, pp->ssp_len);
+		pp->ssp_len = 0;
+		return (ses_error(ESES_BAD_RESPONSE, "target returned "
+		    "truncated page 0x%x (length %d)", page, pp->ssp_len));
+	}
+
 	pip = (spc3_diag_page_impl_t *)buf;
 
 	if (pip->sdpi_page_code == page)
@@ -447,6 +451,7 @@
 	ses_pagedesc_t *dp;
 	size_t pages, pagesize, pagelen;
 	char *scratch;
+	boolean_t simple;
 
 	if ((sp = ses_zalloc(sizeof (ses_snap_t))) == NULL)
 		return (NULL);
@@ -464,6 +469,16 @@
 	sp->ss_generation = (uint32_t)-1;
 	sp->ss_time = gethrtime();
 
+	/*
+	 * First check for the short enclosure status diagnostic page and
+	 * determine if this is a simple subenclosure or not.
+	 */
+	simple = B_FALSE;
+	for (pp = sp->ss_pages; pp != NULL; pp = pp->ssp_next) {
+		if (pp->ssp_num == SES2_DIAGPAGE_SHORT_STATUS)
+			simple = B_TRUE;
+	}
+
 	for (pp = sp->ss_pages; pp != NULL; pp = pp->ssp_next) {
 		/*
 		 * We skip all of:
@@ -478,8 +493,20 @@
 		    SES_PAGE_DIAG)) == NULL)
 			continue;
 
-		if (read_status_page(sp, pp->ssp_num) != 0)
+		if (read_status_page(sp, pp->ssp_num) != 0)  {
+			/*
+			 * If this page is required, and this is not a simple
+			 * subenclosure, then fail the entire snapshot.
+			 */
+			if (dp->spd_req == SES_REQ_MANDATORY_ALL ||
+			    (dp->spd_req == SES_REQ_MANDATORY_STANDARD &&
+			    !simple)) {
+				ses_snap_free(sp);
+				return (NULL);
+			}
+
 			continue;
+		}
 
 		/*
 		 * If the generation code has changed, we don't have a valid
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/scsi/libsmp/Makefile	Sun Apr 11 11:20:12 2010 -0700
@@ -0,0 +1,59 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+include	../../Makefile.lib
+include	../Makefile.defs
+
+HDRS =		libsmp.h libsmp_plugin.h
+ROOTHDRDIR =	$(ROOTSCSIHDRDIR)
+ROOTHDRS =	$(HDRS:%=$(ROOTHDRDIR)/%)
+CHECKDIRS =	$(HDRS:%.h=%.check)
+HDRDIR =	common
+
+SUBDIRS =	$(MACH)
+$(BUILD64)SUBDIRS += $(MACH64)
+
+all :=		TARGET= all
+clean :=	TARGET= clean
+clobber :=	TARGET= clobber
+install :=	TARGET= install
+lint :=		TARGET= lint
+install_h:=	TARGET = install_h
+
+.KEEP_STATE:
+
+all install clean clobber lint: $(SUBDIRS)
+
+install_h: $(ROOTHDRS)
+
+check:		$(CHECKHDRS)
+
+$(SUBDIRS):	FRC
+	@cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
+
+include ../Makefile.rootdirs
+include ../../Makefile.targ
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/scsi/libsmp/Makefile.com	Sun Apr 11 11:20:12 2010 -0700
@@ -0,0 +1,76 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+LIBRARY = libsmp.a
+VERS = .1
+
+OBJECTS = \
+	smp_engine.o \
+	smp_errno.o \
+	smp_plugin.o \
+	smp_subr.o
+
+include ../../../Makefile.lib
+include ../../Makefile.defs
+
+SRCS = $(OBJECTS:%.o=../common/%.c)
+C99MODE = $(C99_ENABLE)
+CPPFLAGS += -I../common -I. -D_REENTRANT
+$(NOT_RELEASE_BUILD)CPPFLAGS += -DDEBUG
+CFLAGS += $(CCVERBOSE)
+LDLIBS += \
+	-lumem \
+	-lc
+LIBS =		$(DYNLIB) $(LINTLIB)
+ROOTLIBDIR =	$(ROOTSCSILIBDIR)
+ROOTLIBDIR64 =	$(ROOTSCSILIBDIR)/$(MACH64)
+
+CLEANFILES += \
+	../common/smp_errno.c
+
+#
+# On SPARC, gcc emits DWARF assembler directives for TLS data that are not
+# understood by the Sun assembler.  Until this problem is fixed, we turn down
+# the amount of generated debugging information, which seems to do the trick.
+#
+$(SPARC_BLD)CTF_FLAGS += -_gcc=-g1
+
+$(LINTLIB) :=	SRCS = $(SRCDIR)/$(LINTSRC)
+
+.KEEP_STATE:
+
+all : $(LIBS)
+
+lint : lintcheck
+
+../common/smp_errno.c: ../common/mkerrno.sh ../common/libsmp.h
+	sh ../common/mkerrno.sh < ../common/libsmp.h > $@
+
+pics/%.o: ../common/%.c
+	$(COMPILE.c) -o $@ $<
+	$(POST_PROCESS_O)
+
+include ../../../Makefile.targ
+include ../../Makefile.rootdirs
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/scsi/libsmp/amd64/Makefile	Sun Apr 11 11:20:12 2010 -0700
@@ -0,0 +1,29 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+include ../Makefile.com
+include ../../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT64)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/scsi/libsmp/common/libsmp.h	Sun Apr 11 11:20:12 2010 -0700
@@ -0,0 +1,125 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#ifndef	_LIBSMP_H
+#define	_LIBSMP_H
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+#include <sys/types.h>
+#include <sys/sysmacros.h>
+#include <sys/scsi/impl/usmp.h>
+#include <sys/scsi/generic/smp_frames.h>
+#include <libnvpair.h>
+#include <stdarg.h>
+
+#define	LIBSMP_VERSION		1
+
+#define	SMP_TARGET_C_LONG_RESP	0x01	/* Long response (SAS-2 10.4.3.4) */
+#define	SMP_TARGET_C_ZONING	0x02	/* Zoning supported */
+#define	SMP_TARGET_C_ZG_256	0x04	/* 256 zone groups supported */
+
+typedef enum smp_errno {
+	ESMP_NONE,		/* no error */
+	ESMP_NOMEM,		/* no memory */
+	ESMP_ZERO_LENGTH,	/* zero-length allocation requested */
+	ESMP_VERSION,		/* library version mismatch */
+	ESMP_BADTARGET,		/* invalid target specification */
+	ESMP_BADFUNC,		/* invalid SMP function */
+	ESMP_BADENGINE,		/* engine library corrupt */
+	ESMP_NOENGINE,		/* engine library not found */
+	ESMP_ENGINE_INIT,	/* engine initialization failed */
+	ESMP_ENGINE_VER,	/* engine version mismatch */
+	ESMP_ENGINE_BADPATH,	/* engine path contains no usable components */
+	ESMP_BADLENGTH,		/* buffer length overflow or size error */
+	ESMP_NEEDBUF,		/* missing required buffer */
+	ESMP_PLUGIN,		/* no plugins found */
+	ESMP_IO,		/* I/O operation failed */
+	ESMP_SYS,		/* system call failed */
+	ESMP_PERM,		/* insufficient permissions */
+	ESMP_RANGE,		/* parameter outside valid range */
+	ESMP_NOTSUP,		/* operation not supported */
+	ESMP_UNKNOWN,		/* error of unknown type */
+	ESMP_REPGEN_FAILED,	/* initial report general command failed */
+	ESMP_MAX		/* maximum libsmp errno value */
+} smp_errno_t;
+
+typedef struct smp_target_def {
+	const char *std_engine;
+	const void *std_def;
+} smp_target_def_t;
+
+struct smp_target;
+typedef struct smp_target smp_target_t;
+
+struct smp_action;
+typedef struct smp_action smp_action_t;
+
+extern int smp_init(int);
+extern void smp_fini(void);
+
+extern smp_target_t *smp_open(const smp_target_def_t *);
+extern uint_t smp_target_getcap(const smp_target_t *);
+extern uint16_t smp_target_get_change_count(const smp_target_t *);
+extern void smp_target_set_change_count(smp_target_t *, uint16_t);
+extern const char *smp_target_vendor(const smp_target_t *);
+extern const char *smp_target_product(const smp_target_t *);
+extern const char *smp_target_revision(const smp_target_t *);
+extern const char *smp_target_component_vendor(const smp_target_t *);
+extern uint16_t smp_target_component_id(const smp_target_t *);
+extern uint8_t smp_target_component_revision(const smp_target_t *);
+extern void smp_target_name(const smp_target_t *, char *, size_t);
+extern uint64_t smp_target_addr(const smp_target_t *);
+extern void smp_close(smp_target_t *);
+
+extern smp_errno_t smp_errno(void);
+extern smp_errno_t smp_errcode(const char *);
+extern const char *smp_errmsg(void);
+extern const char *smp_strerror(smp_errno_t);
+extern const char *smp_errname(smp_errno_t);
+
+extern char *smp_trim_strdup(const char *, size_t);
+
+extern smp_action_t *smp_action_alloc(smp_function_t, smp_target_t *, size_t);
+extern smp_action_t *smp_action_xalloc(smp_function_t, smp_target_t *,
+    void *, size_t, void *, size_t);
+extern uint32_t smp_action_get_timeout(const smp_action_t *);
+extern void smp_action_set_timeout(smp_action_t *, uint32_t);
+extern void smp_action_get_request(const smp_action_t *, void **, size_t *);
+extern void smp_action_get_response(const smp_action_t *,
+    smp_result_t *, void **, size_t *);
+extern int smp_exec(smp_action_t *, smp_target_t *);
+extern void smp_action_free(smp_action_t *);
+
+extern nvlist_t *smp_discover(const smp_target_def_t **, size_t);
+extern nvlist_t *smp_discover_targets(smp_target_t **, size_t);
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* _LIBSMP_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/scsi/libsmp/common/libsmp_plugin.h	Sun Apr 11 11:20:12 2010 -0700
@@ -0,0 +1,132 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#ifndef	_LIBSMP_PLUGIN_H
+#define	_LIBSMP_PLUGIN_H
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+#include <sys/scsi/generic/smp_frames.h>
+#include <scsi/libsmp.h>
+
+#include <stddef.h>
+
+#define	LIBSMP_PLUGIN_VERSION	1
+#define	LIBSMP_ENGINE_VERSION	1
+
+#ifndef SMP_REQ_MINLEN
+#define	SMP_REQ_MINLEN	\
+	(offsetof(smp_request_frame_t, srf_data[0]) + sizeof (smp_crc_t))
+#endif
+#ifndef	SMP_RESP_MINLEN
+#define	SMP_RESP_MINLEN	\
+	(offsetof(smp_response_frame_t, srf_data[0]) + sizeof (smp_crc_t))
+#endif
+
+#define	VERIFY(x)	((void)((x) || smp_assert(#x, __FILE__, __LINE__)))
+
+#ifdef DEBUG
+#define	ASSERT(x)	VERIFY(x)
+#else
+#define	ASSERT(x)
+#endif
+
+struct smp_engine;
+typedef struct smp_engine smp_engine_t;
+
+struct smp_plugin;
+typedef struct smp_plugin smp_plugin_t;
+
+typedef struct smp_engine_ops {
+	void *(*seo_open)(const void *);
+	void (*seo_close)(void *);
+	int (*seo_exec)(void *, smp_action_t *);
+	void (*seo_target_name)(void *, char *, size_t);
+	uint64_t (*seo_target_addr)(void *);
+} smp_engine_ops_t;
+
+typedef struct smp_engine_config {
+	const char *sec_name;
+	const smp_engine_ops_t *sec_ops;
+} smp_engine_config_t;
+
+#define	SMP_FD_F_NEEDS_CHANGE_COUNT	0x0001
+#define	SMP_FD_F_PROVIDES_CHANGE_COUNT	0x0002
+#define	SMP_FD_F_READ			0x0004
+#define	SMP_FD_F_WRITE			0x0008
+
+typedef struct smp_function_def {
+	smp_function_t sfd_function;
+	uint_t sfd_capmask;
+	uint_t sfd_capset;
+	uint_t sfd_flags;
+	size_t (*sfd_rq_len)(size_t, smp_target_t *);
+	off_t (*sfd_rq_dataoff)(smp_action_t *, smp_target_t *);
+	void (*sfd_rq_setframe)(smp_action_t *, smp_target_t *);
+	size_t (*sfd_rs_datalen)(smp_action_t *, smp_target_t *);
+	off_t (*sfd_rs_dataoff)(smp_action_t *, smp_target_t *);
+	void (*sfd_rs_getparams)(smp_action_t *, smp_target_t *);
+} smp_function_def_t;
+
+typedef struct smp_plugin_config {
+	const char *spc_name;
+	smp_function_def_t *spc_functions;
+} smp_plugin_config_t;
+
+extern int smp_assert(const char *, const char *, int);
+
+extern void *smp_alloc(size_t);
+extern void *smp_zalloc(size_t);
+extern char *smp_strdup(const char *);
+extern void smp_free(void *);
+
+extern int smp_set_errno(smp_errno_t);
+extern int smp_verror(smp_errno_t, const char *, va_list);
+extern int smp_error(smp_errno_t, const char *, ...);
+
+extern void smp_action_get_request_frame(const smp_action_t *,
+    void **, size_t *);
+extern void smp_action_get_response_frame(const smp_action_t *,
+    void **, size_t *);
+extern void smp_action_set_response_len(smp_action_t *, size_t);
+extern void smp_action_set_result(smp_action_t *, smp_result_t);
+extern const smp_function_def_t *smp_action_get_function_def(
+    const smp_action_t *);
+
+extern int smp_engine_register(smp_engine_t *, int,
+    const smp_engine_config_t *);
+
+extern int smp_plugin_register(smp_plugin_t *, int,
+    const smp_plugin_config_t *);
+extern void smp_plugin_setspecific(smp_plugin_t *, void *);
+extern void *smp_plugin_getspecific(smp_plugin_t *);
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* _LIBSMP_PLUGIN_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/scsi/libsmp/common/mkerrno.sh	Sun Apr 11 11:20:12 2010 -0700
@@ -0,0 +1,85 @@
+#!/bin/sh
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+echo "\
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#pragma ident\t\"@(#)mkerrno.sh\t1.2\t08/07/31\tSMI\"
+
+#include <strings.h>
+#include <scsi/libsmp.h>
+
+static const struct {
+\tchar *name;\t\t/* error name */
+\tchar *msg;\t\t/* error message */
+} _smp_errstr[] = {"
+
+pattern='^	\(ESMP_[A-Z0-9_]*\),*'
+replace='	{ "\1",'
+open='	\/\* '
+openrepl='"'
+close=' \*\/$'
+closerepl='" },'
+
+( sed -n "s/$pattern/$replace/p" | sed -n "s/$open/$openrepl/p" |
+    sed -n "s/$close/$closerepl/p" ) || exit 1
+
+echo "\
+};\n\
+\n\
+static int _smp_nerrno = sizeof (_smp_errstr) /\n\
+    sizeof (_smp_errstr[0]);\n\
+\n\
+const char *
+smp_strerror(smp_errno_t err)
+{
+	return (err < 0 || err >= _smp_nerrno ? \"unknown error\" :
+	     _smp_errstr[err].msg);
+}
+
+const char *
+smp_errname(smp_errno_t err)
+{
+	return (err < 0 || err >= _smp_nerrno ? NULL :
+	     _smp_errstr[err].name);
+}
+
+smp_errno_t
+smp_errcode(const char *name)
+{
+	smp_errno_t err;
+
+	for (err = 0; err < _smp_nerrno; err++) {
+		if (strcmp(name, _smp_errstr[err].name) == 0)
+			return (err);
+	}
+
+	return (ESMP_UNKNOWN);
+}"
+
+exit 0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/scsi/libsmp/common/smp_engine.c	Sun Apr 11 11:20:12 2010 -0700
@@ -0,0 +1,723 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#include <sys/types.h>
+#include <sys/isa_defs.h>
+#include <sys/systeminfo.h>
+#include <sys/scsi/generic/smp_frames.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <strings.h>
+#include <dlfcn.h>
+#include <limits.h>
+#include <pthread.h>
+#include <synch.h>
+
+#include <scsi/libsmp.h>
+#include "smp_impl.h"
+
+static pthread_mutex_t _libsmp_lock = PTHREAD_MUTEX_INITIALIZER;
+static smp_engine_t *_libsmp_engines;
+static int _libsmp_refcnt;
+
+static boolean_t _libsmp_engine_dlclose;
+
+static void
+smp_engine_free(smp_engine_t *ep)
+{
+	if (ep == NULL)
+		return;
+
+	smp_free(ep->se_name);
+	smp_free(ep);
+}
+
+static void
+smp_engine_destroy(smp_engine_t *ep)
+{
+	smp_engine_t **pp;
+
+	ASSERT(MUTEX_HELD(&_libsmp_lock));
+
+	if (ep->se_fini != NULL)
+		ep->se_fini(ep);
+
+	if (_libsmp_engine_dlclose)
+		(void) dlclose(ep->se_object);
+
+	ASSERT(ep->se_refcnt == 0);
+	for (pp = &_libsmp_engines; *pp != NULL; pp = &((*pp)->se_next))
+		if (*pp == ep)
+			break;
+
+	if (*pp != NULL)
+		*pp = (*pp)->se_next;
+
+	smp_engine_free(ep);
+}
+
+void
+smp_engine_init(void)
+{
+	(void) pthread_mutex_lock(&_libsmp_lock);
+	++_libsmp_refcnt;
+	(void) pthread_mutex_unlock(&_libsmp_lock);
+}
+
+void
+smp_engine_fini(void)
+{
+	smp_engine_t *ep;
+
+	(void) pthread_mutex_lock(&_libsmp_lock);
+	ASSERT(_libsmp_refcnt > 0);
+	if (--_libsmp_refcnt == 0) {
+		while (_libsmp_engines != NULL) {
+			ep = _libsmp_engines;
+			_libsmp_engines = ep->se_next;
+			smp_engine_destroy(ep);
+		}
+	}
+	(void) pthread_mutex_unlock(&_libsmp_lock);
+}
+
+static int
+smp_engine_loadone(const char *path)
+{
+	smp_engine_t *ep;
+	void *obj;
+
+	ASSERT(MUTEX_HELD(&_libsmp_lock));
+
+	if ((obj = dlopen(path, RTLD_PARENT | RTLD_LOCAL | RTLD_LAZY)) == NULL)
+		return (smp_set_errno(ESMP_NOENGINE));
+
+	if ((ep = smp_zalloc(sizeof (smp_engine_t))) == NULL) {
+		(void) dlclose(obj);
+		return (-1);
+	}
+
+	ep->se_object = obj;
+	ep->se_init = (int (*)())dlsym(obj, "_smp_init");
+	ep->se_fini = (void (*)())dlsym(obj, "_smp_fini");
+
+	if (ep->se_init == NULL) {
+		smp_engine_free(ep);
+		return (smp_set_errno(ESMP_BADENGINE));
+	}
+
+	if (ep->se_init(ep) != 0) {
+		smp_engine_free(ep);
+		return (-1);
+	}
+
+	return (0);
+}
+
+int
+smp_engine_register(smp_engine_t *ep, int version,
+    const smp_engine_config_t *ecp)
+{
+	ASSERT(MUTEX_HELD(&_libsmp_lock));
+
+	if (version != LIBSMP_ENGINE_VERSION)
+		return (smp_set_errno(ESMP_VERSION));
+
+	ep->se_ops = ecp->sec_ops;
+	ep->se_name = smp_strdup(ecp->sec_name);
+
+	if (ep->se_name == NULL)
+		return (-1);
+
+	ep->se_next = _libsmp_engines;
+	_libsmp_engines = ep;
+
+	return (0);
+}
+
+static smp_engine_t *
+smp_engine_hold_cached(const char *name)
+{
+	smp_engine_t *ep;
+
+	ASSERT(MUTEX_HELD(&_libsmp_lock));
+
+	for (ep = _libsmp_engines; ep != NULL; ep = ep->se_next) {
+		if (strcmp(ep->se_name, name) == 0) {
+			++ep->se_refcnt;
+			return (ep);
+		}
+	}
+
+	(void) smp_set_errno(ESMP_NOENGINE);
+	return (NULL);
+}
+
+static smp_engine_t *
+smp_engine_hold(const char *name)
+{
+	smp_engine_t *ep;
+	const char *pluginpath, *p, *q;
+	char pluginroot[PATH_MAX];
+	char path[PATH_MAX];
+	char isa[257];
+
+	(void) pthread_mutex_lock(&_libsmp_lock);
+	ep = smp_engine_hold_cached(name);
+	if (ep != NULL) {
+		(void) pthread_mutex_unlock(&_libsmp_lock);
+		return (ep);
+	}
+
+#if defined(_LP64)
+	if (sysinfo(SI_ARCHITECTURE_64, isa, sizeof (isa)) < 0)
+		isa[0] = '\0';
+#else
+	isa[0] = '\0';
+#endif
+
+	if ((pluginpath = getenv("SMP_PLUGINPATH")) == NULL)
+		pluginpath = LIBSMP_DEFAULT_PLUGINDIR;
+
+	_libsmp_engine_dlclose = (getenv("SMP_NODLCLOSE") == NULL);
+
+	for (p = pluginpath; p != NULL; p = q) {
+		if ((q = strchr(p, ':')) != NULL) {
+			ptrdiff_t len = q - p;
+			(void) strncpy(pluginroot, p, len);
+			pluginroot[len] = '\0';
+			while (*q == ':')
+				++q;
+			if (*q == '\0')
+				q = NULL;
+			if (len == 0)
+				continue;
+		} else {
+			(void) strcpy(pluginroot, p);
+		}
+
+		if (pluginroot[0] != '/')
+			continue;
+
+		(void) snprintf(path, PATH_MAX, "%s/%s/%s/%s%s",
+		    pluginroot, LIBSMP_PLUGIN_ENGINE,
+		    isa, name, LIBSMP_PLUGIN_EXT);
+
+		if (smp_engine_loadone(path) == 0) {
+			ep = smp_engine_hold_cached(name);
+			(void) pthread_mutex_unlock(&_libsmp_lock);
+			return (ep);
+		}
+	}
+
+	return (NULL);
+}
+
+static void
+smp_engine_rele(smp_engine_t *ep)
+{
+	(void) pthread_mutex_lock(&_libsmp_lock);
+	ASSERT(ep->se_refcnt > 0);
+	--ep->se_refcnt;
+	(void) pthread_mutex_unlock(&_libsmp_lock);
+}
+
+static void
+smp_parse_mtbf(const char *envvar, uint_t *intp)
+{
+	const char *strval;
+	int intval;
+
+	if ((strval = getenv(envvar)) != NULL &&
+	    (intval = atoi(strval)) > 0) {
+		srand48(gethrtime());
+		*intp = intval;
+	}
+}
+
+smp_target_t *
+smp_open(const smp_target_def_t *tdp)
+{
+	smp_engine_t *ep;
+	smp_target_t *tp;
+	void *private;
+	const char *engine;
+
+	if ((engine = tdp->std_engine) == NULL) {
+		if ((engine = getenv("LIBSMP_DEFAULT_ENGINE")) == NULL)
+			engine = LIBSMP_DEFAULT_ENGINE;
+	}
+
+	if ((ep = smp_engine_hold(engine)) == NULL)
+		return (NULL);
+
+	if ((tp = smp_zalloc(sizeof (smp_target_t))) == NULL) {
+		smp_engine_rele(ep);
+		return (NULL);
+	}
+
+	if ((private = ep->se_ops->seo_open(tdp->std_def)) == NULL) {
+		smp_engine_rele(ep);
+		smp_free(tp);
+		return (NULL);
+	}
+
+	smp_parse_mtbf("LIBSMP_MTBF_REQUEST", &tp->st_mtbf_request);
+	smp_parse_mtbf("LIBSMP_MTBF_RESPONSE", &tp->st_mtbf_response);
+
+	tp->st_engine = ep;
+	tp->st_priv = private;
+
+	if (smp_plugin_load(tp) != 0) {
+		smp_close(tp);
+		return (NULL);
+	}
+
+	return (tp);
+}
+
+void
+smp_target_name(const smp_target_t *tp, char *buf, size_t len)
+{
+	tp->st_engine->se_ops->seo_target_name(tp->st_priv, buf, len);
+}
+
+uint64_t
+smp_target_addr(const smp_target_t *tp)
+{
+	return (tp->st_engine->se_ops->seo_target_addr(tp->st_priv));
+}
+
+const char *
+smp_target_vendor(const smp_target_t *tp)
+{
+	return (tp->st_vendor);
+}
+
+const char *
+smp_target_product(const smp_target_t *tp)
+{
+	return (tp->st_product);
+}
+
+const char *
+smp_target_revision(const smp_target_t *tp)
+{
+	return (tp->st_revision);
+}
+
+const char *
+smp_target_component_vendor(const smp_target_t *tp)
+{
+	return (tp->st_component_vendor);
+}
+
+uint16_t
+smp_target_component_id(const smp_target_t *tp)
+{
+	return (tp->st_component_id);
+}
+
+uint8_t
+smp_target_component_revision(const smp_target_t *tp)
+{
+	return (tp->st_component_revision);
+}
+
+uint_t
+smp_target_getcap(const smp_target_t *tp)
+{
+	uint_t cap = 0;
+
+	if (tp->st_repgen.srgr_long_response)
+		cap |= SMP_TARGET_C_LONG_RESP;
+
+	if (tp->st_repgen.srgr_zoning_supported)
+		cap |= SMP_TARGET_C_ZONING;
+
+	if (tp->st_repgen.srgr_number_of_zone_grps == SMP_ZONE_GROUPS_256)
+		cap |= SMP_TARGET_C_ZG_256;
+
+	return (cap);
+}
+
+void
+smp_target_set_change_count(smp_target_t *tp, uint16_t cc)
+{
+	tp->st_change_count = cc;
+}
+
+uint16_t
+smp_target_get_change_count(const smp_target_t *tp)
+{
+	return (tp->st_change_count);
+}
+
+void
+smp_close(smp_target_t *tp)
+{
+	smp_free(tp->st_vendor);
+	smp_free(tp->st_product);
+	smp_free(tp->st_revision);
+	smp_free(tp->st_component_vendor);
+
+	smp_plugin_unload(tp);
+
+	tp->st_engine->se_ops->seo_close(tp->st_priv);
+	smp_engine_rele(tp->st_engine);
+
+	smp_free(tp);
+}
+
+/*
+ * Set the timeout in seconds for this action.  If no timeout is specified
+ * or if the timeout is set to 0, an implementation-specific timeout will be
+ * used (which may vary based on the target, command or other variables).
+ * Not all engines support all timeout values.  Setting the timeout to a value
+ * not supported by the engine will cause engine-defined behavior when the
+ * action is executed.
+ */
+void
+smp_action_set_timeout(smp_action_t *ap, uint32_t timeout)
+{
+	ap->sa_timeout = timeout;
+}
+
+/*
+ * Obtain the timeout setting for this action.
+ */
+uint32_t
+smp_action_get_timeout(const smp_action_t *ap)
+{
+	return (ap->sa_timeout);
+}
+
+const smp_function_def_t *
+smp_action_get_function_def(const smp_action_t *ap)
+{
+	return (ap->sa_def);
+}
+
+/*
+ * Obtain the user-requested request allocation size.  Note that the
+ * interpretation of this is function-dependent.
+ */
+size_t
+smp_action_get_rqsd(const smp_action_t *ap)
+{
+	return (ap->sa_request_rqsd);
+}
+
+/*
+ * Obtains the address and amount of space allocated for the portion of the
+ * request data that lies between the header (if any) and the CRC.
+ */
+void
+smp_action_get_request(const smp_action_t *ap, void **reqp, size_t *dlenp)
+{
+	if (reqp != NULL) {
+		if (ap->sa_request_data_off >= 0) {
+			*reqp = ap->sa_request + ap->sa_request_data_off;
+		} else {
+			*reqp = NULL;
+		}
+	}
+
+	if (dlenp != NULL)
+		*dlenp = ap->sa_request_alloc_len -
+		    (ap->sa_request_data_off + sizeof (smp_crc_t));
+}
+
+/*
+ * Obtains the address and amount of valid response data (that part of the
+ * response frame, if any, that lies between the header and the CRC).  The
+ * result, if any, is also returned in the location pointed to by result.
+ */
+void
+smp_action_get_response(const smp_action_t *ap, smp_result_t *resultp,
+    void **respp, size_t *dlenp)
+{
+	if (resultp != NULL)
+		*resultp = ap->sa_result;
+
+	if (respp != NULL)
+		*respp = (ap->sa_response_data_len > 0) ?
+		    (ap->sa_response + ap->sa_response_data_off) : NULL;
+
+	if (dlenp != NULL)
+		*dlenp = ap->sa_response_data_len;
+}
+
+/*
+ * Obtains the entire request frame and the amount of space allocated for it.
+ * This is intended only for use by plugins; front-end consumers should use
+ * smp_action_get_request() instead.
+ */
+void
+smp_action_get_request_frame(const smp_action_t *ap, void **reqp, size_t *alenp)
+{
+	if (reqp != NULL)
+		*reqp = ap->sa_request;
+
+	if (alenp != NULL)
+		*alenp = ap->sa_request_alloc_len;
+}
+
+/*
+ * Obtains the entire response frame and the amount of space allocated for it.
+ * This is intended only for use by plugins; front-end consumers should use
+ * smp_action_get_response() instead.
+ */
+void
+smp_action_get_response_frame(const smp_action_t *ap,
+    void **respp, size_t *lenp)
+{
+	if (respp != NULL)
+		*respp = ap->sa_response;
+
+	if (lenp != NULL) {
+		if (ap->sa_flags & SMP_ACTION_F_EXEC)
+			*lenp = ap->sa_response_engine_len;
+		else
+			*lenp = ap->sa_response_alloc_len;
+	}
+}
+
+/*
+ * Set the total response frame length as determined by the engine.  This
+ * should never be called by consumers or plugins other than engines.
+ */
+void
+smp_action_set_response_len(smp_action_t *ap, size_t elen)
+{
+	ap->sa_response_engine_len = elen;
+}
+
+void
+smp_action_set_result(smp_action_t *ap, smp_result_t result)
+{
+	ap->sa_result = result;
+}
+
+/*
+ * Allocate an action object.  The object will contain a request buffer
+ * to hold the frame to be transmitted to the target, a response buffer
+ * for the frame to be received from it, and auxiliary private information.
+ *
+ * For the request, callers may specify:
+ *
+ * - An externally-allocated buffer and its size in bytes, or
+ * - NULL and a function-specific size descriptor, or
+ *
+ * Note that for some functions, the size descriptor may be 0, indicating that
+ * a default buffer length will be used.  It is the caller's responsibility
+ * to correctly interpret function-specific buffer lengths.  See appropriate
+ * plugin documentation for information on buffer sizes and buffer content
+ * interpretation.
+ *
+ * For the response, callers may specify:
+ *
+ * - An externally-allocated buffer and its size in bytes, or
+ * - NULL and 0, to use a guaranteed-sufficient buffer.
+ *
+ * If an invalid request size descriptor is provided, or a preallocated
+ * buffer is provided and it is insufficiently large, this function will
+ * fail with ESMP_RANGE.
+ *
+ * Callers are discouraged from allocating their own buffers and must be
+ * aware of the consequences of specifying non-default lengths.
+ */
+smp_action_t *
+smp_action_xalloc(smp_function_t fn, smp_target_t *tp,
+    void *rq, size_t rqsd, void *rs, size_t rslen)
+{
+	smp_plugin_t *pp;
+	const smp_function_def_t *dp = NULL;
+	smp_action_t *ap;
+	uint_t cap;
+	size_t rqlen, len;
+	uint8_t *alloc;
+	int i;
+
+	cap = smp_target_getcap(tp);
+
+	for (pp = tp->st_plugin_first; pp != NULL; pp = pp->sp_next) {
+		if (pp->sp_functions == NULL)
+			continue;
+
+		for (i = 0; pp->sp_functions[i].sfd_rq_len != NULL; i++) {
+			dp = &pp->sp_functions[i];
+			if (dp->sfd_function == fn &&
+			    ((cap & dp->sfd_capmask) == dp->sfd_capset))
+				break;
+		}
+	}
+
+	if (dp == NULL) {
+		(void) smp_set_errno(ESMP_BADFUNC);
+		return (NULL);
+	}
+
+	if (rq == NULL) {
+		if ((rqlen = dp->sfd_rq_len(rqsd, tp)) == 0)
+			return (NULL);
+	} else if (rqlen < SMP_REQ_MINLEN) {
+		(void) smp_set_errno(ESMP_RANGE);
+		return (NULL);
+	}
+
+	if (rs == NULL) {
+		rslen = 1020 + SMP_RESP_MINLEN;
+	} else if (rslen < SMP_RESP_MINLEN) {
+		(void) smp_set_errno(ESMP_RANGE);
+		return (NULL);
+	}
+
+	len = offsetof(smp_action_t, sa_buf[0]);
+	if (rq == NULL)
+		len += rqlen;
+	if (rs == NULL)
+		len += rslen;
+
+	if ((ap = smp_zalloc(len)) == NULL)
+		return (NULL);
+
+	ap->sa_def = dp;
+	alloc = ap->sa_buf;
+
+	if (rq == NULL) {
+		ap->sa_request = alloc;
+		alloc += rqlen;
+	}
+	ap->sa_request_alloc_len = rqlen;
+
+	if (rs == NULL) {
+		ap->sa_response = alloc;
+		alloc += rslen;
+	}
+	ap->sa_response_alloc_len = rslen;
+
+	ASSERT(alloc - (uint8_t *)ap == len);
+
+	ap->sa_request_data_off = dp->sfd_rq_dataoff(ap, tp);
+	ap->sa_flags |= SMP_ACTION_F_OFFSET;
+
+	return (ap);
+}
+
+/*
+ * Simplified action allocator.  All buffers are allocated for the
+ * caller.  The request buffer size will be based on the function-specific
+ * interpretation of the rqsize parameter.  The response buffer size will be
+ * a function-specific value sufficiently large to capture any response.
+ */
+smp_action_t *
+smp_action_alloc(smp_function_t fn, smp_target_t *tp, size_t rqsd)
+{
+	return (smp_action_xalloc(fn, tp, NULL, rqsd, NULL, 0));
+}
+
+void
+smp_action_free(smp_action_t *ap)
+{
+	if (ap == NULL)
+		return;
+
+	smp_free(ap);
+}
+
+/*
+ * For testing purposes, we allow data to be corrupted via an environment
+ * variable setting.  This helps ensure that higher level software can cope with
+ * arbitrarily broken targets.  The mtbf value represents the number of bytes we
+ * will see, on average, in between each failure.  Therefore, for each N bytes,
+ * we would expect to see (N / mtbf) bytes of corruption.
+ */
+static void
+smp_inject_errors(void *data, size_t len, uint_t mtbf)
+{
+	char *buf = data;
+	double prob;
+	size_t index;
+
+	if (len == 0)
+		return;
+
+	prob = (double)len / mtbf;
+
+	while (prob > 1) {
+		index = lrand48() % len;
+		buf[index] = (lrand48() % 256);
+		prob -= 1;
+	}
+
+	if (drand48() <= prob) {
+		index = lrand48() % len;
+		buf[index] = (lrand48() % 256);
+	}
+}
+
+int
+smp_exec(smp_action_t *ap, smp_target_t *tp)
+{
+	const smp_function_def_t *dp;
+	int ret;
+
+	dp = ap->sa_def;
+	dp->sfd_rq_setframe(ap, tp);
+
+	if (tp->st_mtbf_request != 0) {
+		smp_inject_errors(ap->sa_request, ap->sa_request_alloc_len,
+		    tp->st_mtbf_request);
+	}
+
+	ret = tp->st_engine->se_ops->seo_exec(tp->st_priv, ap);
+
+	if (ret == 0 && tp->st_mtbf_response != 0) {
+		smp_inject_errors(ap->sa_response, ap->sa_response_engine_len,
+		    tp->st_mtbf_response);
+	}
+
+	if (ret != 0)
+		return (ret);
+
+	ap->sa_flags |= SMP_ACTION_F_EXEC;
+
+	/*
+	 * Obtain the data length and offset from the underlying plugins.
+	 * Then offer the plugins the opportunity to set any parameters in the
+	 * target to reflect state observed in the response.
+	 */
+	ap->sa_response_data_len = dp->sfd_rs_datalen(ap, tp);
+	ap->sa_response_data_off = dp->sfd_rs_dataoff(ap, tp);
+	dp->sfd_rs_getparams(ap, tp);
+
+	ap->sa_flags |= SMP_ACTION_F_DECODE;
+
+	return (0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/scsi/libsmp/common/smp_impl.h	Sun Apr 11 11:20:12 2010 -0700
@@ -0,0 +1,123 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#ifndef	_SMP_IMPL_H
+#define	_SMP_IMPL_H
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+#include <sys/scsi/generic/smp_frames.h>
+
+#include <scsi/libsmp.h>
+#include <scsi/libsmp_plugin.h>
+
+#include <pthread.h>
+
+#define	LIBSMP_ERRMSGLEN	512
+
+#define	LIBSMP_DEFAULT_PLUGINDIR	"/usr/lib/scsi/plugins/smp"
+#define	LIBSMP_PLUGIN_ENGINE		"engine"
+#define	LIBSMP_PLUGIN_FRAMEWORK		"framework"
+#define	LIBSMP_PLUGIN_VENDOR		"vendor"
+
+#define	LIBSMP_PLUGIN_EXT		".so"
+
+#define	LIBSMP_DEFAULT_ENGINE		"usmp"
+
+struct smp_engine {
+	char *se_name;
+	const smp_engine_ops_t *se_ops;
+	void *se_object;
+	int (*se_init)(struct smp_engine *);
+	void (*se_fini)(struct smp_engine *);
+	uint_t se_refcnt;
+	struct smp_engine *se_next;
+};
+
+struct smp_plugin {
+	struct smp_plugin *sp_next;
+	struct smp_plugin *sp_prev;
+	smp_target_t *sp_target;
+	uint64_t sp_priority;
+	void *sp_object;
+	void *sp_data;
+	boolean_t sp_initialized;
+	const smp_function_def_t *sp_functions;
+	int (*sp_init)(smp_plugin_t *);
+	void (*sp_fini)(smp_plugin_t *);
+};
+
+#define	SMP_ACTION_F_OFFSET		0x01
+#define	SMP_ACTION_F_EXEC		0x02
+#define	SMP_ACTION_F_DECODE		0x04
+
+struct smp_action {
+	uint32_t sa_timeout;
+	const smp_function_def_t *sa_def;
+	uint8_t *sa_request;
+	size_t sa_request_rqsd;
+	size_t sa_request_alloc_len;
+	off_t sa_request_data_off;
+	uint8_t *sa_response;
+	size_t sa_response_alloc_len;
+	size_t sa_response_engine_len;
+	size_t sa_response_data_len;
+	off_t sa_response_data_off;
+	smp_result_t sa_result;
+	uint_t sa_flags;
+	uint_t sa_cap;
+	uint8_t sa_buf[1];
+};
+
+struct smp_target {
+	smp_engine_t *st_engine;
+	void *st_priv;
+	uint_t st_mtbf_request;
+	uint_t st_mtbf_response;
+	uint16_t st_change_count;
+	smp_plugin_t *st_plugin_first;
+	smp_plugin_t *st_plugin_last;
+	char *st_vendor;
+	char *st_product;
+	char *st_revision;
+	char *st_component_vendor;
+	uint16_t st_component_id;
+	uint8_t st_component_revision;
+	smp_report_general_resp_t st_repgen;
+};
+
+extern void smp_engine_init(void);
+extern void smp_engine_fini(void);
+
+extern int smp_plugin_load(smp_target_t *);
+extern void smp_plugin_unload(smp_target_t *);
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* _SMP_IMPL_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/scsi/libsmp/common/smp_plugin.c	Sun Apr 11 11:20:12 2010 -0700
@@ -0,0 +1,428 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#include <sys/types.h>
+#include <sys/systeminfo.h>
+#include <sys/scsi/generic/commands.h>
+#include <sys/scsi/impl/commands.h>
+
+#include <scsi/libsmp.h>
+#include <scsi/libsmp_plugin.h>
+
+#include <alloca.h>
+#include <dlfcn.h>
+#include <link.h>
+#include <dirent.h>
+#include <string.h>
+#include <strings.h>
+#include <limits.h>
+
+#include "smp_impl.h"
+
+static boolean_t _libsmp_plugin_dlclose;
+
+/*
+ * As part of basic initialization, we always retrieve the REPORT GENERAL
+ * data so that we will know whether this target supports the long response
+ * format.
+ */
+static int
+smp_report_general(smp_target_t *tp)
+{
+	smp_action_t *ap;
+	smp_report_general_resp_t *rp;
+	smp_result_t result;
+	size_t len;
+
+	if ((ap = smp_action_alloc(SMP_FUNC_REPORT_GENERAL, tp, 0)) == NULL)
+		return (-1);
+
+	if (smp_exec(ap, tp) != 0) {
+		smp_action_free(ap);
+		return (smp_set_errno(ESMP_REPGEN_FAILED));
+	}
+
+	smp_action_get_response(ap, &result, (void **)&rp, &len);
+
+	if (result != SMP_RES_FUNCTION_ACCEPTED || len < 24) {
+		smp_action_free(ap);
+		return (smp_set_errno(ESMP_REPGEN_FAILED));
+	}
+
+	bcopy(rp, &tp->st_repgen, sizeof (tp->st_repgen));
+
+	smp_action_free(ap);
+
+	return (0);
+}
+
+static int
+smp_report_manufacturer_information(smp_target_t *tp)
+{
+	smp_action_t *ap;
+	smp_report_manufacturer_info_resp_t *rp;
+	smp_result_t result;
+	size_t len;
+
+	ap = smp_action_alloc(SMP_FUNC_REPORT_MANUFACTURER_INFO, tp, 0);
+	if (ap == NULL)
+		return (-1);
+
+	if (smp_exec(ap, tp) != 0) {
+		smp_action_free(ap);
+		return (smp_set_errno(ESMP_REPGEN_FAILED));
+	}
+
+	smp_action_get_response(ap, &result, (void **)&rp, &len);
+
+	if (result != SMP_RES_FUNCTION_ACCEPTED ||
+	    len != sizeof (smp_report_manufacturer_info_resp_t)) {
+		smp_action_free(ap);
+		return (0);	/* Not supported */
+	}
+
+	tp->st_vendor = smp_trim_strdup(rp->srmir_vendor_identification,
+	    sizeof (rp->srmir_vendor_identification));
+	tp->st_product = smp_trim_strdup(rp->srmir_product_identification,
+	    sizeof (rp->srmir_product_identification));
+	tp->st_revision = smp_trim_strdup(rp->srmir_product_revision_level,
+	    sizeof (rp->srmir_product_revision_level));
+
+	if (rp->srmir_sas_1_1_format) {
+		tp->st_component_vendor =
+		    smp_trim_strdup(rp->srmir_component_vendor_identification,
+		    sizeof (rp->srmir_component_vendor_identification));
+
+		tp->st_component_id = SCSI_READ16(&rp->srmir_component_id);
+		tp->st_component_revision = rp->srmir_component_revision_level;
+	}
+
+	if (tp->st_vendor == NULL || tp->st_product == NULL ||
+	    tp->st_revision == NULL ||
+	    (rp->srmir_sas_1_1_format && tp->st_component_vendor == NULL)) {
+		smp_action_free(ap);
+		return (smp_set_errno(ESMP_NOMEM));
+	}
+
+	smp_action_free(ap);
+
+	return (0);
+}
+
+static int
+smp_target_fill(smp_target_t *tp)
+{
+	if (smp_report_general(tp) != 0 ||
+	    smp_report_manufacturer_information(tp) != 0)
+		return (-1);
+
+	return (0);
+}
+
+const smp_function_def_t *
+smp_get_funcdef(smp_target_t *tp, int fn)
+{
+	smp_plugin_t *pp;
+	const smp_function_def_t *dp;
+
+	for (pp = tp->st_plugin_first; pp != NULL; pp = pp->sp_next) {
+		if (pp->sp_functions == NULL)
+			continue;
+
+		for (dp = &pp->sp_functions[0]; dp->sfd_rq_len != NULL; dp++) {
+			if (dp->sfd_function == fn)
+				return (dp);
+		}
+	}
+
+	(void) smp_error(ESMP_BADFUNC, "failed to find function 0x%x", fn);
+	return (NULL);
+}
+
+int
+smp_plugin_register(smp_plugin_t *pp, int version,
+    const smp_plugin_config_t *pcp)
+{
+	if (version != LIBSMP_PLUGIN_VERSION)
+		return (smp_set_errno(ESMP_VERSION));
+
+	pp->sp_functions = pcp->spc_functions;
+
+	return (0);
+}
+
+void
+smp_plugin_setspecific(smp_plugin_t *pp, void *data)
+{
+	pp->sp_data = data;
+}
+
+void *
+smp_plugin_getspecific(smp_plugin_t *pp)
+{
+	return (pp->sp_data);
+}
+
+static void
+smp_plugin_cleanstr(char *s)
+{
+	while (*s != '\0') {
+		if (*s == ' ' || *s == '/')
+			*s = '-';
+		s++;
+	}
+}
+
+static void
+smp_plugin_destroy(smp_plugin_t *pp)
+{
+	if (pp->sp_initialized && pp->sp_fini != NULL)
+		pp->sp_fini(pp);
+
+	if (_libsmp_plugin_dlclose)
+		(void) dlclose(pp->sp_object);
+
+	smp_free(pp);
+}
+
+static int
+smp_plugin_loadone(smp_target_t *tp, const char *path, uint32_t pass)
+{
+	smp_plugin_t *pp, **loc;
+	void *obj;
+	int (*smp_priority)(void);
+
+	if ((obj = dlopen(path, RTLD_PARENT | RTLD_LOCAL | RTLD_LAZY)) == NULL)
+		return (0);
+
+	if ((pp = smp_zalloc(sizeof (smp_plugin_t))) == NULL) {
+		(void) dlclose(obj);
+		return (-1);
+	}
+
+	pp->sp_object = obj;
+	pp->sp_init = (int (*)())dlsym(obj, "_smp_init");
+	pp->sp_fini = (void (*)())dlsym(obj, "_smp_fini");
+	pp->sp_target = tp;
+
+	if (pp->sp_init == NULL) {
+		smp_plugin_destroy(pp);
+		return (0);
+	}
+
+	/*
+	 * Framework modules can establish an explicit prioritying by declaring
+	 * the '_smp_priority' symbol, which returns an integer used to create
+	 * an explicit ordering between plugins.
+	 */
+	if ((smp_priority = (int (*)())dlsym(obj, "_smp_priority")) != NULL)
+		pp->sp_priority = smp_priority();
+
+	pp->sp_priority |= (uint64_t)pass << 32;
+
+	for (loc = &tp->st_plugin_first; *loc != NULL; loc = &(*loc)->sp_next) {
+		if ((*loc)->sp_priority > pp->sp_priority)
+			break;
+	}
+
+	if (*loc != NULL)
+		(*loc)->sp_prev = pp;
+	else
+		tp->st_plugin_last = pp;
+
+	pp->sp_next = *loc;
+	*loc = pp;
+
+	if (pp->sp_init(pp) != 0)
+		return (-1);
+	pp->sp_initialized = B_TRUE;
+
+	return (0);
+}
+
+static int
+smp_plugin_load_dir(smp_target_t *tp, const char *pluginroot)
+{
+	char path[PATH_MAX];
+	DIR *dirp;
+	struct dirent64 *dp;
+	char *c_vendor, *vendor, *product, *revision;
+	char isa[257];
+
+	(void) snprintf(path, sizeof (path), "%s/%s",
+	    pluginroot, LIBSMP_PLUGIN_FRAMEWORK);
+
+#if defined(_LP64)
+	if (sysinfo(SI_ARCHITECTURE_64, isa, sizeof (isa)) < 0)
+		isa[0] = '\0';
+#else
+	isa[0] = '\0';
+#endif
+
+	if ((dirp = opendir(path)) != NULL) {
+		while ((dp = readdir64(dirp)) != NULL) {
+			if (strcmp(dp->d_name, ".") == 0 ||
+			    strcmp(dp->d_name, "..") == 0)
+				continue;
+
+			(void) snprintf(path, sizeof (path), "%s/%s/%s/%s",
+			    pluginroot, LIBSMP_PLUGIN_FRAMEWORK,
+			    isa, dp->d_name);
+
+			if (smp_plugin_loadone(tp, path, 0) != 0) {
+				(void) closedir(dirp);
+				return (-1);
+			}
+		}
+
+		(void) closedir(dirp);
+	}
+
+	/*
+	 * Now attempt to load platform-specific plugins.  The framework
+	 * plugins had better give us the ability to perform basic SMP
+	 * functions like REPORT GENERAL and REPORT MANUFACTURER INFORMATION;
+	 * if not, we're toast anyway.  If the latter is not supported, we
+	 * will not be able to use any vendor-specific plugins.  Note that
+	 * there are actually two possible specifications for vendor plugins:
+	 * those matching the vendor/product/revision fields, and those
+	 * matching the component vendor/id/revision fields.  The component is
+	 * less specific, so we try to load those first.
+	 */
+
+	if (smp_target_fill(tp) != 0)
+		return (-1);
+
+	if (tp->st_vendor == NULL)
+		return (0);
+
+	if (tp->st_component_vendor != NULL) {
+		c_vendor = alloca(strlen(tp->st_component_vendor) + 1);
+		(void) strcpy(c_vendor, tp->st_component_vendor);
+		smp_plugin_cleanstr(c_vendor);
+	}
+
+	vendor = alloca(strlen(tp->st_vendor) + 1);
+	product = alloca(strlen(tp->st_product) + 1);
+	revision = alloca(strlen(tp->st_revision) + 1);
+
+	(void) strcpy(vendor, tp->st_vendor);
+	(void) strcpy(product, tp->st_product);
+	(void) strcpy(revision, tp->st_revision);
+
+	smp_plugin_cleanstr(vendor);
+	smp_plugin_cleanstr(product);
+	smp_plugin_cleanstr(revision);
+
+	if (tp->st_component_vendor != NULL) {
+		(void) snprintf(path, sizeof (path), "%s/%s/%s/component_%s%s",
+		    pluginroot, LIBSMP_PLUGIN_VENDOR, isa, c_vendor,
+		    LIBSMP_PLUGIN_EXT);
+		if (smp_plugin_loadone(tp, path, 1) != 0)
+			return (-1);
+
+		(void) snprintf(path, sizeof (path),
+		    "%s/%s/%s/component_%s-%04x%s",
+		    pluginroot, LIBSMP_PLUGIN_VENDOR, isa, c_vendor,
+		    tp->st_component_id, LIBSMP_PLUGIN_EXT);
+		if (smp_plugin_loadone(tp, path, 2) != 0)
+			return (-1);
+
+		(void) snprintf(path, sizeof (path),
+		    "%s/%s/%s/component_%s-%04x-%02x%s",
+		    pluginroot, LIBSMP_PLUGIN_VENDOR, isa, c_vendor,
+		    tp->st_component_id, tp->st_component_revision,
+		    LIBSMP_PLUGIN_EXT);
+		if (smp_plugin_loadone(tp, path, 3) != 0)
+			return (-1);
+	}
+
+	(void) snprintf(path, sizeof (path), "%s/%s/%s/%s%s", pluginroot,
+	    LIBSMP_PLUGIN_VENDOR, isa, vendor, LIBSMP_PLUGIN_EXT);
+	if (smp_plugin_loadone(tp, path, 4) != 0)
+		return (-1);
+
+	(void) snprintf(path, sizeof (path), "%s/%s/%s/%s-%s%s", pluginroot,
+	    LIBSMP_PLUGIN_VENDOR, isa, vendor, product, LIBSMP_PLUGIN_EXT);
+	if (smp_plugin_loadone(tp, path, 5) != 0)
+		return (-1);
+
+	(void) snprintf(path, sizeof (path), "%s/%s/%s/%s-%s-%s%s", pluginroot,
+	    LIBSMP_PLUGIN_VENDOR, isa, vendor, product,
+	    revision, LIBSMP_PLUGIN_EXT);
+	if (smp_plugin_loadone(tp, path, 6) != 0)
+		return (-1);
+
+	return (0);
+}
+
+int
+smp_plugin_load(smp_target_t *tp)
+{
+	char pluginroot[PATH_MAX];
+	const char *pluginpath, *p, *q;
+
+	if ((pluginpath = getenv("SMP_PLUGINPATH")) == NULL)
+		pluginpath = LIBSMP_DEFAULT_PLUGINDIR;
+	_libsmp_plugin_dlclose = (getenv("SMP_NODLCLOSE") == NULL);
+
+	for (p = pluginpath; p != NULL; p = q) {
+		if ((q = strchr(p, ':')) != NULL) {
+			ptrdiff_t len = q - p;
+			(void) strncpy(pluginroot, p, len);
+			pluginroot[len] = '\0';
+			while (*q == ':')
+				++q;
+			if (*q == '\0')
+				q = NULL;
+			if (len == 0)
+				continue;
+		} else {
+			(void) strcpy(pluginroot, p);
+		}
+
+		if (pluginroot[0] != '/')
+			continue;
+
+		if (smp_plugin_load_dir(tp, pluginroot) != 0)
+			return (-1);
+	}
+
+	if (tp->st_plugin_first == NULL)
+		return (smp_error(ESMP_PLUGIN, "no plugins found"));
+
+	return (0);
+}
+
+void
+smp_plugin_unload(smp_target_t *tp)
+{
+	smp_plugin_t *pp;
+
+	while ((pp = tp->st_plugin_first) != NULL) {
+		tp->st_plugin_first = pp->sp_next;
+		smp_plugin_destroy(pp);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/scsi/libsmp/common/smp_subr.c	Sun Apr 11 11:20:12 2010 -0700
@@ -0,0 +1,244 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#include <sys/types.h>
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <alloca.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <dlfcn.h>
+#include <thread.h>
+#include <pthread.h>
+#include <ctype.h>
+
+#include <scsi/libsmp.h>
+#include <scsi/libsmp_plugin.h>
+#include "smp_impl.h"
+
+__thread smp_errno_t _smp_errno;
+__thread char _smp_errmsg[LIBSMP_ERRMSGLEN];
+
+int
+smp_assert(const char *expr, const char *file, int line)
+{
+	char *msg;
+	size_t len;
+
+	len = snprintf(NULL, 0,
+	    "ABORT: \"%s\", line %d: assertion failed: %s\n", file, line, expr);
+
+	msg = alloca(len + 1);
+
+	(void) snprintf(msg, len + 1,
+	    "ABORT: \"%s\", line %d: assertion failed: %s\n", file, line, expr);
+
+	(void) write(STDERR_FILENO, msg, strlen(msg));
+
+	abort();
+	_exit(1);
+
+	/*NOTREACHED*/
+	return (0);
+}
+
+int
+smp_set_errno(smp_errno_t err)
+{
+	_smp_errno = err;
+	_smp_errmsg[0] = '\0';
+
+	return (-1);
+}
+
+/*
+ * Internal routine for setting both _smp_errno and _smp_errmsg.  We save
+ * and restore the UNIX errno across this routing so the caller can use either
+ * smp_set_errno(), smp_error(), or smp_verror() without this value changing.
+ */
+int
+smp_verror(smp_errno_t err, const char *fmt, va_list ap)
+{
+	size_t n;
+	char *errmsg;
+
+	/*
+	 * To allow the existing error message to itself be used in an error
+	 * message, we put the new error message into a buffer on the stack,
+	 * and then copy it into lsh_errmsg.  We also need to set the errno,
+	 * but because the call to smp_set_errno() is destructive to
+	 * lsh_errmsg, we do this after we print into our temporary buffer
+	 * (in case _smp_errmsg is part of the error message) and before we
+	 * copy the temporary buffer on to _smp_errmsg (to prevent our new
+	 * message from being nuked by the call to smp_set_errno()).
+	 */
+	errmsg = alloca(sizeof (_smp_errmsg));
+	(void) vsnprintf(errmsg, sizeof (_smp_errmsg), fmt, ap);
+	(void) smp_set_errno(err);
+
+	n = strlen(errmsg);
+
+	if (n != 0 && errmsg[n - 1] == '\n')
+		errmsg[n - 1] = '\0';
+
+	bcopy(errmsg, _smp_errmsg, n + 1);
+
+	return (-1);
+}
+
+int
+smp_error(smp_errno_t err, const char *fmt, ...)
+{
+	va_list ap;
+
+	if (fmt == NULL)
+		return (smp_set_errno(err));
+
+	va_start(ap, fmt);
+	err = smp_verror(err, fmt, ap);
+	va_end(ap);
+
+	return (err);
+}
+
+smp_errno_t
+smp_errno(void)
+{
+	return (_smp_errno);
+}
+
+const char *
+smp_errmsg(void)
+{
+	if (_smp_errmsg[0] == '\0')
+		(void) strlcpy(_smp_errmsg, smp_strerror(_smp_errno),
+		    sizeof (_smp_errmsg));
+
+	return (_smp_errmsg);
+}
+
+/*ARGSUSED*/
+void *
+smp_alloc(size_t size)
+{
+	void *mem;
+
+	if (size == 0) {
+		(void) smp_set_errno(ESMP_ZERO_LENGTH);
+		return (NULL);
+	}
+
+	if ((mem = malloc(size)) == NULL)
+		(void) smp_set_errno(ESMP_NOMEM);
+
+	return (mem);
+}
+
+void *
+smp_zalloc(size_t size)
+{
+	void *mem;
+
+	if ((mem = smp_alloc(size)) == NULL)
+		return (NULL);
+
+	bzero(mem, size);
+
+	return (mem);
+}
+
+char *
+smp_strdup(const char *str)
+{
+	size_t len = strlen(str);
+	char *dup = smp_alloc(len + 1);
+
+	if (dup == NULL)
+		return (NULL);
+
+	return (strcpy(dup, str));
+}
+
+void
+smp_free(void *ptr)
+{
+	free(ptr);
+}
+
+/*
+ * Trim any leading and/or trailing spaces from the fixed-length string
+ * argument and return a newly-allocated copy of it.
+ */
+char *
+smp_trim_strdup(const char *str, size_t len)
+{
+	const char *p;
+	char *r;
+
+	for (p = str; p - str < len && isspace(*p); p++)
+		;
+
+	len -= (p - str);
+
+	if (len == 0)
+		return (NULL);
+
+	for (str = p + len - 1; str > p && isspace(*str); str--, len--)
+		;
+
+	if (len == 0)
+		return (NULL);
+
+	r = smp_alloc(len + 1);
+	if (r == NULL)
+		return (NULL);
+
+	bcopy(p, r, len);
+	r[len] = '\0';
+
+	return (r);
+}
+
+int
+smp_init(int version)
+{
+	if (version != LIBSMP_VERSION)
+		return (smp_error(ESMP_VERSION,
+		    "library version %d does not match requested version %d",
+		    LIBSMP_VERSION, version));
+
+	smp_engine_init();
+
+	return (0);
+}
+
+void
+smp_fini(void)
+{
+	smp_engine_fini();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/scsi/libsmp/i386/Makefile	Sun Apr 11 11:20:12 2010 -0700
@@ -0,0 +1,28 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/scsi/libsmp/libsmp_api.map	Sun Apr 11 11:20:12 2010 -0700
@@ -0,0 +1,51 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+{
+	smp_strerror = FUNCTION extern;
+	smp_errname = FUNCTION extern;
+	smp_errcode = FUNCTION extern;
+	smp_alloc = FUNCTION extern;
+	smp_zalloc = FUNCTION extern;
+	smp_strdup = FUNCTION extern;
+	smp_free = FUNCTION extern;
+	smp_set_errno = FUNCTION extern;
+	smp_verror = FUNCTION extern;
+	smp_error = FUNCTION extern;
+	smp_action_get_timeout = FUNCTION extern;
+	smp_action_get_request = FUNCTION extern;
+	smp_action_get_response = FUNCTION extern;
+	smp_action_get_request_frame = FUNCTION extern;
+	smp_action_get_response_frame = FUNCTION extern;
+	smp_action_get_function_def = FUNCTION extern;
+	smp_action_set_response_len = FUNCTION extern;
+	smp_action_set_result = FUNCTION extern;
+	smp_target_getcap = FUNCTION extern;
+	smp_target_set_change_count = FUNCTION extern;
+	smp_target_get_change_count = FUNCTION extern;
+	smp_assert = FUNCTION extern;
+	smp_engine_register = FUNCTION extern;
+	smp_plugin_register = FUNCTION extern;
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/scsi/libsmp/llib-lsmp	Sun Apr 11 11:20:12 2010 -0700
@@ -0,0 +1,31 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+
+/*LINTLIBRARY*/
+/*PROTOLIB1*/
+
+#include <scsi/libsmp.h>
+#include <scsi/libsmp_plugin.h>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/scsi/libsmp/mapfile-vers	Sun Apr 11 11:20:12 2010 -0700
@@ -0,0 +1,90 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+#
+# MAPFILE HEADER START
+#
+# WARNING:  STOP NOW.  DO NOT MODIFY THIS FILE.
+# Object versioning must comply with the rules detailed in
+#
+#	usr/src/lib/README.mapfiles
+#
+# You should not be making modifications here until you've read the most current
+# copy of that file. If you need help, contact a gatekeeper for guidance.
+#
+# MAPFILE HEADER END
+#
+
+SUNWprivate_1.1 {
+	global:
+		smp_init;
+		smp_fini;
+		smp_open;
+		smp_target_getcap;
+		smp_target_set_change_count;
+		smp_target_get_change_count;
+		smp_target_vendor;
+		smp_target_product;
+		smp_target_revision;
+		smp_target_component_vendor;
+		smp_target_component_id;
+		smp_target_component_revision;
+		smp_target_name;
+		smp_target_addr;
+		smp_close;
+		smp_action_alloc;
+		smp_action_get_timeout;
+		smp_action_set_timeout;
+		smp_action_get_request;
+		smp_action_get_response;
+		smp_action_get_request_frame;
+		smp_action_get_response_frame;
+		smp_action_get_function_def;
+		smp_action_set_response_len;
+		smp_action_set_result;
+		smp_action_free;
+		smp_exec;
+		smp_errno;
+		smp_errmsg;
+		smp_strerror;
+		smp_errname;
+		smp_errcode;
+		smp_assert;
+		smp_engine_register;
+		smp_plugin_register;
+		smp_plugin_setspecific;
+		smp_plugin_getspecific;
+
+		smp_alloc;
+		smp_zalloc;
+		smp_strdup;
+		smp_free;
+		smp_set_errno;
+		smp_verror;
+		smp_error;
+
+	local:
+		*;
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/scsi/libsmp/sparc/Makefile	Sun Apr 11 11:20:12 2010 -0700
@@ -0,0 +1,28 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/scsi/libsmp/sparcv9/Makefile	Sun Apr 11 11:20:12 2010 -0700
@@ -0,0 +1,29 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+include ../Makefile.com
+include ../../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT64)
--- a/usr/src/lib/scsi/plugins/Makefile	Sun Apr 11 11:07:03 2010 +0800
+++ b/usr/src/lib/scsi/plugins/Makefile	Sun Apr 11 11:20:12 2010 -0700
@@ -20,14 +20,13 @@
 #
 
 #
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
+# Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
 #
-#ident	"%Z%%M%	%I%	%E% SMI"
 
 SUBDIRS = 	\
 	scsi	\
-	ses
+	ses	\
+	smp
 
 .KEEP_STATE:
 
--- a/usr/src/lib/scsi/plugins/ses/LSILOGIC-SASX28-A.0/Makefile.com	Sun Apr 11 11:07:03 2010 +0800
+++ b/usr/src/lib/scsi/plugins/ses/LSILOGIC-SASX28-A.0/Makefile.com	Sun Apr 11 11:20:12 2010 -0700
@@ -20,16 +20,13 @@
 #
 
 #
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
+# Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
 #
-#ident	"%Z%%M%	%I%	%E% SMI"
-
 
 MODULE =	LSILOGIC-SASX28-A.0
 SRCS =		lsilogic.c
 SRCDIR =	../common
 PLUGINTYPE =	vendor
-ALIASES =
+ALIASES =	LSILOGIC-SASX28-A.1
 
 include ../../Makefile.lib
--- a/usr/src/lib/scsi/plugins/ses/SUN/Makefile	Sun Apr 11 11:07:03 2010 +0800
+++ b/usr/src/lib/scsi/plugins/ses/SUN/Makefile	Sun Apr 11 11:20:12 2010 -0700
@@ -20,11 +20,10 @@
 #
 
 #
-# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
+# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
 #
 
-HDRS = 
+HDRS = sun.h sun_impl.h
 HDRDIR = common
 PLUGINTYPE = vendor
 
--- a/usr/src/lib/scsi/plugins/ses/SUN/Makefile.com	Sun Apr 11 11:07:03 2010 +0800
+++ b/usr/src/lib/scsi/plugins/ses/SUN/Makefile.com	Sun Apr 11 11:20:12 2010 -0700
@@ -20,13 +20,19 @@
 #
 
 #
-# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
+# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
 #
 
 MODULE =	SUN
-SRCS =		sun_spms.c
+SRCS =		sun.c	\
+		sun_element.c	\
+		sun_enclosure.c	\
+		sun_pages.c
+
 SRCDIR =	../common
 PLUGINTYPE =	vendor
 
 include ../../Makefile.lib
+
+$(PROG) := LDLIBS += -lnvfru
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/scsi/plugins/ses/SUN/common/sun.c	Sun Apr 11 11:20:12 2010 -0700
@@ -0,0 +1,79 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#include <stddef.h>
+#include <string.h>
+#include <strings.h>
+#include <alloca.h>
+#include <libnvpair.h>
+
+#include <scsi/libses.h>
+#include <scsi/libses_plugin.h>
+#include <scsi/plugins/ses/framework/libses.h>
+#include <scsi/plugins/ses/vendor/sun.h>
+#include <scsi/plugins/ses/vendor/sun_impl.h>
+
+#include "../../../../../../lib/libfru/libnvfru/nvfru.h"
+
+int
+sun_fruid_parse_common(sun_fru_descr_impl_t *sfdip, nvlist_t *nvl)
+{
+	int nverr;
+
+	SES_NV_ADD(boolean_value, nverr, nvl,
+	    LIBSES_PROP_FRU, sfdip-> sfdi_fru);
+	SES_NV_ADD(uint64, nverr, nvl,
+	    LIBSES_PROP_PHYS_PARENT, sfdip->sfdi_parent_element_index);
+
+	return (0);
+}
+
+static int
+sun_node_parse(ses_plugin_t *sp, ses_node_t *np)
+{
+	switch (ses_node_type(np)) {
+	case SES_NODE_ENCLOSURE:
+		return (sun_fill_enclosure_node(sp, np));
+
+	case SES_NODE_AGGREGATE:
+	case SES_NODE_ELEMENT:
+		return (sun_fill_element_node(sp, np));
+
+	default:
+		return (0);
+	}
+}
+
+int
+_ses_init(ses_plugin_t *sp)
+{
+	ses_plugin_config_t config = {
+		.spc_pages = sun_pages,
+		.spc_node_parse = sun_node_parse
+	};
+
+	return (ses_plugin_register(sp, LIBSES_PLUGIN_VERSION,
+	    &config) != 0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/scsi/plugins/ses/SUN/common/sun.h	Sun Apr 11 11:20:12 2010 -0700
@@ -0,0 +1,42 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#ifndef	_VENDOR_SUN_H
+#define	_VENDOR_SUN_H
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+/*
+ * Node properties
+ */
+#define	SUN_DIAGPAGE_FRUID	SES2_DIAGPAGE_VENDOR_0
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* _VENDOR_SUN_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/scsi/plugins/ses/SUN/common/sun_element.c	Sun Apr 11 11:20:12 2010 -0700
@@ -0,0 +1,53 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#include <sys/types.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <libnvpair.h>
+
+#include <scsi/libses.h>
+#include <scsi/libses_plugin.h>
+#include <scsi/plugins/ses/vendor/sun.h>
+#include <scsi/plugins/ses/vendor/sun_impl.h>
+
+int
+sun_fill_element_node(ses_plugin_t *sp, ses_node_t *np)
+{
+	ses_snap_t *snap = ses_node_snapshot(np);
+	nvlist_t *props = ses_node_props(np);
+	sun_fru_descr_impl_t *sfdip;
+	size_t len;
+	int err;
+
+	if ((sfdip = ses_plugin_page_lookup(sp, snap,
+	    SUN_DIAGPAGE_FRUID, np, &len)) != NULL) {
+		if ((err = sun_fruid_parse_common(sfdip, props)) != 0)
+			return (err);
+	}
+
+	return (0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/scsi/plugins/ses/SUN/common/sun_enclosure.c	Sun Apr 11 11:20:12 2010 -0700
@@ -0,0 +1,142 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#include <sys/scsi/impl/spc3_types.h>
+
+#include <stddef.h>
+#include <string.h>
+#include <strings.h>
+#include <libnvpair.h>
+
+#include <scsi/libses.h>
+#include <scsi/libses_plugin.h>
+#include <scsi/plugins/ses/framework/ses2.h>
+#include <scsi/plugins/ses/framework/ses2_impl.h>
+#include <scsi/plugins/ses/framework/libses.h>
+#include <scsi/plugins/ses/vendor/sun.h>
+#include <scsi/plugins/ses/vendor/sun_impl.h>
+
+/*ARGSUSED*/
+static int
+enc_parse_feature_block(ses_plugin_t *sp, ses_node_t *np)
+{
+	sun_feature_block_impl_t *sfbip;
+	nvlist_t *encprops;
+	uint8_t *vsp;
+	uint_t vsp_len;
+	uint_t cid_off, cid_len;
+	uint16_t revision;
+	uint64_t chunk;
+	int nverr;
+
+	encprops = ses_node_props(np);
+	if (nvlist_lookup_byte_array(encprops, SES_EN_PROP_VS,
+	    &vsp, &vsp_len) != 0 ||
+	    vsp_len < offsetof(sun_feature_block_impl_t, _reserved2))
+		return (0);
+
+	sfbip = (sun_feature_block_impl_t *)vsp;
+
+	if (strncmp((char *)sfbip->sfbi_spms_header, "SPMS", 4) != 0 ||
+	    sfbip->sfbi_spms_major_ver != 1)
+		return (0);
+
+	revision = SCSI_READ16(&sfbip->sfbi_spms_revision);
+
+	/*
+	 * The offset read from the Sun Feature Block needs to be adjusted
+	 * so that the difference in the sizes of the Enclosure
+	 * Descriptor and the INQUIRY data format is accounted for.
+	 */
+	cid_len = sfbip->sfbi_chassis_id_len;
+
+	if (sfbip->sfbi_chassis_id_off >= 96 && cid_len >= 4) {
+		cid_off = sfbip->sfbi_chassis_id_off -
+		    (sizeof (ses2_ed_impl_t) - 1);
+		cid_off += offsetof(ses2_ed_impl_t, st_priv[0]) -
+		    offsetof(spc3_inquiry_data_t, id_vs_36[0]);
+
+		if (cid_off + cid_len <= vsp_len) {
+			SES_NV_ADD(fixed_string, nverr, encprops,
+			    LIBSES_EN_PROP_CSN, (char *)(vsp + cid_off),
+			    cid_len);
+		}
+	}
+
+	if (revision >= 104) {
+		SES_NV_ADD(boolean_value, nverr, encprops,
+		    LIBSES_EN_PROP_INTERNAL, sfbip->sfbi_int);
+	}
+
+	if (revision >= 105) {
+		if (sfbip->sfbi_fw_upload_max_chunk_sz == 0)
+			chunk = 512;
+		else if (sfbip->sfbi_fw_upload_max_chunk_sz == 0x7f)
+			chunk = 65536;
+		else
+			chunk = 512 * sfbip->sfbi_fw_upload_max_chunk_sz;
+
+		SES_NV_ADD(uint64, nverr, encprops,
+		    LIBSES_EN_PROP_FIRMWARE_CHUNK_SIZE, chunk);
+	}
+
+	/*
+	 * If this is a subchassis, it will have a subchassis index field
+	 * with a value other than 0.  See SPMS-1r111 4.1.3.1.  If not, we
+	 * will see 0 and will not create the subchassis member at all; note
+	 * that this is backward-compatible with pre-111 implementations that
+	 * treated this as a reserved field.  No such implementation contains
+	 * a subchassis.
+	 */
+	if (sfbip->sfbi_spms_revision >= 111 &&
+	    sfbip->sfbi_subchassis_index != 0) {
+		SES_NV_ADD(uint64, nverr, encprops,
+		    LIBSES_EN_PROP_SUBCHASSIS_ID,
+		    sfbip->sfbi_subchassis_index - 1);
+	}
+
+	return (0);
+}
+
+int
+sun_fill_enclosure_node(ses_plugin_t *sp, ses_node_t *np)
+{
+	ses_snap_t *snap = ses_node_snapshot(np);
+	nvlist_t *props = ses_node_props(np);
+	sun_fru_descr_impl_t *sfdi;
+	int err;
+	size_t len;
+
+	if ((err = enc_parse_feature_block(sp, np)) != 0)
+		return (err);
+
+	if ((sfdi = ses_plugin_page_lookup(sp, snap,
+	    SUN_DIAGPAGE_FRUID, np, &len)) != NULL) {
+		if ((err = sun_fruid_parse_common(sfdi, props)) != 0)
+			return (err);
+	}
+
+	return (0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/scsi/plugins/ses/SUN/common/sun_impl.h	Sun Apr 11 11:20:12 2010 -0700
@@ -0,0 +1,101 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#ifndef	_PLUGIN_SUN_IMPL_H
+#define	_PLUGIN_SUN_IMPL_H
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+#include <sys/types.h>
+#include <sys/sysmacros.h>
+#include <sys/scsi/impl/uscsi.h>
+#include <sys/scsi/generic/commands.h>
+#include <sys/scsi/impl/spc3_types.h>
+#include <sys/ccompile.h>
+#include <stdarg.h>
+#include <libnvpair.h>
+
+#include <scsi/libscsi.h>
+#include <scsi/libses_plugin.h>
+
+#pragma	pack(1)
+
+/*
+ * SPMS-1 r111, section 4.2.4 - Configuration
+ * SPMS-1 r111, section 4.1.3.1, Table 8 - Sun Feature Definition
+ */
+typedef struct sun_feature_block_impl {
+	uint8_t		sfbi_spms_header[4];
+	uint8_t		sfbi_spms_major_ver;
+	uint8_t		_reserved1;
+	uint16_t	sfbi_spms_revision;
+	uint8_t		sfbi_chassis_id_off;
+	uint8_t		sfbi_chassis_id_len;
+	DECL_BITFIELD2(
+	    sfbi_fw_upload_max_chunk_sz	:7,
+	    sfbi_int			:1);
+	uint8_t		sfbi_subchassis_index;
+	uint8_t		_reserved2[48];
+	uint8_t		sfbi_ps[1];	/* Flexible platform specific content */
+} sun_feature_block_impl_t;
+
+/*
+ * SPMS-1 SUNW,FRUID FRU descriptor (Table 23, 4.2.18)
+ */
+typedef struct sun_fru_descr_impl {
+	DECL_BITFIELD2(
+	    sfdi_fru	:1,
+	    _reserved1	:7);
+	uint8_t sfdi_parent_element_index;
+	uint16_t sfdi_fru_data_length;
+	uint8_t sfdi_fru_data[1];	/* FRUPROM contents */
+} sun_fru_descr_impl_t;
+
+/*
+ * SPMS-1 SUNW,FRUID diagnostic page (Table 22, 4.2.18)
+ */
+typedef struct sun_fruid_page_impl {
+	uint8_t sfpi_page_code;
+	uint8_t _reserved1;
+	uint16_t sfpi_page_length;
+	uint32_t sfpi_generation_code;
+	uint16_t sfpi_descr_addrs[1];
+} sun_fruid_page_impl_t;
+
+#pragma pack()
+
+extern ses_pagedesc_t sun_pages[];
+
+extern int sun_fill_element_node(ses_plugin_t *, ses_node_t *);
+extern int sun_fill_enclosure_node(ses_plugin_t *, ses_node_t *);
+extern int sun_fruid_parse_common(sun_fru_descr_impl_t *, nvlist_t *);
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* _PLUGIN_SUN_IMPL_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/scsi/plugins/ses/SUN/common/sun_pages.c	Sun Apr 11 11:20:12 2010 -0700
@@ -0,0 +1,79 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#include <stddef.h>
+#include <strings.h>
+
+#include <scsi/libses.h>
+#include <scsi/libses_plugin.h>
+#include <scsi/plugins/ses/vendor/sun.h>
+#include <scsi/plugins/ses/vendor/sun_impl.h>
+
+/*ARGSUSED*/
+static void *
+sun_fruid_index(ses_plugin_t *sp, ses_node_t *np, void *data,
+    size_t pagelen, size_t *len)
+{
+	uint64_t index;
+	nvlist_t *props = ses_node_props(np);
+	sun_fruid_page_impl_t *sfpip = data;
+	sun_fru_descr_impl_t *sfdip;
+	uint16_t *addr;
+
+	if (ses_node_type(np) != SES_NODE_ELEMENT &&
+	    ses_node_type(np) != SES_NODE_ENCLOSURE)
+		return (NULL);
+
+	if (nvlist_lookup_uint64(props, SES_PROP_ELEMENT_ONLY_INDEX,
+	    &index) != 0)
+		return (NULL);
+
+	addr = &sfpip->sfpi_descr_addrs[index];
+	if (!SES_WITHIN_PAGE_STRUCT(addr, data, pagelen))
+		return (NULL);
+
+	sfdip = (sun_fru_descr_impl_t *)((uint8_t *)sfpip + SCSI_READ16(addr));
+	if (!SES_WITHIN_PAGE_STRUCT(sfdip, data, pagelen))
+		return (NULL);
+
+	*len = MIN(((uint8_t *)sfpip - (uint8_t *)sfdip) + pagelen,
+	    SCSI_READ16(&sfdip->sfdi_fru_data_length) +
+	    offsetof(sun_fru_descr_impl_t, sfdi_fru_data));
+
+	return (sfdip);
+}
+
+ses_pagedesc_t sun_pages[] = {
+{
+	.spd_pagenum = SUN_DIAGPAGE_FRUID,
+	.spd_index = sun_fruid_index,
+	.spd_req = SES_REQ_OPTIONAL_STANDARD,
+	.spd_gcoff = offsetof(sun_fruid_page_impl_t, sfpi_generation_code)
+},
+{
+	.spd_pagenum = -1,
+	.spd_gcoff = -1
+}
+};
--- a/usr/src/lib/scsi/plugins/ses/SUN/common/sun_spms.c	Sun Apr 11 11:07:03 2010 +0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,142 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-
-/*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
- */
-
-#include <stddef.h>
-#include <string.h>
-#include <strings.h>
-#include <alloca.h>
-
-#include <scsi/libses.h>
-#include <scsi/libses_plugin.h>
-#include <sys/scsi/impl/spc3_types.h>
-#include <scsi/plugins/ses/framework/ses2_impl.h>
-
-/*
- * Sun SPMS-1 r106, section 4.2.4 - Configuration
- * Sun SPMS r106, section 4.1.3.1, Table 8 - Sun Feature Definition
- * SES-2 r20, section 6.1.2.2, Table 7 - Enclosure Descriptor
- * SPC-4 r14, section 6.4.2, Table 121 - Std. INQUIRY data format
- *
- * Vendor Specific Enclosure Information:
- * (The below offsets are relative to the SES2 Enclosure Descriptor.)
- *    Sun Feature Block, starts at offset 0x28, size 20 bytes
- *    Platform specific content, starts at offset 0x64, variable size
- *
- */
-#pragma pack(1)
-
-typedef struct ses_sun_spms_vs {
-	char		ssvs_spms_header[4];
-	uint8_t		ssvs_spms_major_ver;
-	uint8_t		__reserved1;
-	uint16_t	ssvs_spms_revision;
-	uint8_t		ssvs_chassis_id_off;
-	uint8_t		ssvs_chassis_id_len;
-	DECL_BITFIELD2(
-	    ssvs_fw_upload_max_chunk_sz	:7,
-	    ssvs_int			:1);
-	uint8_t		__reserved2[49];
-	uint8_t		ssvs_ps[1];	/* Flexible platform specific content */
-} ses_sun_spms_vs_t;
-
-#pragma pack()
-
-/*ARGSUSED*/
-static int
-sun_parse_node(ses_plugin_t *sp, ses_node_t *np)
-{
-	ses_sun_spms_vs_t *sfbp;
-	nvlist_t *encprops, *lid_nv;
-	uint8_t *vsp;
-	uint_t vsp_len;
-	uint_t cid_off, cid_len;
-	uint64_t wwn;
-	char lid[17];
-	int nverr;
-
-	if (ses_node_type(np) != SES_NODE_ENCLOSURE)
-		return (0);
-
-	encprops = ses_node_props(np);
-	if (nvlist_lookup_byte_array(encprops, SES_EN_PROP_VS,
-	    &vsp, &vsp_len) != 0 ||
-	    vsp_len < offsetof(ses_sun_spms_vs_t, __reserved2))
-		return (0);
-
-	sfbp = (ses_sun_spms_vs_t *)vsp;
-
-	if (strncmp(sfbp->ssvs_spms_header, "SPMS", 4) != 0)
-		return (0);
-
-
-	/*
-	 * NOTE - The following is a temporary mechanism to identify
-	 *	subchassis until SPMS defines a formal method to do so.
-	 */
-	if (nvlist_lookup_nvlist(encprops, SES_EN_PROP_LID, &lid_nv) != 0 ||
-	    nvlist_lookup_uint64(lid_nv, SPC3_NAA_INT, &wwn) != 0)
-		return (0);
-
-	(void) snprintf(lid, sizeof (lid), "%llx", wwn);
-
-	SES_NV_ADD(fixed_string, nverr, encprops, LIBSES_EN_PROP_SUBCHASSIS_ID,
-	    lid, 16);
-
-	if (sfbp->ssvs_chassis_id_off < 96)
-		return (0);
-
-	cid_len = sfbp->ssvs_chassis_id_len;
-	if (cid_len < 4)
-		return (0);
-
-	/*
-	 * The offset read from the Sun Feature Block needs to be adjusted
-	 * so that the difference in the sizes of the Enclosure
-	 * Descriptor and the INQUIRY data format is accounted for.
-	 */
-	cid_off = sfbp->ssvs_chassis_id_off - (sizeof (ses2_ed_impl_t) - 1);
-	cid_off += offsetof(ses2_ed_impl_t, st_priv[0]) -
-	    offsetof(spc3_inquiry_data_t, id_vs_36[0]);
-
-	if (cid_off + cid_len > vsp_len)
-		return (0);
-
-	SES_NV_ADD(fixed_string, nverr, encprops, LIBSES_EN_PROP_CSN,
-	    (char *)(vsp + cid_off), cid_len);
-
-	return (0);
-}
-
-int
-_ses_init(ses_plugin_t *sp)
-{
-	ses_plugin_config_t config = {
-		.spc_node_parse = sun_parse_node
-	};
-
-	return (ses_plugin_register(sp, LIBSES_PLUGIN_VERSION,
-	    &config) != 0);
-}
--- a/usr/src/lib/scsi/plugins/ses/libses/Makefile.com	Sun Apr 11 11:07:03 2010 +0800
+++ b/usr/src/lib/scsi/plugins/ses/libses/Makefile.com	Sun Apr 11 11:20:12 2010 -0700
@@ -20,10 +20,8 @@
 #
 
 #
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
+# Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
 #
-#ident	"%Z%%M%	%I%	%E% SMI"
 
 MODULE =	libses
 SRCS =		libses.c	\
@@ -35,5 +33,7 @@
 
 SES2HDR =	$(ROOTPLUGINHDRDIR)/ses/framework/ses2.h
 
+CLEANFILES +=	../common/libses_elemtype.c
+
 ../common/libses_elemtype.c: ../common/mkelemtype.sh $(SES2HDR)
 	sh ../common/mkelemtype.sh < $(SES2HDR) > $@
--- a/usr/src/lib/scsi/plugins/ses/libses/common/libses.h	Sun Apr 11 11:07:03 2010 +0800
+++ b/usr/src/lib/scsi/plugins/ses/libses/common/libses.h	Sun Apr 11 11:20:12 2010 -0700
@@ -20,8 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 #ifndef	_FRAMEWORK_LIBSES_H
@@ -52,6 +51,8 @@
  */
 #define	LIBSES_PROP_PART		"libses-part-number"
 #define	LIBSES_PROP_SERIAL		"libses-serial-number"
+#define	LIBSES_PROP_FRU			"libses-is-fru"
+#define	LIBSES_PROP_PHYS_PARENT		"libses-physical-parent-element-index"
 
 /*
  * The chassis serial number is a pseudo property that doesn't exist in SES
@@ -76,6 +77,12 @@
  */
 #define	LIBSES_EN_PROP_SUBCHASSIS_ID	"libses-subchassis-id"
 
+/*
+ * Maximum allowed firmware upload chunk size.  Obtained in a vendor- or
+ * platform-specific manner but generic in nature.
+ */
+#define	LIBSES_EN_PROP_FIRMWARE_CHUNK_SIZE	"libses-firmware-chunksize"
+
 #ifdef	__cplusplus
 }
 #endif
--- a/usr/src/lib/scsi/plugins/ses/ses2/common/ses2.h	Sun Apr 11 11:07:03 2010 +0800
+++ b/usr/src/lib/scsi/plugins/ses/ses2/common/ses2.h	Sun Apr 11 11:20:12 2010 -0700
@@ -20,14 +20,11 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
-#ifndef	_FRAMEWORK_SES_H
-#define	_FRAMEWORK_SES_H
-
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
+#ifndef	_FRAMEWORK_SES2_H
+#define	_FRAMEWORK_SES2_H
 
 #ifdef	__cplusplus
 extern "C" {
@@ -81,6 +78,7 @@
 
 #define	SES_PROP_ELEMENT_CLASS_INDEX	"ses-element-class-index" /* U64 */
 #define	SES_PROP_ELEMENT_INDEX		"ses-element-index"	/* U64 */
+#define	SES_PROP_ELEMENT_ONLY_INDEX	"ses-element-only-index" /* U64 */
 #define	SES_PROP_BAY_NUMBER		"ses-bay-number"	/* U64 */
 #define	SES_PROP_PRDFAIL		"ses-failure-predicted"
 #define	SES_PROP_SWAP			"ses-swapped"
@@ -515,9 +513,10 @@
 #define	SES_CTL_PROP_UCODE_DATA		"ses-ctl-ucode-data"
 #define	SES_CTL_PROP_UCODE_BUFID	"ses-ctl-ucode-bufid"
 #define	SES_CTL_PROP_UCODE_MODE		"ses-ctl-ucode-mode"
+#define	SES_CTL_PROP_UCODE_DATA_LEN	"ses-ctl-ucode-data-length" /* U64 */
 
 #ifdef	__cplusplus
 }
 #endif
 
-#endif	/* _FRAMEWORK_SES_H */
+#endif	/* _FRAMEWORK_SES2_H */
--- a/usr/src/lib/scsi/plugins/ses/ses2/common/ses2_enclosure.c	Sun Apr 11 11:07:03 2010 +0800
+++ b/usr/src/lib/scsi/plugins/ses/ses2/common/ses2_enclosure.c	Sun Apr 11 11:20:12 2010 -0700
@@ -20,12 +20,9 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <stddef.h>
 #include <string.h>
 #include <strings.h>
@@ -77,7 +74,7 @@
 	ses2_subhelp_text_impl_t *tip;
 	nvlist_t *nvl = ses_node_props(np);
 	uint64_t eid;
-	size_t len;
+	size_t len, textlen;
 	off_t pos;
 	int nverr;
 
@@ -97,14 +94,15 @@
 			if (tip->ssti_subenclosure_identifier != eid)
 				continue;
 
+			textlen = SCSI_READ16(
+			    &tip->ssti_subenclosure_help_text_length);
+
 			if (!SES_WITHIN_PAGE(tip->ssti_subenclosure_help_text,
-			    tip->ssti_subenclosure_help_text_length, shpip,
-			    len))
+			    textlen, shpip, len))
 				break;
 
 			SES_NV_ADD(fixed_string, nverr, nvl, SES_EN_PROP_HELP,
-			    tip->ssti_subenclosure_help_text,
-			    tip->ssti_subenclosure_help_text_length);
+			    tip->ssti_subenclosure_help_text, textlen);
 			return (0);
 		}
 	}
@@ -155,13 +153,15 @@
 			if (dip->ssidi_subenclosure_identifier != eid)
 				continue;
 
-			if (!SES_WITHIN_PAGE(dip->ssidi_data,
-			    dip->ssidi_substring_data_length, ssip, len))
+			textlen =
+			    SCSI_READ16(&dip->ssidi_substring_data_length);
+
+			if (!SES_WITHIN_PAGE(dip->ssidi_data, textlen,
+			    ssip, len))
 				break;
 
 			SES_NV_ADD(fixed_string, nverr, nvl, SES_EN_PROP_STRING,
-			    (char *)dip->ssidi_data,
-			    dip->ssidi_substring_data_length);
+			    (char *)dip->ssidi_data, textlen);
 			return (0);
 		}
 	}
--- a/usr/src/lib/scsi/plugins/ses/ses2/common/ses2_enclosure_ctl.c	Sun Apr 11 11:07:03 2010 +0800
+++ b/usr/src/lib/scsi/plugins/ses/ses2/common/ses2_enclosure_ctl.c	Sun Apr 11 11:20:12 2010 -0700
@@ -18,18 +18,11 @@
  *
  * CDDL HEADER END
  */
-/*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
- */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <sys/types.h>
 #include <stddef.h>
 #include <stdio.h>
@@ -40,7 +33,7 @@
 #include <scsi/libses.h>
 #include "ses2_impl.h"
 
-#define	SES_UCODE_CHUNK_SIZE	(32 * 1024)
+#define	SES_UCODE_DEF_CHUNK	(32 * 1024)
 
 /*ARGSUSED*/
 static int
@@ -53,6 +46,7 @@
 	size_t offset, len, pagelen;
 	uint_t datalen;
 	uint64_t mode;
+	uint64_t chunksz = SES_UCODE_DEF_CHUNK;
 
 	/*
 	 * Get the data and check the length.
@@ -83,10 +77,15 @@
 		bufid = 0;
 
 	(void) nvlist_lookup_uint64(nvl, SES_CTL_PROP_UCODE_BUFID, &bufid);
+	(void) nvlist_lookup_uint64(nvl, SES_CTL_PROP_UCODE_DATA_LEN, &chunksz);
 
-	for (offset = 0; offset < datalen; offset += SES_UCODE_CHUNK_SIZE)  {
+	if (chunksz & 3)
+		return (ses_error(ESES_RANGE,
+		    "upload chunk size %llu is not divisible by 4", chunksz));
 
-		len = MIN(datalen - offset, SES_UCODE_CHUNK_SIZE);
+	for (offset = 0; offset < datalen; offset += chunksz)  {
+
+		len = MIN(datalen - offset, chunksz);
 		if (len & 0x3)
 			pagelen = (len + 4) & ~0x3;
 		else
@@ -114,6 +113,7 @@
 	(void) nvlist_remove_all(nvl, SES_CTL_PROP_UCODE_DATA);
 	(void) nvlist_remove_all(nvl, SES_CTL_PROP_UCODE_MODE);
 	(void) nvlist_remove_all(nvl, SES_CTL_PROP_UCODE_BUFID);
+	(void) nvlist_remove_all(nvl, SES_CTL_PROP_UCODE_DATA_LEN);
 
 	return (0);
 }
--- a/usr/src/lib/scsi/plugins/ses/ses2/common/ses2_impl.h	Sun Apr 11 11:07:03 2010 +0800
+++ b/usr/src/lib/scsi/plugins/ses/ses2/common/ses2_impl.h	Sun Apr 11 11:20:12 2010 -0700
@@ -20,15 +20,12 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 #ifndef	_PLUGIN_SES_IMPL_H
 #define	_PLUGIN_SES_IMPL_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #ifdef	__cplusplus
 extern "C" {
 #endif
@@ -1348,7 +1345,7 @@
 } ses2_subhelp_text_impl_t;
 
 #define	SES2_SUBHELP_LEN(stip)	\
-	((stip)->ssti_subenclosure_help_text_length + \
+	(SCSI_READ16(&(stip)->ssti_subenclosure_help_text_length) + \
 	    offsetof(ses2_subhelp_text_impl_t, ssti_subenclosure_help_text[0]))
 /*
  * SES-2 Subenclosure String Out diagnostic page (Table 42, 6.1.15).
@@ -1383,7 +1380,7 @@
 } ses2_substring_in_data_impl_t;
 
 #define	SES2_SUBSTR_LEN(sdip)	\
-	((sdip)->ssidi_substring_data_length + \
+	(SCSI_READ16(&(sdip)->ssidi_substring_data_length) + \
 	    offsetof(ses2_substring_in_data_impl_t, ssidi_data[0]))
 
 /*
--- a/usr/src/lib/scsi/plugins/ses/ses2/common/ses2_pages.c	Sun Apr 11 11:07:03 2010 +0800
+++ b/usr/src/lib/scsi/plugins/ses/ses2/common/ses2_pages.c	Sun Apr 11 11:20:12 2010 -0700
@@ -20,12 +20,9 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <stddef.h>
 #include <strings.h>
 
@@ -359,61 +356,74 @@
 ses_pagedesc_t ses2_pages[] = {
 {
 	.spd_pagenum = SES2_DIAGPAGE_SUPPORTED_PAGES,
+	.spd_req = SES_REQ_MANDATORY_ALL,
 	.spd_gcoff = -1
 },
 {
 	.spd_pagenum = SES2_DIAGPAGE_CONFIG,
+	.spd_req = SES_REQ_MANDATORY_STANDARD,
 	.spd_gcoff = offsetof(ses2_config_page_impl_t, scpi_generation_code)
 },
 {
 	.spd_pagenum = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
+	.spd_req = SES_REQ_MANDATORY_STANDARD,
 	.spd_index = ses2_status_index,
 	.spd_gcoff = offsetof(ses2_status_page_impl_t, sspi_generation_code)
 },
 {
 	.spd_pagenum = SES2_DIAGPAGE_HELP_TEXT,
+	.spd_req = SES_REQ_OPTIONAL_STANDARD,
 	.spd_gcoff = -1
 },
 {
 	.spd_pagenum = SES2_DIAGPAGE_STRING_IO,
+	.spd_req = SES_REQ_OPTIONAL_STANDARD,
 	.spd_gcoff = -1
 },
 {
 	.spd_pagenum = SES2_DIAGPAGE_THRESHOLD_IO,
 	.spd_index = ses2_threshold_index,
+	.spd_req = SES_REQ_OPTIONAL_STANDARD,
 	.spd_gcoff =
 	    offsetof(ses2_threshold_in_page_impl_t, stipi_generation_code)
 },
 {
 	.spd_pagenum = SES2_DIAGPAGE_ELEMENT_DESC,
 	.spd_index = ses2_element_index,
+	.spd_req = SES_REQ_OPTIONAL_STANDARD,
 	.spd_gcoff = offsetof(ses2_elem_desc_page_impl_t, sedpi_generation_code)
 },
 {
 	.spd_pagenum = SES2_DIAGPAGE_ADDL_ELEM_STATUS,
 	.spd_index = ses2_aes_index,
+	.spd_req = SES_REQ_OPTIONAL_STANDARD,
 	.spd_gcoff = offsetof(ses2_aes_page_impl_t, sapi_generation_code)
 },
 {
 	.spd_pagenum = SES2_DIAGPAGE_SUBENCLOSURE_HELP_TEXT,
+	.spd_req = SES_REQ_OPTIONAL_STANDARD,
 	.spd_gcoff = offsetof(ses2_subhelp_page_impl_t, sspi_generation_code)
 },
 {
 	.spd_pagenum = SES2_DIAGPAGE_SUBENCLOSURE_STRING_IO,
+	.spd_req = SES_REQ_OPTIONAL_STANDARD,
 	.spd_gcoff =
 	    offsetof(ses2_substring_in_page_impl_t, ssipi_generation_code)
 },
 {
 	.spd_pagenum = SES2_DIAGPAGE_SUPPORTED_SES_PAGES,
+	.spd_req = SES_REQ_OPTIONAL_STANDARD,
 	.spd_gcoff = -1
 },
 {
 	.spd_pagenum = SES2_DIAGPAGE_DL_MICROCODE_CTL_STATUS,
+	.spd_req = SES_REQ_OPTIONAL_STANDARD,
 	.spd_gcoff =
 	    offsetof(ses2_ucode_status_page_impl_t, suspi_generation_code)
 },
 {
 	.spd_pagenum = SES2_DIAGPAGE_SUBENCLOSURE_NICKNAME_CTL_STATUS,
+	.spd_req = SES_REQ_OPTIONAL_STANDARD,
 	.spd_gcoff =
 	    offsetof(ses2_subnick_status_page_impl_t, sspci_generation_code)
 },
@@ -422,23 +432,27 @@
 	.spd_pagenum = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
 	.spd_ctl_len = ses2_ctl_len,
 	.spd_ctl_fill = ses2_ctl_fill,
+	.spd_req = SES_REQ_MANDATORY_STANDARD,
 	.spd_gcoff = offsetof(ses2_control_page_impl_t, scpi_generation_code)
 },
 {
 	.spd_pagenum = SES2_DIAGPAGE_STRING_IO,
 	.spd_ctl_len = ses2_stringout_len,
+	.spd_req = SES_REQ_OPTIONAL_STANDARD,
 	.spd_gcoff = -1
 },
 {
 	.spd_pagenum = SES2_DIAGPAGE_THRESHOLD_IO,
 	.spd_ctl_len = ses2_threshout_len,
 	.spd_ctl_fill = ses2_threshout_ctl_fill,
+	.spd_req = SES_REQ_OPTIONAL_STANDARD,
 	.spd_gcoff =
 	    offsetof(ses2_threshold_out_page_impl_t, stopi_generation_code)
 },
 {
 	.spd_pagenum = SES2_DIAGPAGE_SUBENCLOSURE_STRING_IO,
 	.spd_ctl_len = ses2_substrout_len,
+	.spd_req = SES_REQ_OPTIONAL_STANDARD,
 	.spd_gcoff =
 	    offsetof(ses2_substring_out_page_impl_t, ssopi_generation_code)
 },
@@ -446,12 +460,14 @@
 	.spd_pagenum = SES2_DIAGPAGE_DL_MICROCODE_CTL_STATUS,
 	.spd_ctl_len = ses2_ucodeout_len,
 	.spd_ctl_fill = ses2_ucodeout_ctl_fill,
+	.spd_req = SES_REQ_OPTIONAL_STANDARD,
 	.spd_gcoff =
 	    offsetof(ses2_ucode_ctl_page_impl_t, sucpi_generation_code)
 },
 {
 	.spd_pagenum = SES2_DIAGPAGE_SUBENCLOSURE_NICKNAME_CTL_STATUS,
 	.spd_ctl_len = ses2_subnickout_len,
+	.spd_req = SES_REQ_OPTIONAL_STANDARD,
 	.spd_gcoff =
 	    offsetof(ses2_subnick_ctl_page_impl_t, sspci_generation_code)
 },
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/scsi/plugins/smp/Makefile	Sun Apr 11 11:20:12 2010 -0700
@@ -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 (c) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+SUBDIRS =	\
+	sas2	\
+	usmp
+
+.KEEP_STATE:
+
+.PARALLEL:
+
+include ../../Makefile.subdirs
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/scsi/plugins/smp/Makefile.lib	Sun Apr 11 11:20:12 2010 -0700
@@ -0,0 +1,83 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+.KEEP_STATE:
+.SUFFIXES:
+
+include ../../../../../../cmd/Makefile.cmd
+include ../../../../Makefile.defs
+
+#
+# Set PROG and OBJS based on the values of MODULE and SRCS.  We expect that
+# these macros to be defined by the Makefile that is including this file.
+#
+PROG = $(MODULE:%=%.so)
+YOBJS = $(YSRCS:%.y=%.o)
+OBJS = $(YOBJS) $(SRCS:%.c=%.o)
+
+#
+# A module may set DMOD and DMOD_SRCS if it has a mdb proc module.
+# DMOD, if set, must match PROG above (for mdb autoloading) so it will
+# be built in a subdirectory.
+#
+ROOTDMOD = $(DMOD:%.so=$(ROOT)/usr/lib/mdb/proc/%.so)
+ROOTDMOD64 = $(DMOD:%.so=$(ROOT)/usr/lib/mdb/proc/$(MACH64)/%.so)
+DMODPROG = $(DMOD:%=dmod/%)
+DMOD_OBJS = $(DMOD_SRCS:%.c=%.o)
+
+ROOTPLUGINDIR = $(ROOTPLUGINLIBDIR)/smp/$(PLUGINTYPE)
+ROOTPLUGINDIR64 = $(ROOTPLUGINLIBDIR)/smp/$(PLUGINTYPE)/$(MACH64)
+
+ROOTPROG = $(ROOTPLUGINDIR)/$(PROG)
+ROOTPROG64 = $(ROOTPLUGINDIR64)/$(PROG)
+
+#
+# A module can set ALIASES as a list of additional names to correspond to the
+# same library.
+#
+ROOTALIASES = $(ALIASES:%=$(ROOTPLUGINDIR)/%.so)
+ROOTALIASES64 = $(ALIASES:%=$(ROOTPLUGINDIR64)/%.so)
+
+LINTFLAGS += -mu
+LINTFILES = $(SRCS:%.c=%.ln)
+
+DMODLINTTGT = $(DMOD:%=lint_dmod)
+DMODLINTFILES = $(DMOD_SRCS:%.c=%.ln)
+
+APIMAP = ../../../../libsmp/libsmp_api.map
+
+C99MODE = $(C99_ENABLE)
+CFLAGS += $(CTF_FLAGS) $(CCVERBOSE) $(XSTRCONST) $(CC_PICFLAGS)
+CFLAGS += -G $(XREGSFLAG) 
+CFLAGS64 += $(CTF_FLAGS) $(CCVERBOSE) $(XSTRCONST) $(CC_PICFLAGS)
+CFLAGS64 += -G $(XREGSFLAG) 
+CPPFLAGS += -D_POSIX_PTHREAD_SEMANTICS -D_REENTRANT
+$(NOT_RELEASE_BUILD)CPPFLAGS += -DDEBUG
+LDFLAGS += $(ZTEXT) $(ZCOMBRELOC) $(ZIGNORE)
+
+$(PROG) := LDFLAGS += $(ZDEFS) -M$(APIMAP)
+$(PROG) := LDLIBS += -lc
+
+$(DMODPROG) := LDFLAGS += $(ZNODEFS)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/scsi/plugins/smp/Makefile.plugin	Sun Apr 11 11:20:12 2010 -0700
@@ -0,0 +1,57 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+include $(SRC)/Makefile.master
+
+SUBDIRS = $(MACH)
+$(BUILD64)SUBDIRS += $(MACH64)
+
+include ../../../Makefile.defs
+
+ROOTHDRDIR = $(ROOTPLUGINHDRDIR)/smp/$(PLUGINTYPE)
+ROOTHDRS = $(HDRS:%=$(ROOTHDRDIR)/%)
+
+all :=		TARGET= all
+clean :=	TARGET= clean
+clobber :=	TARGET= clobber
+install :=	TARGET= install
+lint :=		TARGET= lint
+install_h:=	TARGET = install_h
+
+.KEEP_STATE:
+
+all install clean clobber lint: $(SUBDIRS)
+
+install_h: $(ROOTHDRDIR) $(ROOTHDRS)
+
+check:
+
+$(SUBDIRS):	FRC
+	@cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
+
+include ../../../Makefile.rootdirs
+include ../../../../Makefile.targ
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/scsi/plugins/smp/Makefile.targ	Sun Apr 11 11:20:12 2010 -0700
@@ -0,0 +1,86 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+all: $(PROG) $(DMODPROG)
+
+.NO_PARALLEL:
+.PARALLEL: $(OBJS) $(LINTFILES) $(DMOD_OBJS) $(DMODLINTFILES)
+
+$(PROG): $(OBJS) $(APIMAP)
+	$(LINK.c) $(OBJS) -o $@ $(LDLIBS)
+	$(CTFMERGE) -L VERSION -o $@ $(OBJS)
+	$(POST_PROCESS_SO)
+
+$(DMODPROG): $(DMOD_OBJS)
+	-@mkdir -p $(@D)
+	$(LINK.c) $(DMOD_OBJS) -o $@
+	$(POST_PROCESS)
+
+%.o: %.c
+	$(COMPILE.c) $<
+	$(CTFCONVERT_O)
+
+%.o: $(SRCDIR)/%.c
+	$(COMPILE.c) $<
+	$(CTFCONVERT_O)
+
+clean:
+	$(RM) $(OBJS) $(DMOD_OBJS) $(LINTFILES) $(DMODLINTFILES) $(CLEANFILES)
+
+clobber: clean
+	$(RM) $(PROG) $(DMODPROG)
+
+%.ln: %.c
+	$(LINT.c) -c $<
+
+%.ln: $(SRCDIR)/%.c
+	$(LINT.c) -c $<
+
+lint_prog: $(LINTFILES)
+	$(LINT) $(LINTFLAGS) $(LINTFILES) $(LDLIBS)
+
+lint_dmod: $(DMODLINTFILES)
+	$(LINT) $(LINTFLAGS) $(DMODLINTFILES) $(LDLIBS)
+
+lint: lint_prog $(DMODLINTTGT)
+
+install_h:
+
+$(ROOTPLUGINDIR)/%: $(PROG)
+	$(RM) $@; $(LN) -s $< $@
+
+$(ROOTPLUGINDIR64)/%: $(PROG)
+	$(RM) $@; $(LN) -s $< $@
+
+$(ROOTPROG): $$(@D) $(PROG)
+	$(RM) $@; $(INS) -s -m 0755 -f $(@D) $(PROG)
+
+$(ROOTPROG64): $$(@D) $(PROG)
+	$(RM) $@; $(INS) -s -m 0755 -f $(@D) $(PROG)
+
+$(ROOTDMOD): $$(@D) $(DMODPROG)
+	$(RM) $@; $(INS) -s -m 0755 -f $(@D) $(DMODPROG)
+
+include ../../../../Makefile.rootdirs
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/scsi/plugins/smp/sas2/Makefile	Sun Apr 11 11:20:12 2010 -0700
@@ -0,0 +1,30 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+HDRS =
+HDRDIR = common
+PLUGINTYPE = framework
+
+include ../Makefile.plugin
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/scsi/plugins/smp/sas2/Makefile.com	Sun Apr 11 11:20:12 2010 -0700
@@ -0,0 +1,33 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+MODULE =	sas2
+SRCS =		sas2.c \
+		sas2_functions.c
+
+SRCDIR =        ../common
+PLUGINTYPE =    framework
+
+include ../../Makefile.lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/scsi/plugins/smp/sas2/amd64/Makefile	Sun Apr 11 11:20:12 2010 -0700
@@ -0,0 +1,31 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+include ../Makefile.com
+include $(SRC)/Makefile.master.64
+
+install: all $(ROOTPROG64)
+
+include ../../Makefile.targ
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/scsi/plugins/smp/sas2/common/sas2.c	Sun Apr 11 11:20:12 2010 -0700
@@ -0,0 +1,39 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#include <scsi/libsmp.h>
+#include <scsi/libsmp_plugin.h>
+#include "sas2.h"
+
+int
+_smp_init(smp_plugin_t *pp)
+{
+	smp_plugin_config_t config = {
+		.spc_name = "SAS-2",
+		.spc_functions = sas2_functions
+	};
+
+	return (smp_plugin_register(pp, LIBSMP_PLUGIN_VERSION, &config));
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/scsi/plugins/smp/sas2/common/sas2.h	Sun Apr 11 11:20:12 2010 -0700
@@ -0,0 +1,39 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#ifndef	_SAS2_H
+#define	_SAS2_H
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+extern smp_function_def_t sas2_functions[];
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* _SAS2_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/scsi/plugins/smp/sas2/common/sas2_functions.c	Sun Apr 11 11:20:12 2010 -0700
@@ -0,0 +1,1066 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#include <sys/types.h>
+#include <sys/scsi/generic/commands.h>
+#include <sys/scsi/impl/commands.h>
+#include <sys/scsi/generic/smp_frames.h>
+
+#include <scsi/libsmp.h>
+#include <scsi/libsmp_plugin.h>
+#include "sas2.h"
+
+/*ARGSUSED*/
+static size_t
+sas2_rq_len(size_t user, smp_target_t *tp)
+{
+	if (user != 0) {
+		(void) smp_set_errno(ESMP_RANGE);
+		return (0);
+	}
+
+	return (SMP_REQ_MINLEN);
+}
+
+/*ARGSUSED*/
+static off_t
+sas2_rq_dataoff(smp_action_t *ap, smp_target_t *tp)
+{
+	size_t len;
+
+	smp_action_get_request_frame(ap, NULL, &len);
+
+	if (len > SMP_REQ_MINLEN)
+		return (offsetof(smp_request_frame_t, srf_data[0]));
+
+	return (-1);
+}
+
+static void
+sas2_rq_setframe(smp_action_t *ap, smp_target_t *tp)
+{
+	const smp_function_def_t *dp = smp_action_get_function_def(ap);
+	smp_request_frame_t *fp;
+	uint_t cap;
+	uint16_t change_count;
+	uint16_t *rqcc;
+	size_t rqlen, rslen;
+
+	smp_action_get_request_frame(ap, (void *)&fp, &rqlen);
+	smp_action_get_response_frame(ap, NULL, &rslen);
+	cap = smp_target_getcap(tp);
+
+	fp->srf_frame_type = SMP_FRAME_TYPE_REQUEST;
+	fp->srf_function = dp->sfd_function;
+
+	if (cap & SMP_TARGET_C_LONG_RESP) {
+		fp->srf_allocated_response_len = (rslen - SMP_RESP_MINLEN) / 4;
+		fp->srf_request_len = (rqlen - SMP_REQ_MINLEN) / 4;
+	} else {
+		fp->srf_allocated_response_len = 0;
+		fp->srf_request_len = 0;
+	}
+
+	/*
+	 * If this command requires that the expected expander change count
+	 * be set (as many do), we will attempt to set it based on the
+	 * most recently executed command.  However, if the user has set it
+	 * already, we will not overwrite that setting.  It is the consumer's
+	 * responsibility to keep track of expander changes each time it
+	 * receives a new change count in a response.
+	 */
+	if (dp->sfd_flags & SMP_FD_F_NEEDS_CHANGE_COUNT) {
+		ASSERT(rqlen >= SMP_REQ_MINLEN + sizeof (uint16_t));
+		/* LINTED - alignment */
+		rqcc = (uint16_t *)(&fp->srf_data[0]);
+		if (SCSI_READ16(rqcc) == 0) {
+			change_count = smp_target_get_change_count(tp);
+			SCSI_WRITE16(rqcc, change_count);
+		}
+	}
+}
+
+/*ARGSUSED*/
+static size_t
+sas2_rs_datalen(smp_action_t *ap, smp_target_t *tp)
+{
+	smp_response_frame_t *fp;
+	size_t len;
+
+	smp_action_get_response_frame(ap, (void **)&fp, &len);
+
+	if (len >= SMP_RESP_MINLEN)
+		len -= SMP_RESP_MINLEN;
+	else
+		return (0);
+
+	len &= ~3;
+
+	if (fp->srf_response_len == 0)
+		return (0);
+
+	return (MIN(len, 4 * (fp->srf_response_len)));
+}
+
+/*ARGSUSED*/
+static off_t
+sas2_rs_dataoff(smp_action_t *ap, smp_target_t *tp)
+{
+	size_t len;
+
+	smp_action_get_response_frame(ap, NULL, &len);
+
+	if (len > SMP_RESP_MINLEN)
+		return (offsetof(smp_request_frame_t, srf_data[0]));
+
+	return (-1);
+}
+
+static void
+sas2_rs_getparams(smp_action_t *ap, smp_target_t *tp)
+{
+	const smp_function_def_t *dp;
+	smp_response_frame_t *fp;
+	size_t len;
+	uint16_t change_count;
+
+	dp = smp_action_get_function_def(ap);
+
+	smp_action_get_response_frame(ap, (void **)&fp, &len);
+
+	smp_action_set_result(ap, fp->srf_result);
+
+	if (!(dp->sfd_flags & SMP_FD_F_PROVIDES_CHANGE_COUNT))
+		return;
+
+	if (len <= SMP_RESP_MINLEN + sizeof (uint16_t))
+		return;
+
+	change_count = SCSI_READ16(&fp->srf_data[0]);
+	smp_target_set_change_count(tp, change_count);
+}
+
+/*ARGSUSED*/
+static size_t
+sas2_report_general_rs_datalen(smp_action_t *ap, smp_target_t *tp)
+{
+	const smp_function_def_t *dp = smp_action_get_function_def(ap);
+	smp_response_frame_t *fp;
+	size_t len;
+
+	ASSERT(dp->sfd_function == SMP_FUNC_REPORT_GENERAL);
+	smp_action_get_response_frame(ap, (void **)&fp, &len);
+
+	if (len >= SMP_RESP_MINLEN)
+		len -= SMP_RESP_MINLEN;
+	else
+		return (0);
+
+	len &= ~3;
+
+	if (fp->srf_response_len == 0)
+		return (MIN(len, 24));
+
+	return (MIN(len, 4 * (fp->srf_response_len)));
+}
+
+/*ARGSUSED*/
+static size_t
+sas2_report_manufacturer_info_rs_datalen(smp_action_t *ap, smp_target_t *tp)
+{
+	const smp_function_def_t *dp = smp_action_get_function_def(ap);
+	smp_response_frame_t *fp;
+	size_t len;
+
+	ASSERT(dp->sfd_function == SMP_FUNC_REPORT_MANUFACTURER_INFO);
+	smp_action_get_response_frame(ap, (void **)&fp, &len);
+
+	if (len >= SMP_RESP_MINLEN)
+		len -= SMP_RESP_MINLEN;
+	else
+		return (0);
+
+	len &= ~3;
+
+	if (fp->srf_response_len == 0)
+		return (MIN(len, 56));
+
+	return (MIN(len, 4 * (fp->srf_response_len)));
+}
+
+/*ARGSUSED*/
+static size_t
+sas2_report_self_config_status_rq_len(size_t user, smp_target_t *tp)
+{
+	if (user != 0) {
+		(void) smp_set_errno(ESMP_RANGE);
+		return (0);
+	}
+
+	return (SMP_REQ_MINLEN + sizeof (smp_report_self_config_status_req_t));
+}
+
+/*ARGSUSED*/
+static size_t
+sas2_report_zone_perm_table_rq_len(size_t user, smp_target_t *tp)
+{
+	if (user != 0) {
+		(void) smp_set_errno(ESMP_RANGE);
+		return (0);
+	}
+
+	return (SMP_REQ_MINLEN + sizeof (smp_report_zone_perm_table_req_t));
+}
+
+/*ARGSUSED*/
+static size_t
+sas2_report_broadcast_rq_len(size_t user, smp_target_t *tp)
+{
+	if (user != 0) {
+		(void) smp_set_errno(ESMP_RANGE);
+		return (0);
+	}
+
+	return (SMP_REQ_MINLEN + sizeof (smp_report_broadcast_req_t));
+}
+
+/*ARGSUSED*/
+static size_t
+sas2_discover_rq_len(size_t user, smp_target_t *tp)
+{
+	if (user != 0) {
+		(void) smp_set_errno(ESMP_RANGE);
+		return (0);
+	}
+
+	return (SMP_REQ_MINLEN + sizeof (smp_discover_req_t));
+}
+
+/*ARGSUSED*/
+static size_t
+sas2_discover_rs_datalen(smp_action_t *ap, smp_target_t *tp)
+{
+	const smp_function_def_t *dp = smp_action_get_function_def(ap);
+	smp_response_frame_t *fp;
+	size_t len;
+
+	ASSERT(dp->sfd_function == SMP_FUNC_DISCOVER);
+	smp_action_get_response_frame(ap, (void **)&fp, &len);
+
+	if (len >= SMP_RESP_MINLEN)
+		len -= SMP_RESP_MINLEN;
+	else
+		return (0);
+
+	len &= ~3;
+
+	if (fp->srf_response_len == 0)
+		return (MIN(len, 48));
+
+	return (MIN(len, 4 * (fp->srf_response_len)));
+}
+
+/*ARGSUSED*/
+static size_t
+sas2_report_phy_error_log_rq_len(size_t user, smp_target_t *tp)
+{
+	if (user != 0) {
+		(void) smp_set_errno(ESMP_RANGE);
+		return (0);
+	}
+
+	return (SMP_REQ_MINLEN + sizeof (smp_report_phy_error_log_req_t));
+}
+
+/*ARGSUSED*/
+static size_t
+sas2_report_phy_error_log_rs_datalen(smp_action_t *ap, smp_target_t *tp)
+{
+	const smp_function_def_t *dp = smp_action_get_function_def(ap);
+	smp_response_frame_t *fp;
+	size_t len;
+
+	ASSERT(dp->sfd_function == SMP_FUNC_REPORT_PHY_ERROR_LOG);
+	smp_action_get_response_frame(ap, (void **)&fp, &len);
+
+	if (len >= SMP_RESP_MINLEN)
+		len -= SMP_RESP_MINLEN;
+	else
+		return (0);
+
+	len &= ~3;
+
+	if (fp->srf_response_len == 0)
+		return (MIN(len, sizeof (smp_report_phy_error_log_resp_t)));
+
+	return (MIN(len, 4 * (fp->srf_response_len)));
+}
+
+/*ARGSUSED*/
+static size_t
+sas2_report_phy_sata_rq_len(size_t user, smp_target_t *tp)
+{
+	if (user != 0) {
+		(void) smp_set_errno(ESMP_RANGE);
+		return (0);
+	}
+
+	return (SMP_REQ_MINLEN + sizeof (smp_report_phy_sata_req_t));
+}
+
+/*ARGSUSED*/
+static size_t
+sas2_report_phy_sata_rs_datalen(smp_action_t *ap, smp_target_t *tp)
+{
+	const smp_function_def_t *dp = smp_action_get_function_def(ap);
+	smp_response_frame_t *fp;
+	size_t len;
+
+	ASSERT(dp->sfd_function == SMP_FUNC_REPORT_PHY_SATA);
+	smp_action_get_response_frame(ap, (void **)&fp, &len);
+
+	if (len >= SMP_RESP_MINLEN)
+		len -= SMP_RESP_MINLEN;
+	else
+		return (0);
+
+	len &= ~3;
+
+	if (fp->srf_response_len == 0)
+		return (MIN(len, 52));
+
+	return (MIN(len, 4 * (fp->srf_response_len)));
+}
+
+/*ARGSUSED*/
+static size_t
+sas2_report_route_info_rq_len(size_t user, smp_target_t *tp)
+{
+	if (user != 0) {
+		(void) smp_set_errno(ESMP_RANGE);
+		return (0);
+	}
+
+	return (SMP_REQ_MINLEN + sizeof (smp_report_route_info_req_t));
+}
+
+/*ARGSUSED*/
+static size_t
+sas2_report_route_info_rs_datalen(smp_action_t *ap, smp_target_t *tp)
+{
+	const smp_function_def_t *dp = smp_action_get_function_def(ap);
+	smp_response_frame_t *fp;
+	size_t len;
+
+	ASSERT(dp->sfd_function == SMP_FUNC_REPORT_ROUTE_INFO);
+	smp_action_get_response_frame(ap, (void **)&fp, &len);
+
+	if (len >= SMP_RESP_MINLEN)
+		len -= SMP_RESP_MINLEN;
+	else
+		return (0);
+
+	len &= ~3;
+
+	if (fp->srf_response_len == 0)
+		return (MIN(len, sizeof (smp_report_route_info_resp_t)));
+
+	return (MIN(len, 4 * (fp->srf_response_len)));
+}
+
+/*ARGSUSED*/
+static size_t
+sas2_report_phy_event_rq_len(size_t user, smp_target_t *tp)
+{
+	if (user != 0) {
+		(void) smp_set_errno(ESMP_RANGE);
+		return (0);
+	}
+
+	return (SMP_REQ_MINLEN + sizeof (smp_report_phy_event_req_t));
+}
+
+/*ARGSUSED*/
+static size_t
+sas2_discover_list_rq_len(size_t user, smp_target_t *tp)
+{
+	if (user != 0) {
+		(void) smp_set_errno(ESMP_RANGE);
+		return (0);
+	}
+
+	return (SMP_REQ_MINLEN + sizeof (smp_discover_list_req_t));
+}
+
+/*ARGSUSED*/
+static size_t
+sas2_report_phy_event_list_rq_len(size_t user, smp_target_t *tp)
+{
+	if (user != 0) {
+		(void) smp_set_errno(ESMP_RANGE);
+		return (0);
+	}
+
+	return (SMP_REQ_MINLEN + sizeof (smp_report_phy_event_list_req_t));
+}
+
+/*ARGSUSED*/
+static size_t
+sas2_report_exp_route_table_list_rq_len(size_t user, smp_target_t *tp)
+{
+	if (user != 0) {
+		(void) smp_set_errno(ESMP_RANGE);
+		return (0);
+	}
+
+	return (SMP_REQ_MINLEN +
+	    sizeof (smp_report_exp_route_table_list_req_t));
+}
+
+/*ARGSUSED*/
+static size_t
+sas2_config_general_rq_len(size_t user, smp_target_t *tp)
+{
+	if (user != 0) {
+		(void) smp_set_errno(ESMP_RANGE);
+		return (0);
+	}
+
+	return (SMP_REQ_MINLEN + sizeof (smp_config_general_req_t));
+}
+
+/*ARGSUSED*/
+static size_t
+sas2_enable_disable_zoning_rq_len(size_t user, smp_target_t *tp)
+{
+	if (user != 0) {
+		(void) smp_set_errno(ESMP_RANGE);
+		return (0);
+	}
+
+	return (SMP_REQ_MINLEN + sizeof (smp_enable_disable_zoning_req_t));
+}
+
+/*ARGSUSED*/
+static size_t
+sas2_zoned_broadcast_rq_len(size_t user, smp_target_t *tp)
+{
+	size_t descrsz;
+
+	if (user == 0 || user > 1008) {
+		(void) smp_set_errno(ESMP_RANGE);
+		return (0);
+	}
+
+	descrsz = P2ROUNDUP((user - 1), 4);
+
+	return (SMP_REQ_MINLEN + descrsz + sizeof (smp_zoned_broadcast_req_t));
+}
+
+/*ARGSUSED*/
+static size_t
+sas2_zone_lock_rq_len(size_t user, smp_target_t *tp)
+{
+	if (user != 0) {
+		(void) smp_set_errno(ESMP_RANGE);
+		return (0);
+	}
+
+	return (SMP_REQ_MINLEN + sizeof (smp_zone_lock_req_t));
+}
+
+/*ARGSUSED*/
+static size_t
+sas2_zone_activate_rq_len(size_t user, smp_target_t *tp)
+{
+	if (user != 0) {
+		(void) smp_set_errno(ESMP_RANGE);
+		return (0);
+	}
+
+	return (SMP_REQ_MINLEN + sizeof (smp_zone_activate_req_t));
+}
+
+/*ARGSUSED*/
+static size_t
+sas2_zone_unlock_rq_len(size_t user, smp_target_t *tp)
+{
+	if (user != 0) {
+		(void) smp_set_errno(ESMP_RANGE);
+		return (0);
+	}
+
+	return (SMP_REQ_MINLEN + sizeof (smp_zone_unlock_req_t));
+}
+
+/*ARGSUSED*/
+static size_t
+sas2_config_zone_manager_password_rq_len(size_t user, smp_target_t *tp)
+{
+	if (user != 0) {
+		(void) smp_set_errno(ESMP_RANGE);
+		return (0);
+	}
+
+	return (SMP_REQ_MINLEN +
+	    sizeof (smp_config_zone_manager_password_req_t));
+}
+
+/*ARGSUSED*/
+static size_t
+sas2_config_zone_phy_info_rq_len(size_t user, smp_target_t *tp)
+{
+	if (user == 0 || user > 252) {
+		(void) smp_set_errno(ESMP_RANGE);
+		return (0);
+	}
+
+	return (SMP_REQ_MINLEN + sizeof (smp_config_zone_phy_info_req_t) +
+	    (user - 1) * sizeof (smp_zone_phy_config_descr_t));
+}
+
+static size_t
+sas2_config_zone_perm_table_rq_len(size_t user, smp_target_t *tp)
+{
+	uint_t cap = smp_target_getcap(tp);
+	size_t maxdescr, descrsz;
+
+	if (cap & SMP_TARGET_C_ZG_256)
+		descrsz = sizeof (smp_zone_perm_descr256_t);
+	else
+		descrsz = sizeof (smp_zone_perm_descr128_t);
+
+	maxdescr = (1020 - sizeof (smp_config_zone_perm_table_req_t)) / descrsz;
+
+	if (user == 0 || user > maxdescr) {
+		(void) smp_set_errno(ESMP_RANGE);
+		return (0);
+	}
+
+	return (SMP_REQ_MINLEN + sizeof (smp_config_zone_perm_table_req_t) - 1 +
+	    user * descrsz);
+}
+
+/*ARGSUSED*/
+static size_t
+sas2_config_route_info_rq_len(size_t user, smp_target_t *tp)
+{
+	if (user != 0) {
+		(void) smp_set_errno(ESMP_RANGE);
+		return (0);
+	}
+
+	return (SMP_REQ_MINLEN + sizeof (smp_config_route_info_req_t));
+}
+
+/*ARGSUSED*/
+static size_t
+sas2_phy_control_rq_len(size_t user, smp_target_t *tp)
+{
+	if (user != 0) {
+		(void) smp_set_errno(ESMP_RANGE);
+		return (0);
+	}
+
+	return (SMP_REQ_MINLEN + sizeof (smp_phy_control_req_t));
+}
+
+/*ARGSUSED*/
+static size_t
+sas2_phy_test_function_rq_len(size_t user, smp_target_t *tp)
+{
+	if (user != 0) {
+		(void) smp_set_errno(ESMP_RANGE);
+		return (0);
+	}
+
+	return (SMP_REQ_MINLEN + sizeof (smp_phy_test_function_req_t));
+}
+
+/*ARGSUSED*/
+static size_t
+sas2_config_phy_event_rq_len(size_t user, smp_target_t *tp)
+{
+	if (user == 0 || user > 126) {
+		(void) smp_set_errno(ESMP_RANGE);
+		return (0);
+	}
+
+	return (SMP_REQ_MINLEN + sizeof (smp_config_phy_event_req_t) +
+	    (user - 1) * sizeof (smp_phy_event_config_descr_t));
+}
+
+smp_function_def_t sas2_functions[] = {
+{
+	.sfd_function = SMP_FUNC_REPORT_GENERAL,
+	.sfd_flags = SMP_FD_F_READ | SMP_FD_F_PROVIDES_CHANGE_COUNT,
+	.sfd_rq_len = sas2_rq_len,
+	.sfd_rq_dataoff = sas2_rq_dataoff,
+	.sfd_rq_setframe = sas2_rq_setframe,
+	.sfd_rs_datalen = sas2_report_general_rs_datalen,
+	.sfd_rs_dataoff = sas2_rs_dataoff,
+	.sfd_rs_getparams = sas2_rs_getparams
+},
+{
+	.sfd_function = SMP_FUNC_REPORT_MANUFACTURER_INFO,
+	.sfd_flags = SMP_FD_F_READ | SMP_FD_F_PROVIDES_CHANGE_COUNT,
+	.sfd_rq_len = sas2_rq_len,
+	.sfd_rq_dataoff = sas2_rq_dataoff,
+	.sfd_rq_setframe = sas2_rq_setframe,
+	.sfd_rs_datalen = sas2_report_manufacturer_info_rs_datalen,
+	.sfd_rs_dataoff = sas2_rs_dataoff,
+	.sfd_rs_getparams = sas2_rs_getparams
+},
+{
+	.sfd_function = SMP_FUNC_REPORT_SELF_CONFIG_STATUS,
+	.sfd_flags = SMP_FD_F_READ | SMP_FD_F_WRITE |
+	    SMP_FD_F_PROVIDES_CHANGE_COUNT,
+	.sfd_rq_len = sas2_report_self_config_status_rq_len,
+	.sfd_rq_dataoff = sas2_rq_dataoff,
+	.sfd_rq_setframe = sas2_rq_setframe,
+	.sfd_rs_datalen = sas2_rs_datalen,
+	.sfd_rs_dataoff = sas2_rs_dataoff,
+	.sfd_rs_getparams = sas2_rs_getparams
+},
+{
+	.sfd_function = SMP_FUNC_REPORT_ZONE_PERM_TABLE,
+	.sfd_flags = SMP_FD_F_READ | SMP_FD_F_WRITE |
+	    SMP_FD_F_PROVIDES_CHANGE_COUNT,
+	.sfd_rq_len = sas2_report_zone_perm_table_rq_len,
+	.sfd_rq_dataoff = sas2_rq_dataoff,
+	.sfd_rq_setframe = sas2_rq_setframe,
+	.sfd_rs_datalen = sas2_rs_datalen,
+	.sfd_rs_dataoff = sas2_rs_dataoff,
+	.sfd_rs_getparams = sas2_rs_getparams
+},
+{
+	.sfd_function = SMP_FUNC_REPORT_ZONE_MANAGER_PASSWORD,
+	.sfd_flags = SMP_FD_F_READ | SMP_FD_F_PROVIDES_CHANGE_COUNT,
+	.sfd_rq_len = sas2_rq_len,
+	.sfd_rq_dataoff = sas2_rq_dataoff,
+	.sfd_rq_setframe = sas2_rq_setframe,
+	.sfd_rs_datalen = sas2_rs_datalen,
+	.sfd_rs_dataoff = sas2_rs_dataoff,
+	.sfd_rs_getparams = sas2_rs_getparams
+},
+{
+	.sfd_function = SMP_FUNC_REPORT_BROADCAST,
+	.sfd_flags = SMP_FD_F_READ | SMP_FD_F_WRITE |
+	    SMP_FD_F_PROVIDES_CHANGE_COUNT,
+	.sfd_rq_len = sas2_report_broadcast_rq_len,
+	.sfd_rq_dataoff = sas2_rq_dataoff,
+	.sfd_rq_setframe = sas2_rq_setframe,
+	.sfd_rs_datalen = sas2_rs_datalen,
+	.sfd_rs_dataoff = sas2_rs_dataoff,
+	.sfd_rs_getparams = sas2_rs_getparams
+},
+{
+	.sfd_function = SMP_FUNC_DISCOVER,
+	.sfd_flags = SMP_FD_F_READ | SMP_FD_F_WRITE |
+	    SMP_FD_F_PROVIDES_CHANGE_COUNT,
+	.sfd_rq_len = sas2_discover_rq_len,
+	.sfd_rq_dataoff = sas2_rq_dataoff,
+	.sfd_rq_setframe = sas2_rq_setframe,
+	.sfd_rs_datalen = sas2_discover_rs_datalen,
+	.sfd_rs_dataoff = sas2_rs_dataoff,
+	.sfd_rs_getparams = sas2_rs_getparams
+},
+{
+	.sfd_function = SMP_FUNC_REPORT_PHY_ERROR_LOG,
+	.sfd_flags = SMP_FD_F_READ | SMP_FD_F_WRITE |
+	    SMP_FD_F_PROVIDES_CHANGE_COUNT,
+	.sfd_rq_len = sas2_report_phy_error_log_rq_len,
+	.sfd_rq_dataoff = sas2_rq_dataoff,
+	.sfd_rq_setframe = sas2_rq_setframe,
+	.sfd_rs_datalen = sas2_report_phy_error_log_rs_datalen,
+	.sfd_rs_dataoff = sas2_rs_dataoff,
+	.sfd_rs_getparams = sas2_rs_getparams
+},
+{
+	.sfd_function = SMP_FUNC_REPORT_PHY_SATA,
+	.sfd_flags = SMP_FD_F_READ | SMP_FD_F_WRITE |
+	    SMP_FD_F_PROVIDES_CHANGE_COUNT,
+	.sfd_rq_len = sas2_report_phy_sata_rq_len,
+	.sfd_rq_dataoff = sas2_rq_dataoff,
+	.sfd_rq_setframe = sas2_rq_setframe,
+	.sfd_rs_datalen = sas2_report_phy_sata_rs_datalen,
+	.sfd_rs_dataoff = sas2_rs_dataoff,
+	.sfd_rs_getparams = sas2_rs_getparams
+},
+{
+	.sfd_function = SMP_FUNC_REPORT_ROUTE_INFO,
+	.sfd_flags = SMP_FD_F_READ | SMP_FD_F_WRITE |
+	    SMP_FD_F_PROVIDES_CHANGE_COUNT,
+	.sfd_rq_len = sas2_report_route_info_rq_len,
+	.sfd_rq_dataoff = sas2_rq_dataoff,
+	.sfd_rq_setframe = sas2_rq_setframe,
+	.sfd_rs_datalen = sas2_report_route_info_rs_datalen,
+	.sfd_rs_dataoff = sas2_rs_dataoff,
+	.sfd_rs_getparams = sas2_rs_getparams
+},
+{
+	.sfd_function = SMP_FUNC_REPORT_PHY_EVENT,
+	.sfd_flags = SMP_FD_F_READ | SMP_FD_F_WRITE |
+	    SMP_FD_F_PROVIDES_CHANGE_COUNT,
+	.sfd_rq_len = sas2_report_phy_event_rq_len,
+	.sfd_rq_dataoff = sas2_rq_dataoff,
+	.sfd_rq_setframe = sas2_rq_setframe,
+	.sfd_rs_datalen = sas2_rs_datalen,
+	.sfd_rs_dataoff = sas2_rs_dataoff,
+	.sfd_rs_getparams = sas2_rs_getparams
+},
+{
+	.sfd_function = SMP_FUNC_DISCOVER_LIST,
+	.sfd_flags = SMP_FD_F_READ | SMP_FD_F_WRITE |
+	    SMP_FD_F_PROVIDES_CHANGE_COUNT,
+	.sfd_rq_len = sas2_discover_list_rq_len,
+	.sfd_rq_dataoff = sas2_rq_dataoff,
+	.sfd_rq_setframe = sas2_rq_setframe,
+	.sfd_rs_datalen = sas2_rs_datalen,
+	.sfd_rs_dataoff = sas2_rs_dataoff,
+	.sfd_rs_getparams = sas2_rs_getparams
+},
+{
+	.sfd_function = SMP_FUNC_REPORT_PHY_EVENT_LIST,
+	.sfd_flags = SMP_FD_F_READ | SMP_FD_F_WRITE |
+	    SMP_FD_F_PROVIDES_CHANGE_COUNT,
+	.sfd_rq_len = sas2_report_phy_event_list_rq_len,
+	.sfd_rq_dataoff = sas2_rq_dataoff,
+	.sfd_rq_setframe = sas2_rq_setframe,
+	.sfd_rs_datalen = sas2_rs_datalen,
+	.sfd_rs_dataoff = sas2_rs_dataoff,
+	.sfd_rs_getparams = sas2_rs_getparams
+},
+{
+	.sfd_function = SMP_FUNC_REPORT_EXP_ROUTE_TABLE_LIST,
+	.sfd_flags = SMP_FD_F_READ | SMP_FD_F_WRITE |
+	    SMP_FD_F_PROVIDES_CHANGE_COUNT,
+	.sfd_rq_len = sas2_report_exp_route_table_list_rq_len,
+	.sfd_rq_dataoff = sas2_rq_dataoff,
+	.sfd_rq_setframe = sas2_rq_setframe,
+	.sfd_rs_datalen = sas2_rs_datalen,
+	.sfd_rs_dataoff = sas2_rs_dataoff,
+	.sfd_rs_getparams = sas2_rs_getparams
+},
+{
+	.sfd_function = SMP_FUNC_CONFIG_GENERAL,
+	.sfd_flags = SMP_FD_F_WRITE | SMP_FD_F_NEEDS_CHANGE_COUNT,
+	.sfd_rq_len = sas2_config_general_rq_len,
+	.sfd_rq_dataoff = sas2_rq_dataoff,
+	.sfd_rq_setframe = sas2_rq_setframe,
+	.sfd_rs_datalen = sas2_rs_datalen,
+	.sfd_rs_dataoff = sas2_rs_dataoff,
+	.sfd_rs_getparams = sas2_rs_getparams
+},
+{
+	.sfd_function = SMP_FUNC_ENABLE_DISABLE_ZONING,
+	.sfd_flags = SMP_FD_F_WRITE | SMP_FD_F_NEEDS_CHANGE_COUNT,
+	.sfd_rq_len = sas2_enable_disable_zoning_rq_len,
+	.sfd_rq_dataoff = sas2_rq_dataoff,
+	.sfd_rq_setframe = sas2_rq_setframe,
+	.sfd_rs_datalen = sas2_rs_datalen,
+	.sfd_rs_dataoff = sas2_rs_dataoff,
+	.sfd_rs_getparams = sas2_rs_getparams
+},
+{
+	.sfd_function = SMP_FUNC_ZONED_BROADCAST,
+	.sfd_flags = SMP_FD_F_WRITE,
+	.sfd_rq_len = sas2_zoned_broadcast_rq_len,
+	.sfd_rq_dataoff = sas2_rq_dataoff,
+	.sfd_rq_setframe = sas2_rq_setframe,
+	.sfd_rs_datalen = sas2_rs_datalen,
+	.sfd_rs_dataoff = sas2_rs_dataoff,
+	.sfd_rs_getparams = sas2_rs_getparams
+},
+{
+	.sfd_function = SMP_FUNC_ZONE_LOCK,
+	.sfd_flags = SMP_FD_F_READ | SMP_FD_F_WRITE |
+	    SMP_FD_F_NEEDS_CHANGE_COUNT,
+	.sfd_rq_len = sas2_zone_lock_rq_len,
+	.sfd_rq_dataoff = sas2_rq_dataoff,
+	.sfd_rq_setframe = sas2_rq_setframe,
+	.sfd_rs_datalen = sas2_rs_datalen,
+	.sfd_rs_dataoff = sas2_rs_dataoff,
+	.sfd_rs_getparams = sas2_rs_getparams
+},
+{
+	.sfd_function = SMP_FUNC_ZONE_ACTIVATE,
+	.sfd_flags = SMP_FD_F_WRITE | SMP_FD_F_NEEDS_CHANGE_COUNT,
+	.sfd_rq_len = sas2_zone_activate_rq_len,
+	.sfd_rq_dataoff = sas2_rq_dataoff,
+	.sfd_rq_setframe = sas2_rq_setframe,
+	.sfd_rs_datalen = sas2_rs_datalen,
+	.sfd_rs_dataoff = sas2_rs_dataoff,
+	.sfd_rs_getparams = sas2_rs_getparams
+},
+{
+	.sfd_function = SMP_FUNC_ZONE_UNLOCK,
+	.sfd_flags = SMP_FD_F_WRITE,
+	.sfd_rq_len = sas2_zone_unlock_rq_len,
+	.sfd_rq_dataoff = sas2_rq_dataoff,
+	.sfd_rq_setframe = sas2_rq_setframe,
+	.sfd_rs_datalen = sas2_rs_datalen,
+	.sfd_rs_dataoff = sas2_rs_dataoff,
+	.sfd_rs_getparams = sas2_rs_getparams
+},
+{
+	.sfd_function = SMP_FUNC_CONFIG_ZONE_MANAGER_PASSWORD,
+	.sfd_flags = SMP_FD_F_WRITE | SMP_FD_F_NEEDS_CHANGE_COUNT,
+	.sfd_rq_len = sas2_config_zone_manager_password_rq_len,
+	.sfd_rq_dataoff = sas2_rq_dataoff,
+	.sfd_rq_setframe = sas2_rq_setframe,
+	.sfd_rs_datalen = sas2_rs_datalen,
+	.sfd_rs_dataoff = sas2_rs_dataoff,
+	.sfd_rs_getparams = sas2_rs_getparams
+},
+{
+	.sfd_function = SMP_FUNC_CONFIG_ZONE_PHY_INFO,
+	.sfd_flags = SMP_FD_F_WRITE | SMP_FD_F_NEEDS_CHANGE_COUNT,
+	.sfd_rq_len = sas2_config_zone_phy_info_rq_len,
+	.sfd_rq_dataoff = sas2_rq_dataoff,
+	.sfd_rq_setframe = sas2_rq_setframe,
+	.sfd_rs_datalen = sas2_rs_datalen,
+	.sfd_rs_dataoff = sas2_rs_dataoff,
+	.sfd_rs_getparams = sas2_rs_getparams
+},
+{
+	.sfd_function = SMP_FUNC_CONFIG_ZONE_PERM_TABLE,
+	.sfd_flags = SMP_FD_F_WRITE | SMP_FD_F_NEEDS_CHANGE_COUNT,
+	.sfd_rq_len = sas2_config_zone_perm_table_rq_len,
+	.sfd_rq_dataoff = sas2_rq_dataoff,
+	.sfd_rq_setframe = sas2_rq_setframe,
+	.sfd_rs_datalen = sas2_rs_datalen,
+	.sfd_rs_dataoff = sas2_rs_dataoff,
+	.sfd_rs_getparams = sas2_rs_getparams
+},
+{
+	.sfd_function = SMP_FUNC_CONFIG_ROUTE_INFO,
+	.sfd_flags = SMP_FD_F_WRITE | SMP_FD_F_NEEDS_CHANGE_COUNT,
+	.sfd_rq_len = sas2_config_route_info_rq_len,
+	.sfd_rq_dataoff = sas2_rq_dataoff,
+	.sfd_rq_setframe = sas2_rq_setframe,
+	.sfd_rs_datalen = sas2_rs_datalen,
+	.sfd_rs_dataoff = sas2_rs_dataoff,
+	.sfd_rs_getparams = sas2_rs_getparams
+},
+{
+	.sfd_function = SMP_FUNC_PHY_CONTROL,
+	.sfd_flags = SMP_FD_F_WRITE | SMP_FD_F_NEEDS_CHANGE_COUNT,
+	.sfd_rq_len = sas2_phy_control_rq_len,
+	.sfd_rq_dataoff = sas2_rq_dataoff,
+	.sfd_rq_setframe = sas2_rq_setframe,
+	.sfd_rs_datalen = sas2_rs_datalen,
+	.sfd_rs_dataoff = sas2_rs_dataoff,
+	.sfd_rs_getparams = sas2_rs_getparams
+},
+{
+	.sfd_function = SMP_FUNC_PHY_TEST_FUNCTION,
+	.sfd_flags = SMP_FD_F_WRITE | SMP_FD_F_NEEDS_CHANGE_COUNT,
+	.sfd_rq_len = sas2_phy_test_function_rq_len,
+	.sfd_rq_dataoff = sas2_rq_dataoff,
+	.sfd_rq_setframe = sas2_rq_setframe,
+	.sfd_rs_datalen = sas2_rs_datalen,
+	.sfd_rs_dataoff = sas2_rs_dataoff,
+	.sfd_rs_getparams = sas2_rs_getparams
+},
+{
+	.sfd_function = SMP_FUNC_CONFIG_PHY_EVENT,
+	.sfd_flags = SMP_FD_F_WRITE | SMP_FD_F_NEEDS_CHANGE_COUNT,
+	.sfd_rq_len = sas2_config_phy_event_rq_len,
+	.sfd_rq_dataoff = sas2_rq_dataoff,
+	.sfd_rq_setframe = sas2_rq_setframe,
+	.sfd_rs_datalen = sas2_rs_datalen,
+	.sfd_rs_dataoff = sas2_rs_dataoff,
+	.sfd_rs_getparams = sas2_rs_getparams
+},
+{
+	.sfd_function = -1
+}
+};
+
+/*
+ * Returns the number of bytes in the request frame, including the header
+ * and footer, for the given function and capabilities.  Presently the only
+ * relevant capability is long-request, which in some cases increases the
+ * size of the request from the SAS-1 spec to that found in SAS-2.
+ *
+ * Variably-sized request frames have no default size; we return 0 in that
+ * case, which will often be interpreted by the caller as an error although
+ * in general it is not.
+ */
+size_t
+smp_default_request_len(uint_t cap, smp_function_t fn)
+{
+	switch (fn) {
+	case SMP_FUNC_REPORT_GENERAL:
+	case SMP_FUNC_REPORT_MANUFACTURER_INFO:
+	case SMP_FUNC_REPORT_ZONE_MANAGER_PASSWORD:
+		return (SMP_REQ_MINLEN);
+
+	case SMP_FUNC_REPORT_SELF_CONFIG_STATUS:
+		if (cap & SMP_TARGET_C_LONG_RESP)
+			return (SMP_REQ_MINLEN +
+			    sizeof (smp_report_self_config_status_req_t));
+		return (SMP_REQ_MINLEN);
+	case SMP_FUNC_REPORT_ZONE_PERM_TABLE:
+		if (cap & SMP_TARGET_C_LONG_RESP)
+			return (SMP_REQ_MINLEN +
+			    sizeof (smp_report_zone_perm_table_req_t));
+		return (SMP_REQ_MINLEN);
+	case SMP_FUNC_REPORT_BROADCAST:
+		if (cap & SMP_TARGET_C_LONG_RESP)
+			return (SMP_REQ_MINLEN +
+			    sizeof (smp_report_broadcast_req_t));
+		return (SMP_REQ_MINLEN);
+	case SMP_FUNC_DISCOVER:
+		return (SMP_REQ_MINLEN + sizeof (smp_discover_req_t));
+	case SMP_FUNC_REPORT_PHY_ERROR_LOG:
+		return (SMP_REQ_MINLEN +
+		    sizeof (smp_report_phy_error_log_req_t));
+	case SMP_FUNC_REPORT_PHY_SATA:
+		return (SMP_REQ_MINLEN + sizeof (smp_report_phy_sata_req_t));
+	case SMP_FUNC_REPORT_ROUTE_INFO:
+		return (SMP_REQ_MINLEN + sizeof (smp_report_route_info_req_t));
+	case SMP_FUNC_REPORT_PHY_EVENT:
+		if (cap & SMP_TARGET_C_LONG_RESP)
+			return (SMP_REQ_MINLEN +
+			    sizeof (smp_report_phy_event_req_t));
+		return (SMP_REQ_MINLEN);
+	case SMP_FUNC_DISCOVER_LIST:
+		if (cap & SMP_TARGET_C_LONG_RESP)
+			return (SMP_REQ_MINLEN +
+			    sizeof (smp_discover_list_req_t));
+		return (SMP_REQ_MINLEN);
+	case SMP_FUNC_REPORT_PHY_EVENT_LIST:
+		if (cap & SMP_TARGET_C_LONG_RESP)
+			return (SMP_REQ_MINLEN +
+			    sizeof (smp_report_phy_event_list_req_t));
+		return (SMP_REQ_MINLEN);
+	case SMP_FUNC_REPORT_EXP_ROUTE_TABLE_LIST:
+		if (cap & SMP_TARGET_C_LONG_RESP)
+			return (SMP_REQ_MINLEN +
+			    sizeof (smp_report_exp_route_table_list_req_t));
+		return (SMP_REQ_MINLEN);
+	case SMP_FUNC_CONFIG_GENERAL:
+		if (cap & SMP_TARGET_C_LONG_RESP)
+			return (SMP_REQ_MINLEN +
+			    sizeof (smp_config_general_req_t));
+		return (SMP_REQ_MINLEN);
+	case SMP_FUNC_ENABLE_DISABLE_ZONING:
+		if (cap & SMP_TARGET_C_LONG_RESP)
+			return (SMP_REQ_MINLEN +
+			    sizeof (smp_enable_disable_zoning_req_t));
+		return (SMP_REQ_MINLEN);
+	case SMP_FUNC_ZONE_LOCK:
+		if (cap & SMP_TARGET_C_LONG_RESP)
+			return (SMP_REQ_MINLEN +
+			    sizeof (smp_zone_lock_req_t));
+		return (SMP_REQ_MINLEN);
+	case SMP_FUNC_ZONE_ACTIVATE:
+		if (cap & SMP_TARGET_C_LONG_RESP)
+			return (SMP_REQ_MINLEN +
+			    sizeof (smp_zone_activate_req_t));
+		return (SMP_REQ_MINLEN);
+	case SMP_FUNC_ZONE_UNLOCK:
+		if (cap & SMP_TARGET_C_LONG_RESP)
+			return (SMP_REQ_MINLEN +
+			    sizeof (smp_zone_unlock_req_t));
+		return (SMP_REQ_MINLEN);
+	case SMP_FUNC_CONFIG_ZONE_MANAGER_PASSWORD:
+		if (cap & SMP_TARGET_C_LONG_RESP)
+			return (SMP_REQ_MINLEN +
+			    sizeof (smp_config_zone_manager_password_req_t));
+		return (SMP_REQ_MINLEN);
+	case SMP_FUNC_CONFIG_ROUTE_INFO:
+		return (SMP_REQ_MINLEN + sizeof (smp_config_route_info_req_t));
+	case SMP_FUNC_PHY_CONTROL:
+		return (SMP_REQ_MINLEN + sizeof (smp_phy_control_req_t));
+	case SMP_FUNC_PHY_TEST_FUNCTION:
+		return (SMP_REQ_MINLEN + sizeof (smp_phy_test_function_req_t));
+
+	case SMP_FUNC_ZONED_BROADCAST:
+	case SMP_FUNC_CONFIG_ZONE_PHY_INFO:
+	case SMP_FUNC_CONFIG_ZONE_PERM_TABLE:
+	case SMP_FUNC_CONFIG_PHY_EVENT:
+	default:
+		return (0);
+	}
+}
+
+/*
+ * This is slightly different - return the length in bytes, including the
+ * header and footer, to be assumed for the response frame type if the
+ * length field is zero.  Since the length field will not be zero unless the
+ * long response bit is clear or the target is buggy, we always assume that
+ * the caller wants the size of the v1 frame.
+ */
+/*ARGSUSED*/
+size_t
+smp_default_response_len(uint_t cap, smp_function_t fn)
+{
+	switch (fn) {
+	case SMP_FUNC_REPORT_SELF_CONFIG_STATUS:
+	case SMP_FUNC_REPORT_ZONE_PERM_TABLE:
+	case SMP_FUNC_REPORT_ZONE_MANAGER_PASSWORD:
+	case SMP_FUNC_REPORT_BROADCAST:
+	case SMP_FUNC_REPORT_PHY_EVENT:
+	case SMP_FUNC_DISCOVER_LIST:
+	case SMP_FUNC_REPORT_PHY_EVENT_LIST:
+	case SMP_FUNC_REPORT_EXP_ROUTE_TABLE_LIST:
+	case SMP_FUNC_CONFIG_GENERAL:
+	case SMP_FUNC_ENABLE_DISABLE_ZONING:
+	case SMP_FUNC_ZONED_BROADCAST:
+	case SMP_FUNC_ZONE_LOCK:
+	case SMP_FUNC_ZONE_ACTIVATE:
+	case SMP_FUNC_ZONE_UNLOCK:
+	case SMP_FUNC_CONFIG_ZONE_MANAGER_PASSWORD:
+	case SMP_FUNC_CONFIG_ZONE_PHY_INFO:
+	case SMP_FUNC_CONFIG_ZONE_PERM_TABLE:
+	case SMP_FUNC_CONFIG_ROUTE_INFO:
+	case SMP_FUNC_PHY_CONTROL:
+	case SMP_FUNC_PHY_TEST_FUNCTION:
+	case SMP_FUNC_CONFIG_PHY_EVENT:
+		return (SMP_RESP_MINLEN);
+
+	case SMP_FUNC_REPORT_GENERAL:
+		return (SMP_RESP_MINLEN + 24);
+	case SMP_FUNC_REPORT_MANUFACTURER_INFO:
+		return (SMP_RESP_MINLEN +
+		    sizeof (smp_report_manufacturer_info_resp_t));
+	case SMP_FUNC_DISCOVER:
+		return (SMP_RESP_MINLEN + 48);
+	case SMP_FUNC_REPORT_PHY_ERROR_LOG:
+		return (SMP_RESP_MINLEN +
+		    sizeof (smp_report_phy_error_log_resp_t));
+	case SMP_FUNC_REPORT_PHY_SATA:
+		return (SMP_RESP_MINLEN + 52);
+	case SMP_FUNC_REPORT_ROUTE_INFO:
+		return (SMP_RESP_MINLEN +
+		    sizeof (smp_report_route_info_resp_t));
+
+	default:
+		return (0);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/scsi/plugins/smp/sas2/i386/Makefile	Sun Apr 11 11:20:12 2010 -0700
@@ -0,0 +1,30 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+include ../Makefile.com
+
+install: all $(ROOTPROG)
+
+include ../../Makefile.targ
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/scsi/plugins/smp/sas2/sparc/Makefile	Sun Apr 11 11:20:12 2010 -0700
@@ -0,0 +1,30 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+include ../Makefile.com
+
+install: all $(ROOTPROG)
+
+include ../../Makefile.targ
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/scsi/plugins/smp/sas2/sparcv9/Makefile	Sun Apr 11 11:20:12 2010 -0700
@@ -0,0 +1,31 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+include ../Makefile.com
+include $(SRC)/Makefile.master.64
+
+install: all $(ROOTPROG64)
+
+include ../../Makefile.targ
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/scsi/plugins/smp/usmp/Makefile	Sun Apr 11 11:20:12 2010 -0700
@@ -0,0 +1,30 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+HDRS =
+HDRDIR = common
+PLUGINTYPE = engine
+
+include ../Makefile.plugin
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/scsi/plugins/smp/usmp/Makefile.com	Sun Apr 11 11:20:12 2010 -0700
@@ -0,0 +1,35 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+MODULE =	usmp
+SRCS =		usmp.c
+
+SRCDIR =        ../common
+PLUGINTYPE =    engine
+
+include ../../Makefile.lib
+
+LDLIBS +=	-ldevinfo	\
+		-ldevid
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/scsi/plugins/smp/usmp/amd64/Makefile	Sun Apr 11 11:20:12 2010 -0700
@@ -0,0 +1,31 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+include ../Makefile.com
+include $(SRC)/Makefile.master.64
+
+install: all $(ROOTPROG64)
+
+include ../../Makefile.targ
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/scsi/plugins/smp/usmp/common/usmp.c	Sun Apr 11 11:20:12 2010 -0700
@@ -0,0 +1,231 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/scsi/scsi_address.h>
+#include <sys/scsi/impl/usmp.h>
+#include <sys/libdevid.h>
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <strings.h>
+#include <stdio.h>
+#include <limits.h>
+
+#include <scsi/libsmp.h>
+#include <scsi/libsmp_plugin.h>
+
+#include <libdevinfo.h>
+
+struct usmp_dev {
+	int ud_fd;
+	char *ud_dev;
+	uint64_t ud_addr;
+};
+
+struct di_walk_arg {
+	dev_t dev;
+	uint64_t addr;
+};
+
+static int
+di_walk(di_node_t node, di_minor_t minor, void *arg)
+{
+	struct di_walk_arg *wp = arg;
+	char *wwn;
+
+	if (di_minor_spectype(minor) != S_IFCHR)
+		return (DI_WALK_CONTINUE);
+
+	if (di_minor_devt(minor) == wp->dev) {
+		if (di_prop_lookup_strings(DDI_DEV_T_ANY, node,
+		    SCSI_ADDR_PROP_TARGET_PORT, &wwn) != 1 &&
+		    di_prop_lookup_strings(DDI_DEV_T_ANY, node,
+		    "smp-wwn", &wwn) != 1)
+			return (DI_WALK_CONTINUE);
+
+		if (scsi_wwnstr_to_wwn(wwn, &wp->addr) != DDI_SUCCESS)
+			return (DI_WALK_CONTINUE);
+
+		return (DI_WALK_TERMINATE);
+	}
+
+	return (DI_WALK_CONTINUE);
+}
+
+static void *
+usmp_open(const void *target)
+{
+	struct usmp_dev *dp;
+	const char *target_name = (const char *)target;
+
+	struct stat64 st;
+	di_node_t root, smp;
+	struct di_walk_arg walk;
+
+	if ((dp = smp_zalloc(sizeof (struct usmp_dev))) == NULL)
+		return (NULL);
+
+	if ((dp->ud_dev = smp_strdup(target_name)) == NULL) {
+		smp_free(dp);
+		return (NULL);
+	}
+
+	if ((dp->ud_fd = open(target_name, O_RDONLY)) < 0) {
+		(void) smp_error(ESMP_BADTARGET,
+		    "failed to open %s for reading: %s",
+		    target_name, strerror(errno));
+		smp_free(dp->ud_dev);
+		smp_free(dp);
+		return (NULL);
+	}
+
+	if (fstat64(dp->ud_fd, &st) != 0) {
+		(void) smp_error(ESMP_BADTARGET,
+		    "failed to stat %s: %s", target_name, strerror(errno));
+		(void) close(dp->ud_fd);
+		smp_free(dp->ud_dev);
+		smp_free(dp);
+		return (NULL);
+	}
+
+	if ((root = di_init("/", DINFOCACHE)) != DI_NODE_NIL) {
+		for (smp = di_drv_first_node("smp", root); smp != DI_NODE_NIL;
+		    smp = di_drv_next_node(smp)) {
+			bzero(&walk, sizeof (walk));
+			walk.dev = st.st_rdev;
+			(void) di_walk_minor(smp, NULL, 0, &walk, di_walk);
+			if (walk.addr != 0) {
+				dp->ud_addr = walk.addr;
+				break;
+			}
+		}
+		di_fini(root);
+	}
+
+	return (dp);
+}
+
+static void
+usmp_close(void *private)
+{
+	struct usmp_dev *dp = (struct usmp_dev *)private;
+
+	if (dp == NULL)
+		return;
+
+	if (dp->ud_fd > 0)
+		(void) close(dp->ud_fd);
+
+	smp_free(dp->ud_dev);
+	smp_free(dp);
+}
+
+static int
+usmp_exec(void *private, smp_action_t *ap)
+{
+	struct usmp_dev *dp = (struct usmp_dev *)private;
+	struct usmp_cmd cmd;
+	void *req, *resp;
+	size_t reqlen, resplen;
+
+	bzero(&cmd, sizeof (cmd));
+
+	smp_action_get_request_frame(ap, &req, &reqlen);
+	smp_action_get_response_frame(ap, &resp, &resplen);
+
+	ASSERT(req != NULL);
+	ASSERT(resp != NULL);
+	ASSERT(reqlen != 0);
+	ASSERT(resplen != 0);
+
+	cmd.usmp_req = req;
+	cmd.usmp_reqsize = reqlen;
+	cmd.usmp_rsp = resp;
+	cmd.usmp_rspsize = resplen;
+	cmd.usmp_timeout = (int)smp_action_get_timeout(ap);
+
+	if (ioctl(dp->ud_fd, USMPFUNC, &cmd) < 0) {
+		ASSERT(errno != EFAULT);
+		switch (errno) {
+		case EINVAL:
+			return (smp_error(ESMP_BADFUNC, "internal usmp error"));
+		case EPERM:
+			return (smp_error(ESMP_PERM,
+			    "insufficient privileges"));
+		case EIO:
+			return (smp_error(ESMP_IO, "I/O error"));
+		default:
+			return (smp_error(ESMP_SYS, "usmp ioctl failed: %s",
+			    strerror(errno)));
+		}
+	}
+
+	/*
+	 * There is no way to determine the amount of data actually transferred
+	 * so we will just place the upper bound at the allocated size.
+	 */
+	smp_action_set_response_len(ap, resplen);
+
+	return (0);
+}
+
+static void
+usmp_target_name(void *private, char *buf, size_t len)
+{
+	struct usmp_dev *dp = (struct usmp_dev *)private;
+
+	(void) strlcpy(buf, dp->ud_dev, len);
+}
+
+static uint64_t
+usmp_target_addr(void *private)
+{
+	struct usmp_dev *dp = (struct usmp_dev *)private;
+
+	return (dp->ud_addr);
+}
+
+static const smp_engine_ops_t usmp_ops = {
+	.seo_open = usmp_open,
+	.seo_close = usmp_close,
+	.seo_exec = usmp_exec,
+	.seo_target_name = usmp_target_name,
+	.seo_target_addr = usmp_target_addr
+};
+
+int
+_smp_init(smp_engine_t *ep)
+{
+	smp_engine_config_t config = {
+		.sec_name = "usmp",
+		.sec_ops = &usmp_ops
+	};
+
+	return (smp_engine_register(ep, LIBSMP_ENGINE_VERSION, &config));
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/scsi/plugins/smp/usmp/i386/Makefile	Sun Apr 11 11:20:12 2010 -0700
@@ -0,0 +1,30 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+include ../Makefile.com
+
+install: all $(ROOTPROG)
+
+include ../../Makefile.targ
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/scsi/plugins/smp/usmp/sparc/Makefile	Sun Apr 11 11:20:12 2010 -0700
@@ -0,0 +1,30 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+include ../Makefile.com
+
+install: all $(ROOTPROG)
+
+include ../../Makefile.targ
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/scsi/plugins/smp/usmp/sparcv9/Makefile	Sun Apr 11 11:20:12 2010 -0700
@@ -0,0 +1,31 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+include ../Makefile.com
+include $(SRC)/Makefile.master.64
+
+install: all $(ROOTPROG64)
+
+include ../../Makefile.targ
--- a/usr/src/pkg/manifests/developer-library-lint.mf	Sun Apr 11 11:07:03 2010 +0800
+++ b/usr/src/pkg/manifests/developer-library-lint.mf	Sun Apr 11 11:20:12 2010 -0700
@@ -20,8 +20,7 @@
 #
 
 #
-# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
 #
 
 set name=pkg.fmri value=pkg:/developer/library/lint@$(PKGVERS)
@@ -336,10 +335,13 @@
 file path=usr/lib/llib-lzoneinfo.ln
 file path=usr/lib/scsi/$(ARCH64)/llib-lscsi.ln
 file path=usr/lib/scsi/$(ARCH64)/llib-lses.ln
+file path=usr/lib/scsi/$(ARCH64)/llib-lsmp.ln
 file path=usr/lib/scsi/llib-lscsi
 file path=usr/lib/scsi/llib-lscsi.ln
 file path=usr/lib/scsi/llib-lses
 file path=usr/lib/scsi/llib-lses.ln
+file path=usr/lib/scsi/llib-lsmp
+file path=usr/lib/scsi/llib-lsmp.ln
 file path=usr/lib/values-Xa.o
 file path=usr/lib/values-Xc.o
 file path=usr/lib/values-Xs.o
--- a/usr/src/pkg/manifests/system-header.mf	Sun Apr 11 11:07:03 2010 +0800
+++ b/usr/src/pkg/manifests/system-header.mf	Sun Apr 11 11:20:12 2010 -0700
@@ -63,6 +63,9 @@
 dir path=usr/include/scsi/plugins/ses
 dir path=usr/include/scsi/plugins/ses/framework
 dir path=usr/include/scsi/plugins/ses/vendor
+dir path=usr/include/scsi/plugins/smp
+dir path=usr/include/scsi/plugins/smp/engine
+dir path=usr/include/scsi/plugins/smp/framework
 dir path=usr/include/security
 dir path=usr/include/sharefs
 dir path=usr/include/sys
@@ -727,9 +730,12 @@
 file path=usr/include/scsi/libscsi.h
 file path=usr/include/scsi/libses.h
 file path=usr/include/scsi/libses_plugin.h
+file path=usr/include/scsi/libsmp.h
+file path=usr/include/scsi/libsmp_plugin.h
 file path=usr/include/scsi/plugins/ses/framework/libses.h
 file path=usr/include/scsi/plugins/ses/framework/ses2.h
 file path=usr/include/scsi/plugins/ses/framework/ses2_impl.h
+file path=usr/include/scsi/plugins/ses/vendor/sun.h
 file path=usr/include/sdp.h
 file path=usr/include/search.h
 file path=usr/include/secdb.h
@@ -1353,6 +1359,7 @@
 file path=usr/include/sys/scsi/generic/mode.h
 file path=usr/include/sys/scsi/generic/persist.h
 file path=usr/include/sys/scsi/generic/sense.h
+file path=usr/include/sys/scsi/generic/sff_frames.h
 file path=usr/include/sys/scsi/generic/smp_frames.h
 file path=usr/include/sys/scsi/generic/status.h
 file path=usr/include/sys/scsi/impl/commands.h
--- a/usr/src/pkg/manifests/system-io-tests.mf	Sun Apr 11 11:07:03 2010 +0800
+++ b/usr/src/pkg/manifests/system-io-tests.mf	Sun Apr 11 11:20:12 2010 -0700
@@ -20,8 +20,7 @@
 #
 
 #
-# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. 
 #
 
 set name=pkg.fmri value=pkg:/system/io/tests@$(PKGVERS)
@@ -59,6 +58,7 @@
 $(i386_ONLY)file path=usr/kernel/drv/tphci group=sys
 $(i386_ONLY)file path=usr/kernel/drv/tvhci group=sys
 file path=usr/lib/scsi/sestopo mode=0555
+file path=usr/lib/scsi/smp mode=0555
 file path=usr/sbin/devctl mode=0555
 file path=usr/sbin/emul64ioctl mode=0555
 legacy pkg=SUNWioth arch=$(ARCH) category=system desc="I/O Test Header Files" \
--- a/usr/src/pkg/manifests/system-library-storage-scsi-plugins.mf	Sun Apr 11 11:07:03 2010 +0800
+++ b/usr/src/pkg/manifests/system-library-storage-scsi-plugins.mf	Sun Apr 11 11:20:12 2010 -0700
@@ -20,8 +20,7 @@
 #
 
 #
-# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
 #
 
 set name=pkg.fmri value=pkg:/system/library/storage/scsi-plugins@$(PKGVERS)
@@ -57,3 +56,7 @@
     target=SUN-Storage-J4400.so
 link path=usr/lib/scsi/plugins/ses/vendor/SUN-Storage-J4200.so \
     target=SUN-Storage-J4400.so
+link path=usr/lib/scsi/plugins/ses/vendor/$(ARCH64)/LSILOGIC-SASX28-A.1.so \
+    target=LSILOGIC-SASX28-A.0.so
+link path=usr/lib/scsi/plugins/ses/vendor/LSILOGIC-SASX28-A.1.so \
+    target=LSILOGIC-SASX28-A.0.so
--- a/usr/src/pkg/manifests/system-library.mf	Sun Apr 11 11:07:03 2010 +0800
+++ b/usr/src/pkg/manifests/system-library.mf	Sun Apr 11 11:20:12 2010 -0700
@@ -20,8 +20,7 @@
 #
 
 #
-# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
 #
 
 set name=pkg.fmri value=pkg:/system/library@$(PKGVERS)
@@ -74,6 +73,11 @@
 dir path=usr/lib/scsi/plugins/ses/framework/$(ARCH64)
 dir path=usr/lib/scsi/plugins/ses/vendor
 $(sparc_ONLY)dir path=usr/lib/scsi/plugins/ses/vendor/$(ARCH64)
+dir path=usr/lib/scsi/plugins/smp
+dir path=usr/lib/scsi/plugins/smp/framework
+dir path=usr/lib/scsi/plugins/smp/framework/$(ARCH64)
+dir path=usr/lib/scsi/plugins/smp/engine
+dir path=usr/lib/scsi/plugins/smp/engine/$(ARCH64)
 dir path=usr/lib/security
 dir path=usr/lib/security/$(ARCH64)
 dir path=usr/xpg4
@@ -375,14 +379,20 @@
 file path=usr/lib/raidcfg/mpt.so.1
 file path=usr/lib/scsi/$(ARCH64)/libscsi.so.1
 file path=usr/lib/scsi/$(ARCH64)/libses.so.1
+file path=usr/lib/scsi/$(ARCH64)/libsmp.so.1
 file path=usr/lib/scsi/libscsi.so.1
 file path=usr/lib/scsi/libses.so.1
+file path=usr/lib/scsi/libsmp.so.1
 file path=usr/lib/scsi/plugins/scsi/engines/$(ARCH64)/uscsi.so
 file path=usr/lib/scsi/plugins/scsi/engines/uscsi.so
+file path=usr/lib/scsi/plugins/smp/engine/$(ARCH64)/usmp.so
+file path=usr/lib/scsi/plugins/smp/engine/usmp.so
 file path=usr/lib/scsi/plugins/ses/framework/$(ARCH64)/libses.so
 file path=usr/lib/scsi/plugins/ses/framework/$(ARCH64)/ses2.so
 file path=usr/lib/scsi/plugins/ses/framework/libses.so
 file path=usr/lib/scsi/plugins/ses/framework/ses2.so
+file path=usr/lib/scsi/plugins/smp/framework/$(ARCH64)/sas2.so
+file path=usr/lib/scsi/plugins/smp/framework/sas2.so
 file path=usr/lib/security/$(ARCH64)/crypt_bsdbf.so.1
 file path=usr/lib/security/$(ARCH64)/crypt_bsdmd5.so.1
 file path=usr/lib/security/$(ARCH64)/crypt_sha256.so.1
@@ -1095,8 +1105,10 @@
 link path=usr/lib/nss_user.so.1 target=../../lib/nss_user.so.1
 link path=usr/lib/scsi/$(ARCH64)/libscsi.so target=./libscsi.so.1
 link path=usr/lib/scsi/$(ARCH64)/libses.so target=./libses.so.1
+link path=usr/lib/scsi/$(ARCH64)/libsmp.so target=./libsmp.so.1
 link path=usr/lib/scsi/libscsi.so target=./libscsi.so.1
 link path=usr/lib/scsi/libses.so target=./libses.so.1
+link path=usr/lib/scsi/libsmp.so target=./libsmp.so.1
 link path=usr/lib/security/$(ARCH64)/crypt_bsdbf.so target=./crypt_bsdbf.so.1
 link path=usr/lib/security/$(ARCH64)/crypt_bsdmd5.so target=./crypt_bsdmd5.so.1
 link path=usr/lib/security/$(ARCH64)/crypt_sha256.so target=./crypt_sha256.so.1
--- a/usr/src/uts/common/sys/Makefile	Sun Apr 11 11:07:03 2010 +0800
+++ b/usr/src/uts/common/sys/Makefile	Sun Apr 11 11:20:12 2010 -0700
@@ -904,6 +904,7 @@
 	mode.h		\
 	persist.h	\
 	sense.h		\
+	sff_frames.h	\
 	smp_frames.h	\
 	status.h
 
@@ -1179,6 +1180,7 @@
 	$(SCSICONFHDRS:%.h=scsi/conf/%.check)		\
 	$(SCSIIMPLHDRS:%.h=scsi/impl/%.check)		\
 	$(SCSIISCSIHDRS:%.h=scsi/adapters/%.check)	\
+	$(SCSIGENHDRS:%.h=scsi/generic/%.check)		\
 	$(SCSITARGETSHDRS:%.h=scsi/targets/%.check)	\
 	$(SCSIVHCIHDRS:%.h=scsi/adapters/%.check)	\
 	$(SATAGENHDRS:%.h=sata/%.check)			\
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/sys/scsi/generic/sff_frames.h	Sun Apr 11 11:20:12 2010 -0700
@@ -0,0 +1,261 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#ifndef _SYS_SCSI_GENERIC_SFF_FRAMES_H
+#define	_SYS_SCSI_GENERIC_SFF_FRAMES_H
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+#include <sys/sysmacros.h>
+
+/*
+ * The definitions of SMP frame formats defined by SFF-8485.
+ * These are NOT compatible with the generic SAS-1 and/or SAS-2 SMP frame
+ * formats, but the function numbers and result codes are defined by SAS-2.
+ */
+
+#pragma	pack(1)
+
+typedef struct sff_request_frame {
+	uint8_t srf_frame_type;
+	uint8_t srf_function;
+	uint8_t srf_data[1];
+} sff_request_frame_t;
+
+typedef struct sff_response_frame {
+	uint8_t srf_frame_type;
+	uint8_t srf_function;
+	uint8_t srf_result;
+	uint8_t _reserved1;
+	uint8_t srf_data[1];
+} sff_response_frame_t;
+
+/*
+ * SFF-8485 8.4.1 GPIO register overview
+ */
+typedef enum sff_gpio_reg_type {
+	SFF_GPIO_CFG = 0x00,
+	SFF_GPIO_RX = 0x01,
+	SFF_GPIO_RX_GP = 0x02,
+	SFF_GPIO_TX = 0x03,
+	SFF_GPIO_TX_GP = 0x04
+} sff_gpio_reg_type_t;
+
+/*
+ * SFF-8485 8.4.2.1 GPIO configuration registers overview
+ */
+typedef enum sff_gpio_cfg_reg_index {
+	SFF_GPIO_CFG_0 = 0x00,
+	SFF_GPIO_CFG_1 = 0x01
+} sff_gpio_cfg_reg_index_t;
+
+/*
+ * SFF-8485 8.4.2.2 GPIO_CFG[0] register
+ */
+typedef struct sff_gpio_cfg_reg_0 {
+	uint8_t _reserved1;
+	DECL_BITFIELD2(
+	    sgcr0_version	:4,
+	    _reserved2		:4);
+	DECL_BITFIELD3(
+	    sgcr0_gp_register_count	:4,
+	    sgcr0_cfg_register_count	:3,
+	    sgcr0_gpio_enable		:1);
+	uint8_t sgcr0_supported_drive_count;
+} sff_gpio_cfg_reg_0_t;
+
+/*
+ * SFF-8485 8.4.2.3 GPIO_CFG[1] register
+ */
+typedef struct sff_gpio_cfg_reg_1 {
+	uint8_t _reserved1;
+	DECL_BITFIELD2(
+	    sgcr1_blink_gen_rate_a	:4,
+	    sgcr1_blink_gen_rate_b	:4);
+	DECL_BITFIELD2(
+	    sgcr1_max_activity_on	:4,
+	    sgcr1_force_activity_off	:4);
+	DECL_BITFIELD2(
+	    sgcr1_stretch_activity_on	:4,
+	    sgcr1_stretch_activity_off	:4);
+} sff_gpio_cfg_reg_1_t;
+
+/*
+ * SFF-8485 8.4.3 GPIO receive registers
+ */
+typedef struct sff_gpio_rx_reg {
+	DECL_BITFIELD2(
+	    sgrr_drive_3_gpio_input	:3,
+	    _reserved1			:5);
+	DECL_BITFIELD2(
+	    sgrr_drive_2_gpio_input	:3,
+	    _reserved1			:5);
+	DECL_BITFIELD2(
+	    sgrr_drive_1_gpio_input	:3,
+	    _reserved1			:5);
+	DECL_BITFIELD2(
+	    sgrr_drive_0_gpio_input	:3,
+	    _reserved1			:5);
+} sff_gpio_rx_reg_t;
+
+/*
+ * SFF-8485 8.4.4 GPIO transmit registers
+ */
+typedef enum sff_drive_error {
+	SFF_DRIVE_ERR_DISABLE = 0x0,
+	SFF_DRIVE_ERR_ENABLE = 0x1,
+	SFF_DRIVE_ERR_BLINK_A_1_0 = 0x2,
+	SFF_DRIVE_ERR_BLINK_A_0_1 = 0x3,
+	SFF_DRIVE_ERR_ENABLE_4 = 0x4,
+	SFF_DRIVE_ERR_ENABLE_5 = 0x5,
+	SFF_DRIVE_ERR_BLINK_B_1_0 = 0x6,
+	SFF_DRIVE_ERR_BLINK_B_0_1 = 0x7
+} sff_drive_error_t;
+
+typedef enum sff_drive_locate {
+	SFF_DRIVE_LOC_DISABLE = 0x0,
+	SFF_DRIVE_LOC_ENABLE = 0x1,
+	SFF_DRIVE_BLINK_A_1_0 = 0x2,
+	SFF_DRIVE_BLINK_A_0_1 = 0x3
+} sff_drive_locate_t;
+
+typedef enum sff_drive_activity {
+	SFF_DRIVE_ACT_DISABLE = 0x0,
+	SFF_DRIVE_ACT_ENABLE = 0x1,
+	SFF_DRIVE_ACT_BLINK_A_1_0 = 0x2,
+	SFF_DRIVE_ACT_BLINK_A_0_1 = 0x3,
+	SFF_DRIVE_ACT_ENABLE_END = 0x4,
+	SFF_DRIVE_ACT_ENABLE_START = 0x5,
+	SFF_DRIVE_ACT_BLINK_B_1_0 = 0x6,
+	SFF_DRIVE_ACT_BLINK_B_0_1 = 0x7
+} sff_drive_activity_t;
+
+typedef struct sff_gpio_tx_reg {
+	DECL_BITFIELD3(
+	    sgtr_drive_3_error		:3,	/* sff_drive_error_t */
+	    sgtr_drive_3_locate		:2,	/* sff_drive_locate_t */
+	    sgtr_drive_3_activity	:3);	/* sff_drive_activity_t */
+	DECL_BITFIELD3(
+	    sgtr_drive_2_error		:3,	/* sff_drive_error_t */
+	    sgtr_drive_2_locate		:2,	/* sff_drive_locate_t */
+	    sgtr_drive_2_activity	:3);	/* sff_drive_activity_t */
+	DECL_BITFIELD3(
+	    sgtr_drive_1_error		:3,	/* sff_drive_error_t */
+	    sgtr_drive_1_locate		:2,	/* sff_drive_locate_t */
+	    sgtr_drive_1_activity	:3);	/* sff_drive_activity_t */
+	DECL_BITFIELD3(
+	    sgtr_drive_0_error		:3,	/* sff_drive_error_t */
+	    sgtr_drive_0_locate		:2,	/* sff_drive_locate_t */
+	    sgtr_drive_0_activity	:3);	/* sff_drive_activity_t */
+} sff_gpio_tx_reg_t;
+
+/*
+ * SFF-8485 8.4.5.1 GPIO general purpose receive registers overview
+ */
+typedef enum sff_gpio_rx_gp_reg_index {
+	SFF_GPIO_REG_RX_GP_CFG = 0x00,
+	SFF_GPIO_REG_RX_GP_1 = 0x01	/* ... */
+} sff_gpio_rx_gp_reg_index_t;
+
+/*
+ * SFF-8485 8.4.5.2 GPIO_RX_GP_CFG register
+ */
+typedef struct sff_gpio_rx_gp_cfg_reg {
+	uint8_t _reserved1[2];
+	uint8_t sgrgcr_count;
+	uint8_t _reserved2;
+} sff_gpio_rx_gp_cfg_reg_t;
+
+/*
+ * SFF-8485 8.4.5.3 GPIO_RX_GP[1..n] register
+ */
+typedef uint8_t sff_gpio_rx_gp_reg_t[4];	/* little-endian */
+
+/*
+ * SFF-8485 8.4.6.1 GPIO general purpose transmit registers overview
+ */
+typedef enum sff_gpio_tx_gp_reg_index {
+	SFF_GPIO_REG_TX_GP_CFG = 0x00,
+	SFF_GPIO_REG_TX_GP_1 = 0x01	/* ... */
+} sff_gpio_tx_gp_reg_index_t;
+
+/*
+ * SFF-8485 8.4.6.2 GPIO_TX_GP_CFG register
+ */
+typedef struct sff_gpio_tx_cfg_reg {
+	uint8_t _reserved1[2];
+	uint8_t sgtcr_count;
+	DECL_BITFIELD5(
+	    sgtcr_sload_0	:1,
+	    sgtcr_sload_1	:1,
+	    sgtcr_sload_2	:1,
+	    sgtcr_sload_3	:1,
+	    _reserved2		:4);
+} sff_gpio_tx_cfg_reg_t;
+
+/*
+ * SFF-8485 8.4.6.3 GPIO_TX_GP[1..n] registers
+ */
+typedef uint8_t sff_gpio_tx_gp_reg_t[4];	/* little-endian */
+
+/*
+ * SFF-8485 8.2.2 READ GPIO REGISTER request
+ */
+typedef struct sff_read_gpio_req {
+	uint8_t srgr_register_type;
+	uint8_t srgr_register_index;
+	uint8_t srgr_register_count;
+	uint8_t _reserved1[3];
+} sff_read_gpio_req_t;
+
+typedef uint8_t sff_gpio_reg_t[4];
+
+/*
+ * SFF-8485 8.2.2 READ GPIO REGISTER response
+ */
+typedef struct sff_read_gpio_resp {
+	sff_gpio_reg_t srgr_regs[1];
+} smp_response_frame_t;
+
+/*
+ * SFF-8485 8.2.3 WRITE GPIO REGISTER request (no additional response)
+ */
+typedef struct sff_write_gpio_req {
+	uint8_t swgr_register_type;
+	uint8_t swgr_register_index;
+	uint8_t swgr_register_count;
+	uint8_t _reserved1[3];
+	sff_gpio_reg_t swgr_regs[1];
+} sff_write_gpio_req_t;
+
+#pragma	pack()
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* _SYS_SCSI_GENERIC_SFF_FRAMES_H */